diff options
author | rkn@chromium.org <rkn@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-19 22:49:38 +0000 |
---|---|---|
committer | rkn@chromium.org <rkn@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-19 22:49:38 +0000 |
commit | dd01d01beab22bbcce4a726de58a8bcfb6b208a8 (patch) | |
tree | acf35c62d897e5cebc93033e6c53ab8323b20a8d /net/third_party | |
parent | 7b609a8c1c76507112a7d77e0c1375ac4b5865c6 (diff) | |
download | chromium_src-dd01d01beab22bbcce4a726de58a8bcfb6b208a8.zip chromium_src-dd01d01beab22bbcce4a726de58a8bcfb6b208a8.tar.gz chromium_src-dd01d01beab22bbcce4a726de58a8bcfb6b208a8.tar.bz2 |
Merge upstream NSS changes from the cached info extension.
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/7379009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@93119 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/third_party')
-rw-r--r-- | net/third_party/nss/ssl/manifest.mn | 1 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl.h | 13 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3con.c | 73 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3ext.c | 112 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslauth.c | 15 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslimpl.h | 17 |
6 files changed, 220 insertions, 11 deletions
diff --git a/net/third_party/nss/ssl/manifest.mn b/net/third_party/nss/ssl/manifest.mn index 8451229..f09d770 100644 --- a/net/third_party/nss/ssl/manifest.mn +++ b/net/third_party/nss/ssl/manifest.mn @@ -51,6 +51,7 @@ MAPFILE = $(OBJDIR)/ssl.def CSRCS = \ derive.c \ + fnv1a64.c \ prelib.c \ ssl3con.c \ ssl3gthr.c \ diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h index 38edb7f..53ca301 100644 --- a/net/third_party/nss/ssl/ssl.h +++ b/net/third_party/nss/ssl/ssl.h @@ -259,6 +259,12 @@ SSL_IMPORT SECStatus SSL_SecurityStatus(PRFileDesc *fd, int *on, char **cipher, #define SSL_SECURITY_STATUS_FORTEZZA 3 /* NO LONGER SUPPORTED */ /* +** Returns true if the server's Certificate message contained a hash of the +** certificate chain due to the TLS cached info extension. +*/ +SSL_IMPORT PRBool SSL_CertChainDigestReceived(PRFileDesc *fd); + +/* ** Return the certificate for our SSL peer. If the client calls this ** it will always return the server's certificate. If the server calls ** this, it may return NULL if client authentication is not enabled or @@ -278,6 +284,13 @@ SSL_IMPORT CERTCertificate *SSL_PeerCertificate(PRFileDesc *fd); SSL_IMPORT SECStatus SSL_PeerCertificateChain( PRFileDesc *fd, CERTCertificate **certs, unsigned int *certs_size); +/* +** Set the predicted cert chain to be used in the cached info extension. +*/ +SSL_IMPORT SECStatus SSL_SetPredictedPeerCertificates(PRFileDesc *fd, + CERTCertificate **certs, + unsigned int len); + /* SSL_GetStapledOCSPResponse returns the OCSP response that was provided by * the TLS server. The resulting data is copied to |out_data|. On entry, |*len| * must contain the size of |out_data|. On exit, |*len| will contain the size diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c index eb7d63e..c39b8f8 100644 --- a/net/third_party/nss/ssl/ssl3con.c +++ b/net/third_party/nss/ssl/ssl3con.c @@ -7827,6 +7827,69 @@ ssl3_SendCertificate(sslSocket *ss) } } + 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. */ @@ -8044,7 +8107,7 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) /* We are dealing with a certificate_chain digest */ int i; - ss->ssl3.digestReceived = PR_TRUE; + ss->ssl3.cachedInfoCertChainDigestReceived = PR_TRUE; /* Make sure the digests match. */ if (memcmp(b + 4, ss->ssl3.certChainDigest, 8)) { @@ -8077,7 +8140,7 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } } else { /* We are dealing with a regular certificate message */ - ss->ssl3.digestReceived = PR_FALSE; + ss->ssl3.cachedInfoCertChainDigestReceived = PR_FALSE; /* First get the peer cert. */ remaining -= 3; @@ -8147,6 +8210,8 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) if (remaining != 0) goto decode_loser; + + ss->ssl3.peerCertChain = certs; certs = NULL; arena = NULL; } SECKEY_UpdateCertPQG(ss->sec.peerCert); @@ -8167,8 +8232,6 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) /* someone will handle this connection asynchronously*/ SSL_DBG(("%d: SSL3[%d]: go to async cert handler", SSL_GETPID(), ss->fd)); - ss->ssl3.peerCertChain = certs; - certs = NULL; ssl_SetAlwaysBlock(ss); goto cert_block; } @@ -8238,8 +8301,6 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } } - ss->ssl3.peerCertChain = certs; certs = NULL; arena = NULL; - cert_block: if (ss->sec.isServer) { ss->ssl3.hs.ws = wait_client_key; diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c index e3513a3..0342bd0 100644 --- a/net/third_party/nss/ssl/ssl3ext.c +++ b/net/third_party/nss/ssl/ssl3ext.c @@ -236,6 +236,7 @@ static const ssl3HelloExtensionHandler clientHelloHandlers[] = { { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn }, { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, { ssl_next_proto_neg_xtn, &ssl3_ServerHandleNextProtoNegoXtn }, + { ssl_cached_info_xtn, &ssl3_ServerHandleCachedInfoXtn }, { -1, NULL } }; @@ -741,9 +742,9 @@ ssl3_ClientSendCachedInfoXtn(sslSocket * ss, PRBool append, for (i = 0; predictedCertChain[i] != NULL; i++) { unsigned int certLen = predictedCertChain[i]->derCert.len; unsigned char certLenArray[3] = { - (certLen & 0xff0000) >> 16, - (certLen & 0xff00) >> 8, - certLen & 0xff + certLen >> 16, + certLen >> 8, + certLen }; FNV1A64_Update(&certChainHash, certLenArray, 3); FNV1A64_Update(&certChainHash, @@ -768,6 +769,111 @@ ssl3_ClientSendCachedInfoXtn(sslSocket * ss, PRBool append, } SECStatus +ssl3_ServerHandleCachedInfoXtn(sslSocket *ss, PRUint16 ex_type, + SECItem *data) +{ + SECStatus rv; + unsigned char *cached_info = data->data; + unsigned int remaining_len; + + /* Ignore the extension if it isn't enabled. */ + if (!ss->opt.enableCachedInfo) + return SECSuccess; + + if (data->len < 2) + return SECFailure; + remaining_len = (cached_info[0] << 8) | cached_info[1]; + if (remaining_len > 2048 || remaining_len != data->len - 2) + return SECFailure; + cached_info += 2; + + /* Handle reconnaissance case. */ + if (remaining_len == 0) { + /* The client supports information caching, but provides no information + * about what information types it supports */ + ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; + rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type, + ssl3_ServerSendCachedInfoXtn); + return rv; + } + + /* Iterate over the CachedObjects and pick the first item of type + * certificate_chain, while ignoring everything else. */ + while (remaining_len >= 2) { + unsigned char cached_object_type = *cached_info++; + unsigned int cached_object_length = *cached_info++; + remaining_len -= 2; + if (remaining_len < cached_object_length) + return SECFailure; + if (cached_object_length != 8) /* The digest must be present. */ + return SECFailure; + if (cached_object_type == cached_info_certificate_chain && + !ss->ssl3.cachedInfoCertChainDigestReceived) { + ss->ssl3.cachedInfoCertChainDigestReceived = PR_TRUE; + memcpy(ss->ssl3.certChainDigest, cached_info, 8); + } + remaining_len -= cached_object_length; + cached_info += cached_object_length; + } + + if (remaining_len != 0) + return SECFailure; + + if (ss->ssl3.cachedInfoCertChainDigestReceived) { + ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; + rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type, + ssl3_ServerSendCachedInfoXtn); + return SECSuccess; + } + + return SECSuccess; +} + +/* ssl3_ServerSendCachedInfoXtn builds the cached_info extension on the + * server side. */ +PRInt32 +ssl3_ServerSendCachedInfoXtn(sslSocket * ss, PRBool append, + PRUint32 maxBytes) +{ + PRInt32 extension_length = 2 /* extension type */ + + 2 /* extension length */ + + 2 /* cached_info length */ + + 1 /* CachedInformationType */ + + 1 /* hash value length (0) */; + SECStatus rv; + + PORT_Assert(ss->opt.enableCachedInfo); + + if (append && maxBytes >= extension_length) { + /* ExtensionType */ + rv = ssl3_AppendHandshakeNumber(ss, ssl_cached_info_xtn, 2); + if (rv != SECSuccess) + return -1; + /* Extension Length */ + rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); + if (rv != SECSuccess) + return -1; + /* Cached Information Length */ + rv = ssl3_AppendHandshakeNumber(ss, 2, 2); + if (rv != SECSuccess) + return -1; + /* Cached Information Type */ + rv = ssl3_AppendHandshakeNumber(ss, 1 /* certificate_chain */, 1); + if (rv != SECSuccess) + return -1; + /* hash length */ + rv = ssl3_AppendHandshakeNumber(ss, 0, 1); + if (rv != SECSuccess) + return -1; + } else if (maxBytes < extension_length) { + PORT_Assert(0); + return 0; + } + + return extension_length; +} + +SECStatus ssl3_ClientHandleCachedInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) { diff --git a/net/third_party/nss/ssl/sslauth.c b/net/third_party/nss/ssl/sslauth.c index 6313603..8da5c66 100644 --- a/net/third_party/nss/ssl/sslauth.c +++ b/net/third_party/nss/ssl/sslauth.c @@ -120,6 +120,21 @@ SSL_SetPredictedPeerCertificates(PRFileDesc *fd, CERTCertificate **certs, return SECSuccess; } +PRBool +SSL_CertChainDigestReceived(PRFileDesc *fd) +{ + sslSocket *ss; + + ss = ssl_FindSocket(fd); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_CertChainDigestReceived", + SSL_GETPID(), fd)); + return SECFailure; + } + + return ss->ssl3.cachedInfoCertChainDigestReceived; +} + /* NEED LOCKS IN HERE. */ CERTCertificate * SSL_LocalCertificate(PRFileDesc *fd) diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h index e9db8ae..df30029 100644 --- a/net/third_party/nss/ssl/sslimpl.h +++ b/net/third_party/nss/ssl/sslimpl.h @@ -867,7 +867,7 @@ struct ssl3StateStr { PRUint8 certChainDigest[8]; /* Used in cached info extension. Stored in network * byte order. */ - PRBool digestReceived; + PRBool cachedInfoCertChainDigestReceived; int policy; /* This says what cipher suites we can do, and should @@ -876,7 +876,10 @@ struct ssl3StateStr { PRArenaPool * peerCertArena; /* These are used to keep track of the peer CA */ void * peerCertChain; - /* chain while we are trying to validate it. */ + /* Chain while we are trying to validate it. This + * does not include the leaf cert. It is actually a + * linked list of ssl3CertNode structs. + */ CERTDistNames * ca_list; /* used by server. trusted CAs for this socket. */ PRBool initialized; @@ -1565,6 +1568,8 @@ extern SECStatus ssl3_ClientHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data); extern SECStatus ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data); +extern SECStatus ssl3_ServerHandleCachedInfoXtn(sslSocket *ss, + PRUint16 ex_type, SECItem *data); extern SECStatus ssl3_ClientHandleCachedInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data); extern SECStatus ssl3_ClientHandleStatusRequestXtn(sslSocket *ss, @@ -1594,6 +1599,8 @@ extern PRInt32 ssl3_SendServerNameXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes); extern PRInt32 ssl3_ClientSendCachedInfoXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes); +extern PRInt32 ssl3_ServerSendCachedInfoXtn(sslSocket *ss, PRBool append, + PRUint32 maxBytes); extern PRInt32 ssl3_SendOBCertXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes); @@ -1719,6 +1726,12 @@ SECStatus SSL_DisableDefaultExportCipherSuites(void); SECStatus SSL_DisableExportCipherSuites(PRFileDesc * fd); PRBool SSL_IsExportCipherSuite(PRUint16 cipherSuite); +/********************** FNV hash *********************/ + +void FNV1A64_Init(PRUint64 *digest); +void FNV1A64_Update(PRUint64 *digest, const unsigned char *data, + unsigned int length); +void FNV1A64_Final(PRUint64 *digest); #ifdef TRACE #define SSL_TRACE(msg) ssl_Trace msg |