| Index: net/third_party/nss/ssl/ssl3con.c
|
| ===================================================================
|
| --- net/third_party/nss/ssl/ssl3con.c (revision 124804)
|
| +++ net/third_party/nss/ssl/ssl3con.c (working copy)
|
| @@ -39,7 +39,7 @@
|
| * the terms of any one of the MPL, the GPL or the LGPL.
|
| *
|
| * ***** END LICENSE BLOCK ***** */
|
| -/* $Id: ssl3con.c,v 1.142.2.4 2010/09/01 19:47:11 wtc%google.com Exp $ */
|
| +/* $Id: ssl3con.c,v 1.164 2012/02/17 09:50:04 kaie%kuix.de Exp $ */
|
|
|
| #include "cert.h"
|
| #include "ssl.h"
|
| @@ -88,7 +88,8 @@
|
| static SECStatus ssl3_SendServerHelloDone( sslSocket *ss);
|
| static SECStatus ssl3_SendServerKeyExchange( sslSocket *ss);
|
| static SECStatus ssl3_NewHandshakeHashes( sslSocket *ss);
|
| -static SECStatus ssl3_UpdateHandshakeHashes( sslSocket *ss, unsigned char *b,
|
| +static SECStatus ssl3_UpdateHandshakeHashes( sslSocket *ss,
|
| + const unsigned char *b,
|
| unsigned int l);
|
|
|
| static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
|
| @@ -238,9 +239,6 @@
|
| #define EXPORT_RSA_KEY_LENGTH 64 /* bytes */
|
|
|
|
|
| -/* This is a hack to make sure we don't do double handshakes for US policy */
|
| -PRBool ssl3_global_policy_some_restricted = PR_FALSE;
|
| -
|
| /* This global item is used only in servers. It is is initialized by
|
| ** SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest().
|
| */
|
| @@ -930,8 +928,7 @@
|
|
|
| key = CERT_ExtractPublicKey(cert);
|
| if (key == NULL) {
|
| - /* CERT_ExtractPublicKey doesn't set error code */
|
| - PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
|
| + ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
|
| return SECFailure;
|
| }
|
|
|
| @@ -2042,9 +2039,7 @@
|
| return isPresent;
|
| }
|
|
|
| -/* Caller must hold the spec read lock. wrBuf is sometimes, but not always,
|
| - * ss->sec.writeBuf.
|
| - */
|
| +/* Caller must hold the spec read lock. */
|
| static SECStatus
|
| ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
|
| PRBool isServer,
|
| @@ -2229,8 +2224,7 @@
|
|
|
| ssl_GetSpecReadLock(ss); /********************************/
|
|
|
| - if (nIn > 1 &&
|
| - ss->opt.enableFalseStart &&
|
| + if (nIn > 1 && ss->opt.cbcRandomIV &&
|
| ss->ssl3.cwSpec->version <= SSL_LIBRARY_VERSION_3_1_TLS &&
|
| type == content_application_data &&
|
| ss->ssl3.cwSpec->cipher_def->type == type_block /* CBC mode */) {
|
| @@ -2248,7 +2242,7 @@
|
| if (rv != SECSuccess) {
|
| SSL_DBG(("%d: SSL3[%d]: SendRecord, tried to get %d bytes",
|
| SSL_GETPID(), ss->fd, spaceNeeded));
|
| - goto spec_locked_loser; /* sslBuffer_Grow set a memory error code. */
|
| + goto spec_locked_loser; /* sslBuffer_Grow set error code. */
|
| }
|
| }
|
|
|
| @@ -2281,7 +2275,7 @@
|
| ss->sec.isServer, type, pIn,
|
| contentLen, wrBuf);
|
| if (rv == SECSuccess) {
|
| - PRINT_BUF(50, (ss, "send (encrypted) record data [1/1]:",
|
| + PRINT_BUF(50, (ss, "send (encrypted) record data:",
|
| wrBuf->buf, wrBuf->len));
|
| }
|
| }
|
| @@ -2617,6 +2611,40 @@
|
| return SECFailure;
|
| }
|
|
|
| +static void
|
| +ssl3_SendAlertForCertError(sslSocket * ss, PRErrorCode errCode)
|
| +{
|
| + SSL3AlertDescription desc = bad_certificate;
|
| + PRBool isTLS = ss->version >= SSL_LIBRARY_VERSION_3_1_TLS;
|
| +
|
| + switch (errCode) {
|
| + case SEC_ERROR_LIBRARY_FAILURE: desc = unsupported_certificate; break;
|
| + case SEC_ERROR_EXPIRED_CERTIFICATE: desc = certificate_expired; break;
|
| + case SEC_ERROR_REVOKED_CERTIFICATE: desc = certificate_revoked; break;
|
| + case SEC_ERROR_INADEQUATE_KEY_USAGE:
|
| + case SEC_ERROR_INADEQUATE_CERT_TYPE:
|
| + desc = certificate_unknown; break;
|
| + case SEC_ERROR_UNTRUSTED_CERT:
|
| + desc = isTLS ? access_denied : certificate_unknown; break;
|
| + case SEC_ERROR_UNKNOWN_ISSUER:
|
| + case SEC_ERROR_UNTRUSTED_ISSUER:
|
| + desc = isTLS ? unknown_ca : certificate_unknown; break;
|
| + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
|
| + desc = isTLS ? unknown_ca : certificate_expired; break;
|
| +
|
| + case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
|
| + case SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID:
|
| + case SEC_ERROR_CA_CERT_INVALID:
|
| + case SEC_ERROR_BAD_SIGNATURE:
|
| + default: desc = bad_certificate; break;
|
| + }
|
| + SSL_DBG(("%d: SSL3[%d]: peer certificate is no good: error=%d",
|
| + SSL_GETPID(), ss->fd, errCode));
|
| +
|
| + (void) SSL3_SendAlert(ss, alert_fatal, desc);
|
| +}
|
| +
|
| +
|
| /*
|
| * Send handshake_Failure alert. Set generic error number.
|
| */
|
| @@ -3233,7 +3261,8 @@
|
| ** Caller must hold the ssl3Handshake lock.
|
| */
|
| static SECStatus
|
| -ssl3_UpdateHandshakeHashes(sslSocket *ss, unsigned char *b, unsigned int l)
|
| +ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b,
|
| + unsigned int l)
|
| {
|
| SECStatus rv = SECSuccess;
|
|
|
| @@ -3773,7 +3802,6 @@
|
| **************************************************************************/
|
|
|
| /* Called from ssl3_HandleHelloRequest(),
|
| - * ssl3_HandleFinished() (for step-up)
|
| * ssl3_RedoHandshake()
|
| * ssl2_BeginClientHandshake (when resuming ssl3 session)
|
| */
|
| @@ -4346,6 +4374,12 @@
|
| SECStatus rv;
|
| SECItem wrappedKey;
|
| SSLWrappedSymWrappingKey wswk;
|
| +#ifdef NSS_ENABLE_ECC
|
| + PK11SymKey * Ks = NULL;
|
| + SECKEYPublicKey *pubWrapKey = NULL;
|
| + SECKEYPrivateKey *privWrapKey = NULL;
|
| + ECCWrappedKeyInfo *ecWrapped;
|
| +#endif /* NSS_ENABLE_ECC */
|
|
|
| svrPrivKey = ss->serverCerts[exchKeyType].SERVERKEY;
|
| PORT_Assert(svrPrivKey != NULL);
|
| @@ -4422,13 +4456,6 @@
|
|
|
| /* wrap symmetric wrapping key in server's public key. */
|
| switch (exchKeyType) {
|
| -#ifdef NSS_ENABLE_ECC
|
| - PK11SymKey * Ks = NULL;
|
| - SECKEYPublicKey *pubWrapKey = NULL;
|
| - SECKEYPrivateKey *privWrapKey = NULL;
|
| - ECCWrappedKeyInfo *ecWrapped;
|
| -#endif /* NSS_ENABLE_ECC */
|
| -
|
| case kt_rsa:
|
| asymWrapMechanism = CKM_RSA_PKCS;
|
| rv = PK11_PubWrapSymKey(asymWrapMechanism, svrPubKey,
|
| @@ -4796,7 +4823,7 @@
|
| if (ss->sec.peerKey == NULL) {
|
| serverKey = CERT_ExtractPublicKey(ss->sec.peerCert);
|
| if (serverKey == NULL) {
|
| - PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
|
| + ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
|
| return SECFailure;
|
| }
|
| } else {
|
| @@ -5226,6 +5253,7 @@
|
| ssl3_CopyPeerCertsFromSID(ss, sid);
|
| }
|
|
|
| +
|
| /* NULL value for PMS signifies re-use of the old MS */
|
| rv = ssl3_InitPendingCipherSpec(ss, NULL);
|
| if (rv != SECSuccess) {
|
| @@ -5640,7 +5668,7 @@
|
| #endif /* NSS_PLATFORM_CLIENT_AUTH */
|
| switch (rv) {
|
| case SECWouldBlock: /* getClientAuthData has put up a dialog box. */
|
| - ssl_SetAlwaysBlock(ss);
|
| + ssl3_SetAlwaysBlock(ss);
|
| break; /* not an error */
|
|
|
| case SECSuccess:
|
| @@ -5786,7 +5814,7 @@
|
| SECKEYPrivateKey * key,
|
| CERTCertificateList *certChain)
|
| {
|
| - SECStatus rv = SECFailure;
|
| + SECStatus rv = SECSuccess;
|
|
|
| /* XXX This code only works on the initial handshake on a connection,
|
| ** XXX It does not work on a subsequent handshake (redo).
|
| @@ -5816,11 +5844,6 @@
|
| (void)SSL3_SendAlert(ss, alert_warning, no_certificate);
|
| }
|
| }
|
| - ssl_GetRecvBufLock(ss);
|
| - if (ss->ssl3.hs.msgState.buf != NULL) {
|
| - rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf);
|
| - }
|
| - ssl_ReleaseRecvBufLock(ss);
|
| } else {
|
| if (cert) {
|
| CERT_DestroyCertificate(cert);
|
| @@ -5831,22 +5854,38 @@
|
| if (certChain) {
|
| CERT_DestroyCertificateList(certChain);
|
| }
|
| + rv = SECFailure;
|
| }
|
| return rv;
|
| }
|
|
|
| PRBool
|
| ssl3_CanFalseStart(sslSocket *ss) {
|
| - return ss->opt.enableFalseStart &&
|
| - !ss->sec.isServer &&
|
| - !ss->ssl3.hs.isResuming &&
|
| - ss->ssl3.cwSpec &&
|
| - ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10 &&
|
| - (ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_rsa ||
|
| - ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_dh ||
|
| - ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh);
|
| + PRBool rv;
|
| +
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
|
| +
|
| + /* XXX: does not take into account whether we are waiting for
|
| + * SSL_AuthCertificateComplete or SSL_RestartHandshakeAfterCertReq. If/when
|
| + * that is done, this function could return different results each time it
|
| + * would be called.
|
| + */
|
| +
|
| + ssl_GetSpecReadLock(ss);
|
| + rv = ss->opt.enableFalseStart &&
|
| + !ss->sec.isServer &&
|
| + !ss->ssl3.hs.isResuming &&
|
| + ss->ssl3.cwSpec &&
|
| + ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10 &&
|
| + (ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_rsa ||
|
| + ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_dh ||
|
| + ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh);
|
| + ssl_ReleaseSpecReadLock(ss);
|
| + return rv;
|
| }
|
|
|
| +static SECStatus ssl3_SendClientSecondRound(sslSocket *ss);
|
| +
|
| /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
|
| * ssl3 Server Hello Done message.
|
| * Caller must hold Handshake and RecvBuf locks.
|
| @@ -5856,10 +5895,6 @@
|
| {
|
| SECStatus rv;
|
| SSL3WaitState ws = ss->ssl3.hs.ws;
|
| - PRBool sendEmptyCert, sendCert;
|
| - int n = 0, i;
|
| - typedef SECStatus (*SendFunction)(sslSocket*);
|
| - SendFunction send_funcs[5];
|
|
|
| SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello_done handshake",
|
| SSL_GETPID(), ss->fd));
|
| @@ -5875,14 +5910,72 @@
|
| return SECFailure;
|
| }
|
|
|
| + rv = ssl3_SendClientSecondRound(ss);
|
| +
|
| + return rv;
|
| +}
|
| +
|
| +/* Called from ssl3_HandleServerHelloDone and ssl3_AuthCertificateComplete.
|
| + *
|
| + * Caller must hold Handshake and RecvBuf locks.
|
| + */
|
| +static SECStatus
|
| +ssl3_SendClientSecondRound(sslSocket *ss)
|
| +{
|
| + SECStatus rv;
|
| + PRBool sendClientCert;
|
| + PRBool sendEmptyCert;
|
| + int n = 0, i;
|
| + typedef SECStatus (*SendFunction)(sslSocket*);
|
| + SendFunction send_funcs[5];
|
| +
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
|
| +
|
| + sendClientCert = !ss->ssl3.sendEmptyCert &&
|
| + ss->ssl3.clientCertChain != NULL &&
|
| + (ss->ssl3.platformClientKey ||
|
| + ss->ssl3.clientPrivateKey != NULL);
|
| +
|
| + /* We must wait for the server's certificate to be authenticated before
|
| + * sending the client certificate in order to disclosing the client
|
| + * certificate to an attacker that does not have a valid cert for the
|
| + * domain we are connecting to.
|
| + *
|
| + * XXX: We should do the same for the NPN extension, but for that we
|
| + * need an option to give the application the ability to leak the NPN
|
| + * information to get better performance.
|
| + *
|
| + * During the initial handshake on a connection, we never send/receive
|
| + * application data until we have authenticated the server's certificate;
|
| + * i.e. we have fully authenticated the handshake before using the cipher
|
| + * specs agreed upon for that handshake. During a renegotiation, we may
|
| + * continue sending and receiving application data during the handshake
|
| + * interleaved with the handshake records. If we were to send the client's
|
| + * second round for a renegotiation before the server's certificate was
|
| + * authenticated, then the application data sent/received after this point
|
| + * would be using cipher spec that hadn't been authenticated. By waiting
|
| + * until the server's certificate has been authenticated during
|
| + * renegotiations, we ensure that renegotiations have the same property
|
| + * as initial handshakes; i.e. we have fully authenticated the handshake
|
| + * before using the cipher specs agreed upon for that handshake for
|
| + * application data.
|
| + */
|
| + if (ss->ssl3.hs.restartTarget) {
|
| + PR_NOT_REACHED("unexpected ss->ssl3.hs.restartTarget");
|
| + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| + return SECFailure;
|
| + }
|
| + if (ss->ssl3.hs.authCertificatePending &&
|
| + (sendClientCert || ss->ssl3.sendEmptyCert || ss->firstHsDone)) {
|
| + ss->ssl3.hs.restartTarget = ssl3_SendClientSecondRound;
|
| + return SECWouldBlock;
|
| + }
|
| +
|
| ssl_GetXmitBufLock(ss); /*******************************/
|
|
|
| sendEmptyCert = ss->ssl3.sendEmptyCert;
|
| ss->ssl3.sendEmptyCert = PR_FALSE;
|
| - sendCert = !sendEmptyCert &&
|
| - ss->ssl3.clientCertChain != NULL &&
|
| - (ss->ssl3.platformClientKey ||
|
| - ss->ssl3.clientPrivateKey != NULL);
|
|
|
| if (ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) {
|
| send_funcs[n++] = ssl3_SendClientKeyExchange;
|
| @@ -5890,7 +5983,7 @@
|
| if (sendEmptyCert) {
|
| send_funcs[n++] = ssl3_SendEmptyCertificate;
|
| }
|
| - if (sendCert) {
|
| + if (sendClientCert) {
|
| send_funcs[n++] = ssl3_SendCertificate;
|
| send_funcs[n++] = ssl3_SendCertificateVerify;
|
| }
|
| @@ -5898,11 +5991,11 @@
|
| if (sendEmptyCert) {
|
| send_funcs[n++] = ssl3_SendEmptyCertificate;
|
| }
|
| - if (sendCert) {
|
| + if (sendClientCert) {
|
| send_funcs[n++] = ssl3_SendCertificate;
|
| }
|
| send_funcs[n++] = ssl3_SendClientKeyExchange;
|
| - if (sendCert) {
|
| + if (sendClientCert) {
|
| send_funcs[n++] = ssl3_SendCertificateVerify;
|
| }
|
| send_funcs[n++] = ssl3_SendChangeCipherSpecs;
|
| @@ -5917,8 +6010,9 @@
|
| }
|
| }
|
|
|
| - /* We don't send NPN in a renegotiation as it's explicitly disallowed by
|
| - * the spec. */
|
| + /* XXX: If the server's certificate hasn't been authenticated by this
|
| + * point, then we may be leaking this NPN message to an attacker.
|
| + */
|
| if (!ss->firstHsDone) {
|
| rv = ssl3_SendNextProto(ss);
|
| if (rv != SECSuccess) {
|
| @@ -7899,69 +7993,6 @@
|
| }
|
| }
|
|
|
| - if (ss->ssl3.cachedInfoCertChainDigestReceived) {
|
| - /* Compute hash. */
|
| - PRUint64 certChainHash;
|
| - int i;
|
| - FNV1A64_Init(&certChainHash);
|
| - for (i = 0; i < certChain->len; i++) {
|
| - unsigned int certLen = certChain->certs[i].len;
|
| - unsigned char certLenArray[3] = {
|
| - certLen >> 16,
|
| - certLen >> 8,
|
| - certLen
|
| - };
|
| - FNV1A64_Update(&certChainHash, certLenArray, sizeof(certLenArray));
|
| - FNV1A64_Update(&certChainHash, certChain->certs[i].data, certLen);
|
| - }
|
| - FNV1A64_Final(&certChainHash);
|
| -
|
| - /* Both |&certChainHash| and |ss->ssl3.certChainDigest| should be in
|
| - * network byte order since both are computed with the FNV1A64 hash,
|
| - * which calls the function htonll.
|
| - */
|
| - if (memcmp(&certChainHash, ss->ssl3.certChainDigest,
|
| - sizeof(certChainHash)) == 0) {
|
| - /* The client correctly predicted the certificate chain. */
|
| -
|
| - /* Handshake type: certificate. */
|
| - rv = ssl3_AppendHandshakeNumber(ss, certificate, 1);
|
| - if (rv != SECSuccess) {
|
| - return rv; /* err set by AppendHandshake. */
|
| - }
|
| - /* Handshake message length. */
|
| - rv = ssl3_AppendHandshakeNumber(ss, 15, 3);
|
| - if (rv != SECSuccess) {
|
| - return rv; /* err set by AppendHandshake. */
|
| - }
|
| - /* CertChainLen(3) + ASN.1CertLen(3) + DigestLen(1) + Digest(8) */
|
| - rv = ssl3_AppendHandshakeNumber(ss, 12, 3);
|
| - if (rv != SECSuccess) {
|
| - return rv; /* err set by AppendHandshake. */
|
| - }
|
| - /* ASN.1CertLen(3) + DigestLen(1) + Digest(8) */
|
| - rv = ssl3_AppendHandshakeNumber(ss, 9, 3);
|
| - if (rv != SECSuccess) {
|
| - return rv; /* err set by AppendHandshake. */
|
| - }
|
| - /* Digest Length Byte */
|
| - rv = ssl3_AppendHandshakeNumber(ss, sizeof(certChainHash), 1);
|
| - if (rv != SECSuccess) {
|
| - return rv; /* err set by AppendHandshake. */
|
| - }
|
| - /* Digest */
|
| - rv = ssl3_AppendHandshake(ss, &certChainHash,
|
| - sizeof(certChainHash));
|
| - if (rv != SECSuccess) {
|
| - return rv; /* err set by AppendHandshake. */
|
| - }
|
| -
|
| - return SECSuccess;
|
| - }
|
| - }
|
| -
|
| - /* Send the entire certificate as usual. */
|
| -
|
| rv = ssl3_AppendHandshakeHeader(ss, certificate, len + 3);
|
| if (rv != SECSuccess) {
|
| return rv; /* err set by AppendHandshake. */
|
| @@ -8109,15 +8140,13 @@
|
| {
|
| ssl3CertNode * c;
|
| ssl3CertNode * lastCert = NULL;
|
| - ssl3CertNode * certs = NULL;
|
| - PRArenaPool * arena = NULL;
|
| - CERTCertificate *cert;
|
| PRInt32 remaining = 0;
|
| PRInt32 size;
|
| SECStatus rv;
|
| PRBool isServer = (PRBool)(!!ss->sec.isServer);
|
| + PRBool trusted = PR_FALSE;
|
| PRBool isTLS;
|
| - SSL3AlertDescription desc = bad_certificate;
|
| + SSL3AlertDescription desc;
|
| int errCode = SSL_ERROR_RX_MALFORMED_CERTIFICATE;
|
| SECItem certItem;
|
|
|
| @@ -8167,54 +8196,43 @@
|
| errCode = PORT_GetError();
|
| goto loser;
|
| }
|
| - goto cert_block;
|
| + goto server_no_cert;
|
| }
|
|
|
| - ss->ssl3.peerCertArena = arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
| - if ( arena == NULL ) {
|
| + ss->ssl3.peerCertArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
| + if (ss->ssl3.peerCertArena == NULL) {
|
| goto loser; /* don't send alerts on memory errors */
|
| }
|
|
|
| - if (length == 12 && ssl3_ExtensionNegotiated(ss, ssl_cached_info_xtn)) {
|
| - /* We are dealing with a certificate_chain digest */
|
| - int i;
|
| + /* First get the peer cert. */
|
| + remaining -= 3;
|
| + if (remaining < 0)
|
| + goto decode_loser;
|
|
|
| - ss->ssl3.cachedInfoCertChainDigestReceived = PR_TRUE;
|
| + size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
|
| + if (size <= 0)
|
| + goto loser; /* fatal alert already sent by ConsumeHandshake. */
|
|
|
| - /* Make sure the digests match. */
|
| - if (memcmp(b + 4, ss->ssl3.certChainDigest, 8)) {
|
| - desc = handshake_failure;
|
| - goto alert_loser;
|
| - }
|
| + if (remaining < size)
|
| + goto decode_loser;
|
|
|
| - /* First get the peer cert. */
|
| - if (ss->ssl3.predictedCertChain[0] == NULL) {
|
| - desc = handshake_failure;
|
| - goto alert_loser;
|
| - }
|
| - ss->sec.peerCert = CERT_DupCertificate(ss->ssl3.predictedCertChain[0]);
|
| + certItem.data = b;
|
| + certItem.len = size;
|
| + b += size;
|
| + length -= size;
|
| + remaining -= size;
|
|
|
| - /* Now get all of the CA certs. */
|
| - ss->ssl3.peerCertChain = NULL;
|
| - for (i = 1; ss->ssl3.predictedCertChain[i] != NULL; i++) {
|
| - c = PORT_ArenaNew(arena, ssl3CertNode);
|
| - if (c == NULL) {
|
| - goto loser; /* don't send alerts on memory errors */
|
| - }
|
| - c->cert = CERT_DupCertificate(ss->ssl3.predictedCertChain[i]);
|
| - c->next = NULL;
|
| - if (lastCert) {
|
| - lastCert->next = c;
|
| - } else {
|
| - ss->ssl3.peerCertChain = c;
|
| - }
|
| - lastCert = c;
|
| - }
|
| - } else {
|
| - /* We are dealing with a regular certificate message */
|
| - ss->ssl3.cachedInfoCertChainDigestReceived = PR_FALSE;
|
| + ss->sec.peerCert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,
|
| + PR_FALSE, PR_TRUE);
|
| + if (ss->sec.peerCert == NULL) {
|
| + /* We should report an alert if the cert was bad, but not if the
|
| + * problem was just some local problem, like memory error.
|
| + */
|
| + goto ambiguous_err;
|
| + }
|
|
|
| - /* First get the peer cert. */
|
| + /* Now get all of the CA certs. */
|
| + while (remaining > 0) {
|
| remaining -= 3;
|
| if (remaining < 0)
|
| goto decode_loser;
|
| @@ -8228,66 +8246,40 @@
|
|
|
| certItem.data = b;
|
| certItem.len = size;
|
| - b += size;
|
| + b += size;
|
| length -= size;
|
| remaining -= size;
|
|
|
| - ss->sec.peerCert = CERT_NewTempCertificate(ss->dbHandle, &certItem,
|
| - NULL, PR_FALSE, PR_TRUE);
|
| - if (ss->sec.peerCert == NULL) {
|
| - /* We should report an alert if the cert was bad, but not if the
|
| - * problem was just some local problem, like memory error.
|
| - */
|
| - goto ambiguous_err;
|
| + c = PORT_ArenaNew(ss->ssl3.peerCertArena, ssl3CertNode);
|
| + if (c == NULL) {
|
| + goto loser; /* don't send alerts on memory errors */
|
| }
|
|
|
| - /* Now get all of the CA certs. */
|
| - while (remaining > 0) {
|
| - remaining -= 3;
|
| - if (remaining < 0)
|
| - goto decode_loser;
|
| -
|
| - size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
|
| - if (size <= 0)
|
| - goto loser; /* fatal alert already sent by ConsumeHandshake. */
|
| -
|
| - if (remaining < size)
|
| - goto decode_loser;
|
| -
|
| - certItem.data = b;
|
| - certItem.len = size;
|
| - b += size;
|
| - length -= size;
|
| - remaining -= size;
|
| -
|
| - c = PORT_ArenaNew(arena, ssl3CertNode);
|
| - if (c == NULL) {
|
| - goto loser; /* don't send alerts on memory errors */
|
| - }
|
| -
|
| - c->cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,
|
| - PR_FALSE, PR_TRUE);
|
| - if (c->cert == NULL) {
|
| - goto ambiguous_err;
|
| - }
|
| -
|
| - c->next = NULL;
|
| - if (lastCert) {
|
| - lastCert->next = c;
|
| - } else {
|
| - certs = c;
|
| - }
|
| - lastCert = c;
|
| + c->cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,
|
| + PR_FALSE, PR_TRUE);
|
| + if (c->cert == NULL) {
|
| + goto ambiguous_err;
|
| }
|
|
|
| - if (remaining != 0)
|
| - goto decode_loser;
|
| + if (c->cert->trust)
|
| + trusted = PR_TRUE;
|
|
|
| - ss->ssl3.peerCertChain = certs; certs = NULL; arena = NULL;
|
| + c->next = NULL;
|
| + if (lastCert) {
|
| + lastCert->next = c;
|
| + } else {
|
| + ss->ssl3.peerCertChain = c;
|
| + }
|
| + lastCert = c;
|
| }
|
|
|
| + if (remaining != 0)
|
| + goto decode_loser;
|
| +
|
| SECKEY_UpdateCertPQG(ss->sec.peerCert);
|
|
|
| + ss->ssl3.hs.authCertificatePending = PR_FALSE;
|
| +
|
| /*
|
| * Ask caller-supplied callback function to validate cert chain.
|
| */
|
| @@ -8295,42 +8287,42 @@
|
| PR_TRUE, isServer);
|
| if (rv) {
|
| errCode = PORT_GetError();
|
| - if (!ss->handleBadCert) {
|
| - goto bad_cert;
|
| + if (rv != SECWouldBlock) {
|
| + if (ss->handleBadCert) {
|
| + rv = (*ss->handleBadCert)(ss->badCertArg, ss->fd);
|
| + }
|
| }
|
| - rv = (SECStatus)(*ss->handleBadCert)(ss->badCertArg, ss->fd);
|
| - if ( rv ) {
|
| - if ( rv == SECWouldBlock ) {
|
| - /* someone will handle this connection asynchronously*/
|
| - SSL_DBG(("%d: SSL3[%d]: go to async cert handler",
|
| - SSL_GETPID(), ss->fd));
|
| - ssl_SetAlwaysBlock(ss);
|
| - goto cert_block;
|
| +
|
| + if (rv == SECWouldBlock) {
|
| + if (ss->sec.isServer) {
|
| + errCode = SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS;
|
| + rv = SECFailure;
|
| + goto loser;
|
| }
|
| - /* cert is bad */
|
| - goto bad_cert;
|
| +
|
| + ss->ssl3.hs.authCertificatePending = PR_TRUE;
|
| + rv = SECSuccess;
|
| +
|
| + /* XXX: Async cert validation and False Start don't work together
|
| + * safely yet; if we leave False Start enabled, we may end up false
|
| + * starting (sending application data) before we
|
| + * SSL_AuthCertificateComplete has been called.
|
| + */
|
| + ss->opt.enableFalseStart = PR_FALSE;
|
| }
|
| - /* cert is good */
|
| - }
|
|
|
| - /* start SSL Step Up, if appropriate */
|
| - cert = ss->sec.peerCert;
|
| - if (!isServer &&
|
| - ssl3_global_policy_some_restricted &&
|
| - ss->ssl3.policy == SSL_ALLOWED &&
|
| - anyRestrictedEnabled(ss) &&
|
| - SECSuccess == CERT_VerifyCertNow(cert->dbhandle, cert,
|
| - PR_FALSE, /* checkSig */
|
| - certUsageSSLServerWithStepUp,
|
| -/*XXX*/ ss->authCertificateArg) ) {
|
| - ss->ssl3.policy = SSL_RESTRICTED;
|
| - ss->ssl3.hs.rehandshake = PR_TRUE;
|
| + if (rv != SECSuccess) {
|
| + ssl3_SendAlertForCertError(ss, errCode);
|
| + goto loser;
|
| + }
|
| }
|
|
|
| ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
|
| ssl3_CopyPeerCertsToSID(ss->ssl3.peerCertChain, ss->sec.ci.sid);
|
|
|
| if (!ss->sec.isServer) {
|
| + CERTCertificate *cert = ss->sec.peerCert;
|
| +
|
| /* set the server authentication and key exchange types and sizes
|
| ** from the value in the cert. If the key exchange key is different,
|
| ** it will get fixed when we handle the server key exchange message.
|
| @@ -8371,16 +8363,7 @@
|
| SECKEY_DestroyPublicKey(pubKey);
|
| pubKey = NULL;
|
| }
|
| - }
|
|
|
| -cert_block:
|
| - if (ss->sec.isServer) {
|
| - if (ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) {
|
| - ss->ssl3.hs.ws = wait_cert_verify;
|
| - } else {
|
| - ss->ssl3.hs.ws = wait_client_key;
|
| - }
|
| - } else {
|
| ss->ssl3.hs.ws = wait_cert_request; /* disallow server_key_exchange */
|
| if (ss->ssl3.hs.kea_def->is_limited ||
|
| /* XXX OR server cert is signing only. */
|
| @@ -8391,11 +8374,22 @@
|
| ss->ssl3.hs.kea_def->exchKeyType == kt_dh) {
|
| ss->ssl3.hs.ws = wait_server_key; /* allow server_key_exchange */
|
| }
|
| + } else {
|
| +server_no_cert:
|
| + if (ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) {
|
| + ss->ssl3.hs.ws = wait_cert_verify;
|
| + } else {
|
| + ss->ssl3.hs.ws = wait_client_key;
|
| + }
|
| }
|
|
|
| - /* rv must normally be equal to SECSuccess here. If we called
|
| - * handleBadCert, it can also be SECWouldBlock.
|
| - */
|
| + PORT_Assert(rv == SECSuccess);
|
| + if (rv != SECSuccess) {
|
| + errCode = SEC_ERROR_LIBRARY_FAILURE;
|
| + rv = SECFailure;
|
| + goto loser;
|
| + }
|
| +
|
| return rv;
|
|
|
| ambiguous_err:
|
| @@ -8410,35 +8404,9 @@
|
| }
|
| goto loser;
|
| }
|
| - /* fall through to bad_cert. */
|
| + ssl3_SendAlertForCertError(ss, errCode);
|
| + goto loser;
|
|
|
| -bad_cert: /* caller has set errCode. */
|
| - switch (errCode) {
|
| - case SEC_ERROR_LIBRARY_FAILURE: desc = unsupported_certificate; break;
|
| - case SEC_ERROR_EXPIRED_CERTIFICATE: desc = certificate_expired; break;
|
| - case SEC_ERROR_REVOKED_CERTIFICATE: desc = certificate_revoked; break;
|
| - case SEC_ERROR_INADEQUATE_KEY_USAGE:
|
| - case SEC_ERROR_INADEQUATE_CERT_TYPE:
|
| - desc = certificate_unknown; break;
|
| - case SEC_ERROR_UNTRUSTED_CERT:
|
| - desc = isTLS ? access_denied : certificate_unknown; break;
|
| - case SEC_ERROR_UNKNOWN_ISSUER:
|
| - case SEC_ERROR_UNTRUSTED_ISSUER:
|
| - desc = isTLS ? unknown_ca : certificate_unknown; break;
|
| - case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
|
| - desc = isTLS ? unknown_ca : certificate_expired; break;
|
| -
|
| - case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
|
| - case SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID:
|
| - case SEC_ERROR_CA_CERT_INVALID:
|
| - case SEC_ERROR_BAD_SIGNATURE:
|
| - default: desc = bad_certificate; break;
|
| - }
|
| - SSL_DBG(("%d: SSL3[%d]: peer certificate is no good: error=%d",
|
| - SSL_GETPID(), ss->fd, errCode));
|
| -
|
| - goto alert_loser;
|
| -
|
| decode_loser:
|
| desc = isTLS ? decode_error : bad_certificate;
|
|
|
| @@ -8446,10 +8414,6 @@
|
| (void)SSL3_SendAlert(ss, alert_fatal, desc);
|
|
|
| loser:
|
| - if (ss->ssl3.peerCertChain == NULL) {
|
| - ss->ssl3.peerCertChain = certs; certs = NULL; arena = NULL;
|
| - }
|
| - PORT_Assert(certs == NULL);
|
| ssl3_CleanupPeerCerts(ss);
|
|
|
| if (ss->sec.peerCert != NULL) {
|
| @@ -8460,61 +8424,63 @@
|
| return SECFailure;
|
| }
|
|
|
| +static SECStatus ssl3_FinishHandshake(sslSocket *ss);
|
|
|
| -/* restart an SSL connection that we stopped to run certificate dialogs
|
| -** XXX Need to document here how an application marks a cert to show that
|
| -** the application has accepted it (overridden CERT_VerifyCert).
|
| - *
|
| - * XXX This code only works on the initial handshake on a connection, XXX
|
| - * It does not work on a subsequent handshake (redo).
|
| - *
|
| - * Return value: XXX
|
| - *
|
| - * Caller holds 1stHandshakeLock.
|
| +static SECStatus
|
| +ssl3_AlwaysFail(sslSocket * ss)
|
| +{
|
| + PORT_SetError(PR_INVALID_STATE_ERROR);
|
| + return SECFailure;
|
| +}
|
| +
|
| +/* Caller must hold 1stHandshakeLock.
|
| */
|
| -int
|
| -ssl3_RestartHandshakeAfterServerCert(sslSocket *ss)
|
| +SECStatus
|
| +ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error)
|
| {
|
| - CERTCertificate * cert;
|
| - int rv = SECSuccess;
|
| + SECStatus rv;
|
|
|
| - if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_3_0)) {
|
| - SET_ERROR_CODE
|
| - return SECFailure;
|
| + PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
|
| +
|
| + if (ss->sec.isServer) {
|
| + PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS);
|
| + return SECFailure;
|
| }
|
| - if (!ss->ssl3.initialized) {
|
| - SET_ERROR_CODE
|
| - return SECFailure;
|
| - }
|
|
|
| - cert = ss->sec.peerCert;
|
| + ssl_GetRecvBufLock(ss);
|
| + ssl_GetSSL3HandshakeLock(ss);
|
|
|
| - /* Permit step up if user decided to accept the cert */
|
| - if (!ss->sec.isServer &&
|
| - ssl3_global_policy_some_restricted &&
|
| - ss->ssl3.policy == SSL_ALLOWED &&
|
| - anyRestrictedEnabled(ss) &&
|
| - (SECSuccess == CERT_VerifyCertNow(cert->dbhandle, cert,
|
| - PR_FALSE, /* checksig */
|
| - certUsageSSLServerWithStepUp,
|
| -/*XXX*/ ss->authCertificateArg) )) {
|
| - ss->ssl3.policy = SSL_RESTRICTED;
|
| - ss->ssl3.hs.rehandshake = PR_TRUE;
|
| + if (!ss->ssl3.hs.authCertificatePending) {
|
| + PORT_SetError(PR_INVALID_STATE_ERROR);
|
| + rv = SECFailure;
|
| + goto done;
|
| }
|
|
|
| - if (ss->handshake != NULL) {
|
| - ss->handshake = ssl_GatherRecord1stHandshake;
|
| - ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
|
| - ssl3_CopyPeerCertsToSID((ssl3CertNode *)ss->ssl3.peerCertChain,
|
| - ss->sec.ci.sid);
|
| + ss->ssl3.hs.authCertificatePending = PR_FALSE;
|
|
|
| - ssl_GetRecvBufLock(ss);
|
| - if (ss->ssl3.hs.msgState.buf != NULL) {
|
| - rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf);
|
| + if (error != 0) {
|
| + ss->ssl3.hs.restartTarget = ssl3_AlwaysFail;
|
| + ssl3_SendAlertForCertError(ss, error);
|
| + rv = SECSuccess;
|
| + } else if (ss->ssl3.hs.restartTarget != NULL) {
|
| + sslRestartTarget target = ss->ssl3.hs.restartTarget;
|
| + ss->ssl3.hs.restartTarget = NULL;
|
| + rv = target(ss);
|
| + /* Even if we blocked here, we have accomplished enough to claim
|
| + * success. Any remaining work will be taken care of by subsequent
|
| + * calls to SSL_ForceHandshake/PR_Send/PR_Read/etc.
|
| + */
|
| + if (rv == SECWouldBlock) {
|
| + rv = SECSuccess;
|
| }
|
| - ssl_ReleaseRecvBufLock(ss);
|
| + } else {
|
| + rv = SECSuccess;
|
| }
|
|
|
| +done:
|
| + ssl_ReleaseSSL3HandshakeLock(ss);
|
| + ssl_ReleaseRecvBufLock(ss);
|
| +
|
| return rv;
|
| }
|
|
|
| @@ -8779,7 +8745,6 @@
|
| SECStatus rv = SECSuccess;
|
| PRBool isServer = ss->sec.isServer;
|
| PRBool isTLS;
|
| - PRBool doStepUp;
|
| SSL3KEAType effectiveExchKeyType;
|
|
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
|
| @@ -8835,8 +8800,6 @@
|
| }
|
| }
|
|
|
| - doStepUp = (PRBool)(!isServer && ss->ssl3.hs.rehandshake);
|
| -
|
| ssl_GetXmitBufLock(ss); /*************************************/
|
|
|
| if ((isServer && !ss->ssl3.hs.isResuming) ||
|
| @@ -8862,19 +8825,18 @@
|
| goto xmit_loser; /* err is set. */
|
| }
|
| /* If this thread is in SSL_SecureSend (trying to write some data)
|
| - ** or if it is going to step up,
|
| ** then set the ssl_SEND_FLAG_FORCE_INTO_BUFFER flag, so that the
|
| ** last two handshake messages (change cipher spec and finished)
|
| ** will be sent in the same send/write call as the application data.
|
| */
|
| - if (doStepUp || ss->writerThread == PR_GetCurrentThread()) {
|
| + if (ss->writerThread == PR_GetCurrentThread()) {
|
| flags = ssl_SEND_FLAG_FORCE_INTO_BUFFER;
|
| }
|
|
|
| if (!isServer && !ss->firstHsDone) {
|
| rv = ssl3_SendNextProto(ss);
|
| if (rv != SECSuccess) {
|
| - goto xmit_loser; /* err code was set. */
|
| + goto xmit_loser; /* err code was set. */
|
| }
|
| }
|
|
|
| @@ -8884,22 +8846,12 @@
|
| }
|
| }
|
|
|
| - /* Optimization: don't cache this connection if we're going to step up. */
|
| - if (doStepUp) {
|
| - ssl_FreeSID(sid);
|
| - ss->sec.ci.sid = sid = NULL;
|
| - ss->ssl3.hs.rehandshake = PR_FALSE;
|
| - rv = ssl3_SendClientHello(ss);
|
| xmit_loser:
|
| - ssl_ReleaseXmitBufLock(ss);
|
| - return rv; /* err code is set if appropriate. */
|
| + ssl_ReleaseXmitBufLock(ss); /*************************************/
|
| + if (rv != SECSuccess) {
|
| + return rv;
|
| }
|
|
|
| - ssl_ReleaseXmitBufLock(ss); /*************************************/
|
| -
|
| - /* The first handshake is now completed. */
|
| - ss->handshake = NULL;
|
| - ss->firstHsDone = PR_TRUE;
|
| ss->gs.writeOffset = 0;
|
| ss->gs.readOffset = 0;
|
|
|
| @@ -8949,10 +8901,42 @@
|
| /* If the wrap failed, we don't cache the sid.
|
| * The connection continues normally however.
|
| */
|
| - if (rv == SECSuccess) {
|
| - (*ss->sec.cache)(sid);
|
| + ss->ssl3.hs.cacheSID = rv == SECSuccess;
|
| + }
|
| +
|
| + if (ss->ssl3.hs.authCertificatePending) {
|
| + if (ss->ssl3.hs.restartTarget) {
|
| + PR_NOT_REACHED("ssl3_HandleFinished: unexpected restartTarget");
|
| + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| + return SECFailure;
|
| }
|
| +
|
| + ss->ssl3.hs.restartTarget = ssl3_FinishHandshake;
|
| + return SECWouldBlock;
|
| }
|
| +
|
| + rv = ssl3_FinishHandshake(ss);
|
| + return rv;
|
| +}
|
| +
|
| +SECStatus
|
| +ssl3_FinishHandshake(sslSocket * ss)
|
| +{
|
| + SECStatus rv;
|
| +
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
|
| + PORT_Assert( ss->ssl3.hs.restartTarget == NULL );
|
| +
|
| + /* The first handshake is now completed. */
|
| + ss->handshake = NULL;
|
| + ss->firstHsDone = PR_TRUE;
|
| +
|
| + if (ss->sec.ci.sid->cached == never_cached &&
|
| + !ss->opt.noCache && ss->sec.cache && ss->ssl3.hs.cacheSID) {
|
| + (*ss->sec.cache)(ss->sec.ci.sid);
|
| + }
|
| +
|
| ss->ssl3.hs.ws = idle_handshake;
|
|
|
| /* Do the handshake callback for sslv3 here, if we cannot false start. */
|
| @@ -9317,7 +9301,6 @@
|
| *
|
| * Called from ssl3_GatherCompleteHandshake
|
| * ssl3_RestartHandshakeAfterCertReq
|
| - * ssl3_RestartHandshakeAfterServerCert
|
| *
|
| * Caller must hold the RecvBufLock.
|
| *
|
| @@ -9667,7 +9650,6 @@
|
| ssl_GetSpecWriteLock(ss);
|
| ss->ssl3.crSpec = ss->ssl3.cwSpec = &ss->ssl3.specs[0];
|
| ss->ssl3.prSpec = ss->ssl3.pwSpec = &ss->ssl3.specs[1];
|
| - ss->ssl3.hs.rehandshake = PR_FALSE;
|
| ss->ssl3.hs.sendingSCSV = PR_FALSE;
|
| ssl3_InitCipherSpec(ss, ss->ssl3.crSpec);
|
| ssl3_InitCipherSpec(ss, ss->ssl3.prSpec);
|
| @@ -9776,10 +9758,6 @@
|
| }
|
| suite->policy = policy;
|
|
|
| - if (policy == SSL_RESTRICTED) {
|
| - ssl3_global_policy_some_restricted = PR_TRUE;
|
| - }
|
| -
|
| return SECSuccess;
|
| }
|
|
|
| @@ -9956,21 +9934,6 @@
|
| return rv;
|
| }
|
|
|
| -static void
|
| -ssl3_CleanupPredictedPeerCertificates(sslSocket *ss) {
|
| - unsigned int i;
|
| -
|
| - if (!ss->ssl3.predictedCertChain)
|
| - return;
|
| -
|
| - for (i = 0; ss->ssl3.predictedCertChain[i]; i++) {
|
| - CERT_DestroyCertificate(ss->ssl3.predictedCertChain[i]);
|
| - }
|
| -
|
| - PORT_Free(ss->ssl3.predictedCertChain);
|
| - ss->ssl3.predictedCertChain = NULL;
|
| -}
|
| -
|
| /* Called from ssl_DestroySocketContents() in sslsock.c */
|
| void
|
| ssl3_DestroySSL3Info(sslSocket *ss)
|
| @@ -9994,9 +9957,6 @@
|
| ss->ssl3.clientCertChain = NULL;
|
| }
|
|
|
| - if (ss->ssl3.predictedCertChain != NULL)
|
| - ssl3_CleanupPredictedPeerCertificates(ss);
|
| -
|
| /* clean up handshake */
|
| if (ss->opt.bypassPKCS11) {
|
| SHA1_DestroyContext((SHA1Context *)ss->ssl3.hs.sha_cx, PR_FALSE);
|
| @@ -10030,10 +9990,7 @@
|
|
|
| ss->ssl3.initialized = PR_FALSE;
|
|
|
| - if (ss->ssl3.nextProto.data) {
|
| - PORT_Free(ss->ssl3.nextProto.data);
|
| - ss->ssl3.nextProto.data = NULL;
|
| - }
|
| + SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
|
| }
|
|
|
| /* End of ssl3con.c */
|
|
|