sslcon.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,213 行 · 第 1/5 页
C
2,213 行
/************************************************************************//* Called from ssl2_ServerSetupSessionCypher() * ssl2_ClientSetupSessionCypher() */static SECStatusssl2_FillInSID(sslSessionID * sid, int cipher, PRUint8 *keyData, int keyLen, PRUint8 *ca, int caLen, int keyBits, int secretKeyBits){ PORT_Assert(sid->references == 1); PORT_Assert(sid->cached == never_cached); PORT_Assert(sid->u.ssl2.masterKey.data == 0); PORT_Assert(sid->u.ssl2.cipherArg.data == 0); sid->version = SSL_LIBRARY_VERSION_2; sid->u.ssl2.cipherType = cipher; sid->u.ssl2.masterKey.data = (PRUint8*) PORT_Alloc(keyLen); if (!sid->u.ssl2.masterKey.data) { return SECFailure; } PORT_Memcpy(sid->u.ssl2.masterKey.data, keyData, keyLen); sid->u.ssl2.masterKey.len = keyLen; sid->u.ssl2.keyBits = keyBits; sid->u.ssl2.secretKeyBits = secretKeyBits; if (caLen) { sid->u.ssl2.cipherArg.data = (PRUint8*) PORT_Alloc(caLen); if (!sid->u.ssl2.cipherArg.data) { return SECFailure; } sid->u.ssl2.cipherArg.len = caLen; PORT_Memcpy(sid->u.ssl2.cipherArg.data, ca, caLen); } return SECSuccess;}/*** Construct session keys given the masterKey (tied to the session-id),** the client's challenge and the server's nonce.**** Called from ssl2_CreateSessionCypher() <-*/static SECStatusssl2_ProduceKeys(sslSocket * ss, SECItem * readKey, SECItem * writeKey, SECItem * masterKey, PRUint8 * challenge, PRUint8 * nonce, int cipherType){ PK11Context * cx = 0; unsigned nkm = 0; /* number of hashes to generate key mat. */ unsigned nkd = 0; /* size of readKey and writeKey. */ unsigned part; unsigned i; unsigned off; SECStatus rv; PRUint8 countChar; PRUint8 km[3*16]; /* buffer for key material. */ readKey->data = 0; writeKey->data = 0; PORT_Assert( ssl_Have1stHandshakeLock(ss) ); PORT_Assert((ss->sec != 0)); rv = SECSuccess; cx = PK11_CreateDigestContext(SEC_OID_MD5); if (cx == NULL) { ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); return SECFailure; } nkm = ssl_Specs[cipherType].nkm; nkd = ssl_Specs[cipherType].nkd; readKey->data = (PRUint8*) PORT_Alloc(nkd); if (!readKey->data) goto loser; readKey->len = nkd; writeKey->data = (PRUint8*) PORT_Alloc(nkd); if (!writeKey->data) goto loser; writeKey->len = nkd; /* Produce key material */ countChar = '0'; for (i = 0, off = 0; i < nkm; i++, off += 16) { rv = PK11_DigestBegin(cx); rv |= PK11_DigestOp(cx, masterKey->data, masterKey->len); rv |= PK11_DigestOp(cx, &countChar, 1); rv |= PK11_DigestOp(cx, challenge, SSL_CHALLENGE_BYTES); rv |= PK11_DigestOp(cx, nonce, SSL_CONNECTIONID_BYTES); rv |= PK11_DigestFinal(cx, km+off, &part, MD5_LENGTH); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); rv = SECFailure; goto loser; } countChar++; } /* Produce keys */ PORT_Memcpy(readKey->data, km, nkd); PORT_Memcpy(writeKey->data, km + nkd, nkd);loser: PK11_DestroyContext(cx, PR_TRUE); return rv;}/* Called from ssl2_ServerSetupSessionCypher() <- ssl2_HandleClientSessionKeyMessage() <- ssl2_HandleClientHelloMessage() * ssl2_ClientSetupSessionCypher() <- ssl2_HandleServerHelloMessage() */static SECStatusssl2_CreateSessionCypher(sslSocket *ss, sslSessionID *sid, PRBool isClient){ sslSecurityInfo * sec; sslConnectInfo * ci; SECItem * rk; SECItem * wk; SECItem * param; SECStatus rv; int cipherType = sid->u.ssl2.cipherType; PK11SlotInfo * slot = NULL; CK_MECHANISM_TYPE mechanism; SECItem readKey; SECItem writeKey; void *readcx = 0; void *writecx = 0; readKey.data = 0; writeKey.data = 0; PORT_Assert( ssl_Have1stHandshakeLock(ss) ); PORT_Assert((ss->sec != 0)); if((ss->sec == 0) || (ss->sec->ci.sid == 0)) goto sec_loser; /* don't crash if asserts are off */ /* Trying to cut down on all these switch statements that should be tables. * So, test cipherType once, here, and then use tables below. */ switch (cipherType) { case SSL_CK_RC4_128_EXPORT40_WITH_MD5: case SSL_CK_RC4_128_WITH_MD5: case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5: case SSL_CK_RC2_128_CBC_WITH_MD5: case SSL_CK_DES_64_CBC_WITH_MD5: case SSL_CK_DES_192_EDE3_CBC_WITH_MD5: break; default: SSL_DBG(("%d: SSL[%d]: ssl2_CreateSessionCypher: unknown cipher=%d", SSL_GETPID(), ss->fd, cipherType)); PORT_SetError(isClient ? SSL_ERROR_BAD_SERVER : SSL_ERROR_BAD_CLIENT); goto loser; } sec = ss->sec; ci = &sec->ci; rk = isClient ? &readKey : &writeKey; wk = isClient ? &writeKey : &readKey; /* Produce the keys for this session */ rv = ssl2_ProduceKeys(ss, &readKey, &writeKey, &sid->u.ssl2.masterKey, ci->clientChallenge, ci->connectionID, cipherType); if (rv != SECSuccess) goto loser; PRINT_BUF(7, (ss, "Session read-key: ", rk->data, rk->len)); PRINT_BUF(7, (ss, "Session write-key: ", wk->data, wk->len)); PORT_Memcpy(ci->readKey, readKey.data, readKey.len); PORT_Memcpy(ci->writeKey, writeKey.data, writeKey.len); ci->keySize = readKey.len; /* Setup the MAC */ rv = ssl2_CreateMAC(sec, rk, wk, cipherType); if (rv != SECSuccess) goto loser; /* First create the session key object */ SSL_TRC(3, ("%d: SSL[%d]: using %s", SSL_GETPID(), ss->fd, ssl_cipherName[cipherType])); mechanism = ssl_Specs[cipherType].mechanism; /* set destructer before we call loser... */ sec->destroy = (void (*)(void*, PRBool)) PK11_DestroyContext; slot = PK11_GetBestSlot(mechanism, ss->pkcs11PinArg); if (slot == NULL) goto loser; param = PK11_ParamFromIV(mechanism, &sid->u.ssl2.cipherArg); if (param == NULL) goto loser; readcx = PK11_CreateContextByRawKey(slot, mechanism, PK11_OriginUnwrap, CKA_DECRYPT, rk, param, ss->pkcs11PinArg); SECITEM_FreeItem(param, PR_TRUE); if (readcx == NULL) goto loser; /* build the client context */ param = PK11_ParamFromIV(mechanism, &sid->u.ssl2.cipherArg); if (param == NULL) goto loser; writecx = PK11_CreateContextByRawKey(slot, mechanism, PK11_OriginUnwrap, CKA_ENCRYPT, wk, param, ss->pkcs11PinArg); SECITEM_FreeItem(param,PR_TRUE); if (writecx == NULL) goto loser; PK11_FreeSlot(slot); rv = SECSuccess; sec->enc = (SSLCipher) PK11_CipherOp; sec->dec = (SSLCipher) PK11_CipherOp; sec->readcx = (void *) readcx; sec->writecx = (void *) writecx; sec->blockSize = ssl_Specs[cipherType].blockSize; sec->blockShift = ssl_Specs[cipherType].blockShift; sec->cipherType = sid->u.ssl2.cipherType; sec->keyBits = sid->u.ssl2.keyBits; sec->secretKeyBits = sid->u.ssl2.secretKeyBits; goto done; loser: if (sec->destroy) { if (readcx) (*sec->destroy)(readcx, PR_TRUE); if (writecx) (*sec->destroy)(writecx, PR_TRUE); } if (slot) PK11_FreeSlot(slot); sec_loser: rv = SECFailure; done: SECITEM_ZfreeItem(rk, PR_FALSE); SECITEM_ZfreeItem(wk, PR_FALSE); return rv;}/*** Setup the server ciphers given information from a CLIENT-MASTER-KEY** message.** "ss" pointer to the ssl-socket object** "cipher" the cipher type to use** "keyBits" the size of the final cipher key** "ck" the clear-key data** "ckLen" the number of bytes of clear-key data** "ek" the encrypted-key data** "ekLen" the number of bytes of encrypted-key data** "ca" the cipher-arg data** "caLen" the number of bytes of cipher-arg data**** The MASTER-KEY is constructed by first decrypting the encrypted-key** data. This produces the SECRET-KEY-DATA. The MASTER-KEY is composed by** concatenating the clear-key data with the SECRET-KEY-DATA. This code** checks to make sure that the client didn't send us an improper amount** of SECRET-KEY-DATA (it restricts the length of that data to match the** spec).**** Called from ssl2_HandleClientSessionKeyMessage().*/static SECStatusssl2_ServerSetupSessionCypher(sslSocket *ss, int cipher, unsigned int keyBits, PRUint8 *ck, unsigned int ckLen, PRUint8 *ek, unsigned int ekLen, PRUint8 *ca, unsigned int caLen){ PRUint8 *kk; sslSecurityInfo * sec; sslSessionID * sid; PRUint8 * kbuf = 0; /* buffer for RSA decrypted data. */ unsigned int el1; /* length of RSA decrypted data in kbuf */ unsigned int keySize; unsigned int modulus; SECStatus rv; PRUint8 mkbuf[SSL_MAX_MASTER_KEY_BYTES]; PORT_Assert( ssl_Have1stHandshakeLock(ss) ); PORT_Assert( ssl_HaveRecvBufLock(ss) ); PORT_Assert((ss->sec != 0) && (ss->serverKey[kt_rsa] != 0)); sec = ss->sec; PORT_Assert((sec->ci.sid != 0)); sid = sec->ci.sid; keySize = (keyBits + 7) >> 3; /* Is the message just way too big? */ if (keySize > SSL_MAX_MASTER_KEY_BYTES) { /* bummer */ SSL_DBG(("%d: SSL[%d]: keySize=%d ckLen=%d max session key size=%d", SSL_GETPID(), ss->fd, keySize, ckLen, SSL_MAX_MASTER_KEY_BYTES)); PORT_SetError(SSL_ERROR_BAD_CLIENT); goto loser; } /* Trying to cut down on all these switch statements that should be tables. * So, test cipherType once, here, and then use tables below. */ switch (cipher) { case SSL_CK_RC4_128_EXPORT40_WITH_MD5: case SSL_CK_RC4_128_WITH_MD5: case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5: case SSL_CK_RC2_128_CBC_WITH_MD5: case SSL_CK_DES_64_CBC_WITH_MD5: case SSL_CK_DES_192_EDE3_CBC_WITH_MD5: break; default: SSL_DBG(("%d: SSL[%d]: ssl2_ServerSetupSessionCypher: unknown cipher=%d", SSL_GETPID(), ss->fd, cipher)); PORT_SetError(SSL_ERROR_BAD_CLIENT); goto loser; } /* For export ciphers, make sure they didn't send too much key data. */ if (ckLen != ssl_Specs[cipher].pubLen) { SSL_DBG(("%d: SSL[%d]: odd secret key size, keySize=%d ckLen=%d!", SSL_GETPID(), ss->fd, keySize, ckLen)); /* Somebody tried to sneak by a strange secret key */ PORT_SetError(SSL_ERROR_BAD_CLIENT); goto loser; } /* allocate the buffer to hold the decrypted portion of the key. */ /* XXX Haven't done any range check on ekLen. */ kbuf = (PRUint8*) PORT_Alloc(ekLen); if (!kbuf) { goto loser; } /* ** Decrypt encrypted half of the key. Note that encrypted half has ** been made to match the modulus size of our public key using ** PKCS#1. keySize is the real size of the data that is interesting. ** NOTE: PK11_PubDecryptRaw will barf on a non-RSA key. This is ** desired behavior here. */ rv = PK11_PubDecryptRaw(ss->serverKey[kt_rsa], kbuf, &el1, ekLen, ek, ekLen); if (rv != SECSuccess) goto hide_loser; modulus = PK11_GetPrivateModulusLen(ss->serverKey[kt_rsa]); if (modulus == -1) { /* If the key was really bad, then PK11_pubDecryptRaw * would have failed, therefore the we must assume that the card * is just being a pain and not giving us the modulus... but it * should be the same size as the encrypted key length, so use it * and keep cranking */ modulus = ekLen; } /* Is the length of the decrypted data (el1) the expected value? */ if (modulus != el1) goto hide_loser; /* Cheaply verify that PKCS#1 was used to format the encryption block */ kk = kbuf + modulus - (keySize - ckLen); if ((kbuf[0] != 0x00) || (kbuf[1] != 0x02) || (kk[-1] != 0x00)) { /* Tsk tsk. */ SSL_DBG(("%d: SSL[%d]: strange encryption block", SSL_GETPID(), ss->fd)); PORT_SetError(SSL_ERROR_BAD_CLIENT); goto hide_loser; } /* Make sure we're not subject to a version rollback attack. */ if (ss->enableSSL3 || ss->enableTLS) { PRUint8 threes[8] = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }; if (PORT_Memcmp(kk - 8 - 1, threes, 8) == 0) { PORT_SetError(SSL_ERROR_BAD_CLIENT); goto hide_loser; } } if (0) {hide_loser: /* Defense against the Bleichenbacher attack. * Provide the client with NO CLUES that the decrypted master key * was erroneous. Don't send any error messages. * Instead, Generate a completely bogus master key . */ PK11_GenerateRandom(kbuf, ekLen); } /* ** Construct master key out of the pieces. */ if (ckLen) { PORT_Memcpy(mkbuf, ck, ckLen); } PORT_Memcpy(mkbuf+ckLen, kk, keySize-ckLen); /* Fill in session-id */ rv = ssl2_FillInSID(sid, cipher, mkbuf, keySize, ca, caLen, keyBits, keyBits - (ckLen<<3)); if (rv != SECSuccess) { goto loser; } /* Create session ciphers */ rv = ssl2_CreateSessionCypher(ss, sid, PR_FALSE); if (rv != SECSuccess) { goto loser; } SSL_TRC(1, ("%d: SSL[%d]: server, using %s cipher, clear=%d total=%d", SSL_GETPID(), ss->fd, ssl_cipherName[cipher], ckLen<<3, keySize<<3)); rv = SECSuccess; goto done; loser: rv = SECFailure; done: PORT_Free(kbuf); return rv;}/************************************************************************//*** Rewrite the incoming cipher specs, comparing to list of specs we support,** (ss->cipherSpecs) and eliminating anything we don't support*** Note: Our list may contain SSL v3 ciphers.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?