summaryrefslogtreecommitdiffstats
path: root/net/third_party
diff options
context:
space:
mode:
authorrkn@chromium.org <rkn@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-19 22:49:38 +0000
committerrkn@chromium.org <rkn@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-19 22:49:38 +0000
commitdd01d01beab22bbcce4a726de58a8bcfb6b208a8 (patch)
treeacf35c62d897e5cebc93033e6c53ab8323b20a8d /net/third_party
parent7b609a8c1c76507112a7d77e0c1375ac4b5865c6 (diff)
downloadchromium_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.mn1
-rw-r--r--net/third_party/nss/ssl/ssl.h13
-rw-r--r--net/third_party/nss/ssl/ssl3con.c73
-rw-r--r--net/third_party/nss/ssl/ssl3ext.c112
-rw-r--r--net/third_party/nss/ssl/sslauth.c15
-rw-r--r--net/third_party/nss/ssl/sslimpl.h17
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