Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1547)

Unified Diff: net/third_party/nss/ssl/ssl3con.c

Issue 9558017: Update net/third_party/nss to NSS 3.13.3. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Upload before checkin Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/third_party/nss/ssl/ssl.h ('k') | net/third_party/nss/ssl/ssl3ecc.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 */
« no previous file with comments | « net/third_party/nss/ssl/ssl.h ('k') | net/third_party/nss/ssl/ssl3ecc.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698