sslcon.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,213 行 · 第 1/5 页
C
2,213 行
* We MUST NOT match on any of those. * Fortunately, this is easy to detect because SSLv3 ciphers have zero* in the first byte, and none of the SSLv2 ciphers do.** Called from ssl2_HandleClientHelloMessage().*/static intssl2_QualifyCypherSpecs(sslSocket *ss, PRUint8 * cs, /* cipher specs in client hello msg. */ int csLen){ PRUint8 * ms; PRUint8 * hs; PRUint8 * qs; int mc; int hc; PRUint8 qualifiedSpecs[ssl2_NUM_SUITES_IMPLEMENTED * 3]; PORT_Assert( ssl_Have1stHandshakeLock(ss) ); PORT_Assert( ssl_HaveRecvBufLock(ss) ); if (!ss->cipherSpecs) { ssl2_ConstructCipherSpecs(ss); } PRINT_BUF(10, (ss, "specs from client:", cs, csLen)); qs = qualifiedSpecs; ms = ss->cipherSpecs; for (mc = ss->sizeCipherSpecs; mc > 0; mc -= 3, ms += 3) { if (ms[0] == 0) continue; for (hs = cs, hc = csLen; hc > 0; hs += 3, hc -= 3) { if ((hs[0] == ms[0]) && (hs[1] == ms[1]) && (hs[2] == ms[2])) { /* Copy this cipher spec into the "keep" section */ qs[0] = hs[0]; qs[1] = hs[1]; qs[2] = hs[2]; qs += 3; break; } } } hc = qs - qualifiedSpecs; PRINT_BUF(10, (ss, "qualified specs from client:", qualifiedSpecs, hc)); PORT_Memcpy(cs, qualifiedSpecs, hc); return hc;}/*** Pick the best cipher we can find, given the array of server cipher** specs. Returns cipher number (e.g. SSL_CK_*), or -1 for no overlap.** If succesful, stores the master key size (bytes) in *pKeyLen.**** This is correct only for the client side, but presently** this function is only called from ** ssl2_ClientSetupSessionCypher() <- ssl2_HandleServerHelloMessage()**** Note that most servers only return a single cipher suite in their ** ServerHello messages. So, the code below for finding the "best" cipher** suite usually has only one choice. The client and server should send ** their cipher suite lists sorted in descending order by preference.*/static intssl2_ChooseSessionCypher(sslSocket *ss, int hc, /* number of cs's in hs. */ PRUint8 * hs, /* server hello's cipher suites. */ int * pKeyLen) /* out: sym key size in bytes. */{ PRUint8 * ms; unsigned int i; int bestKeySize; int bestRealKeySize; int bestCypher; int keySize; int realKeySize; PRUint8 * ohs = hs; PORT_Assert( ssl_Have1stHandshakeLock(ss) ); PORT_Assert( ssl_HaveRecvBufLock(ss) ); if (!ss->cipherSpecs) { ssl2_ConstructCipherSpecs(ss); } if (!ss->preferredCipher) { const PRUint8 * preferred = implementedCipherSuites; unsigned int allowed = ss->allowedByPolicy & ss->chosenPreference & SSL_CB_IMPLEMENTED; if (allowed) { for (i = ssl2_NUM_SUITES_IMPLEMENTED; i > 0; --i) { if (0 != (allowed & (1U << preferred[0]))) { ss->preferredCipher = preferred; break; } preferred += 3; } } } /* ** Scan list of ciphers recieved from peer and look for a match in ** our list. * Note: Our list may contain SSL v3 ciphers. * We MUST NOT match on any of those. * Fortunately, this is easy to detect because SSLv3 ciphers have zero * in the first byte, and none of the SSLv2 ciphers do. */ bestKeySize = bestRealKeySize = 0; bestCypher = -1; while (--hc >= 0) { for (i = 0, ms = ss->cipherSpecs; i < ss->sizeCipherSpecs; i += 3, ms += 3) { if ((hs[0] == ss->preferredCipher[0]) && (hs[1] == ss->preferredCipher[1]) && (hs[2] == ss->preferredCipher[2]) && hs[0] != 0) { /* Pick this cipher immediately! */ *pKeyLen = (((hs[1] << 8) | hs[2]) + 7) >> 3; return hs[0]; } if ((hs[0] == ms[0]) && (hs[1] == ms[1]) && (hs[2] == ms[2]) && hs[0] != 0) { /* Found a match */ /* Use secret keySize to determine which cipher is best */ realKeySize = (hs[1] << 8) | hs[2]; switch (hs[0]) { case SSL_CK_RC4_128_EXPORT40_WITH_MD5: case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5: keySize = 40; break; default: keySize = realKeySize; break; } if (keySize > bestKeySize) { bestCypher = hs[0]; bestKeySize = keySize; bestRealKeySize = realKeySize; } } } hs += 3; } if (bestCypher < 0) { /* ** No overlap between server and client. Re-examine server list ** to see what kind of ciphers it does support so that we can set ** the error code appropriately. */ if ((ohs[0] == SSL_CK_RC4_128_WITH_MD5) || (ohs[0] == SSL_CK_RC2_128_CBC_WITH_MD5)) { PORT_SetError(SSL_ERROR_US_ONLY_SERVER); } else if ((ohs[0] == SSL_CK_RC4_128_EXPORT40_WITH_MD5) || (ohs[0] == SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5)) { PORT_SetError(SSL_ERROR_EXPORT_ONLY_SERVER); } else { PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); } SSL_DBG(("%d: SSL[%d]: no cipher overlap", SSL_GETPID(), ss->fd)); goto loser; } *pKeyLen = (bestRealKeySize + 7) >> 3; return bestCypher; loser: return -1;}static SECStatusssl2_ClientHandleServerCert(sslSocket *ss, PRUint8 *certData, int certLen){ CERTCertificate *cert = NULL; SECItem certItem; PORT_Assert(ss->sec != 0); certItem.data = certData; certItem.len = certLen; /* decode the certificate */ cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL, PR_FALSE, PR_TRUE); if (cert == NULL) { SSL_DBG(("%d: SSL[%d]: decode of server certificate fails", SSL_GETPID(), ss->fd)); PORT_SetError(SSL_ERROR_BAD_CERTIFICATE); return SECFailure; }#ifdef TRACE { if (ssl_trace >= 1) { char *issuer; char *subject; issuer = CERT_NameToAscii(&cert->issuer); subject = CERT_NameToAscii(&cert->subject); SSL_TRC(1,("%d: server certificate issuer: '%s'", SSL_GETPID(), issuer ? issuer : "OOPS")); SSL_TRC(1,("%d: server name: '%s'", SSL_GETPID(), subject ? subject : "OOPS")); PORT_Free(issuer); PORT_Free(subject); } }#endif ss->sec->peerCert = cert; return SECSuccess;}/*** Given the server's public key and cipher specs, generate a session key** that is ready to use for encrypting/decrypting the byte stream. At** the same time, generate the SSL_MT_CLIENT_MASTER_KEY message and** send it to the server.**** Called from ssl2_HandleServerHelloMessage()*/static SECStatusssl2_ClientSetupSessionCypher(sslSocket *ss, PRUint8 *cs, int csLen){ sslSessionID * sid; PRUint8 * ca; /* points to iv data, or NULL if none. */ PRUint8 * ekbuf = 0; CERTCertificate * cert = 0; SECKEYPublicKey * serverKey = 0; unsigned modulusLen = 0; SECStatus rv; int cipher; int keyLen; /* cipher symkey size in bytes. */ int ckLen; /* publicly reveal this many bytes of key. */ int caLen; /* length of IV data at *ca. */ int nc; SECItem eblock; /* holds unencrypted PKCS#1 formatted key. */ SECItem rek; /* holds portion of symkey to be encrypted. */ PRUint8 keyData[SSL_MAX_MASTER_KEY_BYTES]; PRUint8 iv [8]; PORT_Assert( ssl_Have1stHandshakeLock(ss) ); PORT_Assert((ss->sec != 0)); eblock.data = 0; eblock.len = 0; sid = ss->sec->ci.sid; PORT_Assert(sid != 0); cert = ss->sec->peerCert; serverKey = CERT_ExtractPublicKey(cert); if (!serverKey) { SSL_DBG(("%d: SSL[%d]: extract public key failed: error=%d", SSL_GETPID(), ss->fd, PORT_GetError())); PORT_SetError(SSL_ERROR_BAD_CERTIFICATE); rv = SECFailure; goto loser2; } /* Choose a compatible cipher with the server */ nc = csLen / 3; cipher = ssl2_ChooseSessionCypher(ss, nc, cs, &keyLen); if (cipher < 0) { /* ssl2_ChooseSessionCypher has set error code. */ ssl2_SendErrorMessage(ss, SSL_PE_NO_CYPHERS); goto loser; } /* Generate the random keys */ PK11_GenerateRandom(keyData, sizeof(keyData)); /* ** Next, carve up the keys into clear and encrypted portions. The ** clear data is taken from the start of keyData and the encrypted ** portion from the remainder. Note that each of these portions is ** carved in half, one half for the read-key and one for the ** write-key. */ ca = 0; /* We know that cipher is a legit value here, because * ssl2_ChooseSessionCypher doesn't return bogus values. */ ckLen = ssl_Specs[cipher].pubLen; /* cleartext key length. */ caLen = ssl_Specs[cipher].ivLen; /* IV length. */ if (caLen) { PORT_Assert(sizeof iv >= caLen); PK11_GenerateRandom(iv, caLen); ca = iv; } /* Fill in session-id */ rv = ssl2_FillInSID(sid, cipher, keyData, keyLen, ca, caLen, keyLen << 3, (keyLen - ckLen) << 3); if (rv != SECSuccess) { goto loser; } SSL_TRC(1, ("%d: SSL[%d]: client, using %s cipher, clear=%d total=%d", SSL_GETPID(), ss->fd, ssl_cipherName[cipher], ckLen<<3, keyLen<<3)); /* Now setup read and write ciphers */ rv = ssl2_CreateSessionCypher(ss, sid, PR_TRUE); if (rv != SECSuccess) { goto loser; } /* ** Fill in the encryption buffer with some random bytes. Then ** copy in the portion of the session key we are encrypting. */ modulusLen = SECKEY_PublicKeyStrength(serverKey); rek.data = keyData + ckLen; rek.len = keyLen - ckLen; rv = RSA_FormatBlock(&eblock, modulusLen, RSA_BlockPublic, &rek); if (rv) goto loser; /* Set up the padding for version 2 rollback detection. */ /* XXX We should really use defines here */ if (ss->enableSSL3 || ss->enableTLS) { PORT_Assert((modulusLen - rek.len) > 12); PORT_Memset(eblock.data + modulusLen - rek.len - 8 - 1, 0x03, 8); } ekbuf = (PRUint8*) PORT_Alloc(modulusLen); if (!ekbuf) goto loser; PRINT_BUF(10, (ss, "master key encryption block:", eblock.data, eblock.len)); /* Encrypt ekitem */ rv = PK11_PubEncryptRaw(serverKey, ekbuf, eblock.data, modulusLen, ss->pkcs11PinArg); if (rv) goto loser; if (eblock.len != modulusLen) { /* Something strange just happened */ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); goto loser; } /* Now we have everything ready to send */ rv = ssl2_SendSessionKeyMessage(ss, cipher, keyLen << 3, ca, caLen, keyData, ckLen, ekbuf, modulusLen); if (rv != SECSuccess) { goto loser; } rv = SECSuccess; goto done; loser: rv = SECFailure; loser2: done: PORT_Memset(keyData, 0, sizeof(keyData)); PORT_ZFree(ekbuf, modulusLen); SECITEM_ZfreeItem(&eblock, PR_FALSE); SECKEY_DestroyPublicKey(serverKey); return rv;}/************************************************************************//* * Called from ssl2_HandleMessage in response to SSL_MT_SERVER_FINISHED message. * Caller holds recvBufLock and handshakeLock */static voidssl2_ClientRegSessionID(sslSocket *ss, PRUint8 *s){ sslSecurityInfo *sec; sslSessionID *sid; PORT_Assert((ss->sec != 0)); sec = ss->sec; sid = sec->ci.sid; /* Record entry in nonce cache */ if (sid->peerCert == NULL) { PORT_Memcpy(sid->u.ssl2.sessionID, s, sizeof(sid->u.ssl2.sessionID)); sid->peerCert = CERT_DupCertificate(sec->peerCert); } if (!ss->noCache) (*sec->cache)(sid);}/* Called from ssl2_HandleMessage() */static SECStatusssl2_TriggerNextMessage(sslSocket *ss){ sslConnectInfo * ci; SECStatus rv; PORT_Assert( ssl_Have1stHandshakeLock(ss) ); PORT_Assert((ss->sec != 0)); ci = &ss->sec->ci; if ((ci->requiredElements & CIS_HAVE_CERTIFICATE) && !(ci->sentElements & CIS_HAVE_CERTIFICATE)) { ci->sentElements |= CIS_HAVE_CERTIFICATE; rv = ssl2_SendCertificateRequestMessage(ss); return rv; } return SECSuccess;}/* See if it's time to send our finished message, or if the handshakes are** complete. Send finished message if appropriate.** Returns SECSuccess unless anything goes wrong.**** Called from ssl2_HandleMessage,** ssl2_HandleVerifyMessage ** ssl2_HandleServerHelloMessage** ssl2_HandleClientSessionKeyMessage** ssl2_RestartHandshakeAfterCertReq** ssl2_RestartHandshakeAfterServerCert*/static SECStatusssl2_TryToFinish(sslSocket *ss){ sslSecurityInfo *sec; sslConnectInfo * ci; SECStatus rv; char e, ef; PORT_Assert( ssl_Have1stHandshakeLock(ss) ); PORT_Assert((ss->sec != 0)); sec = ss->sec; ci = &sec->ci; e = ci->elements; ef = e | CIS_HAVE_FINISHED; if ((ef & ci->requiredElements
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?