Index: net/third_party/nss/patches/cachedinfo.patch |
=================================================================== |
--- net/third_party/nss/patches/cachedinfo.patch (revision 124804) |
+++ net/third_party/nss/patches/cachedinfo.patch (working copy) |
@@ -1,975 +0,0 @@ |
-From 1c425d479c495d266c23876887198a54e82e7078 Mon Sep 17 00:00:00 2001 |
-From: Adam Langley <agl@chromium.org> |
-Date: Mon, 3 Oct 2011 12:22:24 -0400 |
-Subject: [PATCH] cachedinfo.patch |
- |
---- |
- mozilla/security/nss/lib/ssl/fnv1a64.c | 72 +++++++++ |
- mozilla/security/nss/lib/ssl/manifest.mn | 1 + |
- mozilla/security/nss/lib/ssl/ssl.h | 26 +++ |
- mozilla/security/nss/lib/ssl/ssl3con.c | 221 +++++++++++++++++++------ |
- mozilla/security/nss/lib/ssl/ssl3ext.c | 258 ++++++++++++++++++++++++++++++ |
- mozilla/security/nss/lib/ssl/sslauth.c | 40 +++++ |
- mozilla/security/nss/lib/ssl/sslimpl.h | 33 ++++- |
- mozilla/security/nss/lib/ssl/sslsock.c | 11 ++ |
- mozilla/security/nss/lib/ssl/sslt.h | 3 +- |
- 9 files changed, 611 insertions(+), 54 deletions(-) |
- create mode 100644 mozilla/security/nss/lib/ssl/fnv1a64.c |
- |
-diff --git a/mozilla/security/nss/lib/ssl/fnv1a64.c b/mozilla/security/nss/lib/ssl/fnv1a64.c |
-new file mode 100644 |
-index 0000000..c7c4b08 |
---- /dev/null |
-+++ b/mozilla/security/nss/lib/ssl/fnv1a64.c |
-@@ -0,0 +1,72 @@ |
-+/* |
-+ * FNV1A64 Hash |
-+ * http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param |
-+ * |
-+ * ***** BEGIN LICENSE BLOCK ***** |
-+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
-+ * |
-+ * The contents of this file are subject to the Mozilla Public License Version |
-+ * 1.1 (the "License"); you may not use this file except in compliance with |
-+ * the License. You may obtain a copy of the License at |
-+ * http://www.mozilla.org/MPL/ |
-+ * |
-+ * Software distributed under the License is distributed on an "AS IS" basis, |
-+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
-+ * for the specific language governing rights and limitations under the |
-+ * License. |
-+ * |
-+ * The Original Code is the Netscape security libraries. |
-+ * |
-+ * The Initial Developer of the Original Code is |
-+ * Netscape Communications Corporation. |
-+ * Portions created by the Initial Developer are Copyright (C) 1994-2000 |
-+ * the Initial Developer. All Rights Reserved. |
-+ * |
-+ * Contributor(s): |
-+ * Adam Langley, Google Inc. |
-+ * |
-+ * Alternatively, the contents of this file may be used under the terms of |
-+ * either the GNU General Public License Version 2 or later (the "GPL"), or |
-+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
-+ * in which case the provisions of the GPL or the LGPL are applicable instead |
-+ * of those above. If you wish to allow use of your version of this file only |
-+ * under the terms of either the GPL or the LGPL, and not to allow others to |
-+ * use your version of this file under the terms of the MPL, indicate your |
-+ * decision by deleting the provisions above and replace them with the notice |
-+ * and other provisions required by the GPL or the LGPL. If you do not delete |
-+ * the provisions above, a recipient may use your version of this file under |
-+ * the terms of any one of the MPL, the GPL or the LGPL. |
-+ * |
-+ * ***** END LICENSE BLOCK ***** */ |
-+ |
-+/* $Id: fnv1a64.c,v 1.0 2010/08/09 13:00:00 agl%google.com Exp $ */ |
-+ |
-+#include "prtypes.h" |
-+#include "prnetdb.h" |
-+ |
-+/* Older versions of Visual C++ don't support the 'ull' suffix. */ |
-+#ifdef _MSC_VER |
-+static const PRUint64 FNV1A64_OFFSET_BASIS = 14695981039346656037ui64; |
-+static const PRUint64 FNV1A64_PRIME = 1099511628211ui64; |
-+#else |
-+static const PRUint64 FNV1A64_OFFSET_BASIS = 14695981039346656037ull; |
-+static const PRUint64 FNV1A64_PRIME = 1099511628211ull; |
-+#endif |
-+ |
-+void FNV1A64_Init(PRUint64* digest) { |
-+ *digest = FNV1A64_OFFSET_BASIS; |
-+} |
-+ |
-+void FNV1A64_Update(PRUint64* digest, const unsigned char *data, |
-+ unsigned int length) { |
-+ unsigned int i; |
-+ |
-+ for (i = 0; i < length; i++) { |
-+ *digest ^= data[i]; |
-+ *digest *= FNV1A64_PRIME; |
-+ } |
-+} |
-+ |
-+void FNV1A64_Final(PRUint64 *digest) { |
-+ *digest = PR_htonll(*digest); |
-+} |
-diff --git a/mozilla/security/nss/lib/ssl/manifest.mn b/mozilla/security/nss/lib/ssl/manifest.mn |
-index 8451229..f09d770 100644 |
---- a/mozilla/security/nss/lib/ssl/manifest.mn |
-+++ b/mozilla/security/nss/lib/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/mozilla/security/nss/lib/ssl/ssl.h b/mozilla/security/nss/lib/ssl/ssl.h |
-index 221fe2d..3a22b45 100644 |
---- a/mozilla/security/nss/lib/ssl/ssl.h |
-+++ b/mozilla/security/nss/lib/ssl/ssl.h |
-@@ -140,6 +140,8 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd); |
- /* bits. The advantage of False Start is that it saves a round trip for */ |
- /* client-speaks-first protocols when performing a full handshake. */ |
- #define SSL_ENABLE_OCSP_STAPLING 23 /* Request OCSP stapling (client) */ |
-+#define SSL_ENABLE_CACHED_INFO 24 /* Enable TLS cached information */ |
-+ /* extension, off by default. */ |
- |
- #ifdef SSL_DEPRECATED_FUNCTION |
- /* Old deprecated function names */ |
-@@ -256,6 +258,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 |
-@@ -275,6 +283,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 |
-@@ -405,6 +420,17 @@ SSL_IMPORT SECStatus SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, |
- void *arg); |
- |
- /* |
-+ ** Set the predicted chain of certificates for the peer. This is used for the |
-+ ** TLS Cached Info extension. Note that the SSL_ENABLE_CACHED_INFO option must |
-+ ** be set for this to occur. |
-+ ** |
-+ ** This function takes a reference to each of the given certificates. |
-+ */ |
-+ SSL_IMPORT SECStatus SSL_SetPredictedPeerCertificates( |
-+ PRFileDesc *fd, CERTCertificate **certs, |
-+ unsigned int numCerts); |
-+ |
-+/* |
- ** Configure SSL socket for running a secure server. Needs the |
- ** certificate for the server and the servers private key. The arguments |
- ** are copied. |
-diff --git a/mozilla/security/nss/lib/ssl/ssl3con.c b/mozilla/security/nss/lib/ssl/ssl3con.c |
-index ca2793f..dd99962 100644 |
---- a/mozilla/security/nss/lib/ssl/ssl3con.c |
-+++ b/mozilla/security/nss/lib/ssl/ssl3con.c |
-@@ -5145,7 +5145,6 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) |
- ssl3_CopyPeerCertsFromSID(ss, sid); |
- } |
- |
-- |
- /* NULL value for PMS signifies re-use of the old MS */ |
- rv = ssl3_InitPendingCipherSpec(ss, NULL); |
- if (rv != SECSuccess) { |
-@@ -7715,6 +7714,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. */ |
-@@ -7869,7 +7931,6 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) |
- PRInt32 size; |
- SECStatus rv; |
- PRBool isServer = (PRBool)(!!ss->sec.isServer); |
-- PRBool trusted = PR_FALSE; |
- PRBool isTLS; |
- SSL3AlertDescription desc = bad_certificate; |
- int errCode = SSL_ERROR_RX_MALFORMED_CERTIFICATE; |
-@@ -7929,35 +7990,46 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) |
- goto loser; /* don't send alerts on memory errors */ |
- } |
- |
-- /* First get the peer cert. */ |
-- remaining -= 3; |
-- if (remaining < 0) |
-- goto decode_loser; |
-+ if (length == 12 && ssl3_ExtensionNegotiated(ss, ssl_cached_info_xtn)) { |
-+ /* We are dealing with a certificate_chain digest */ |
-+ int i; |
- |
-- size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length); |
-- if (size <= 0) |
-- goto loser; /* fatal alert already sent by ConsumeHandshake. */ |
-+ ss->ssl3.cachedInfoCertChainDigestReceived = PR_TRUE; |
- |
-- if (remaining < size) |
-- goto decode_loser; |
-+ /* Make sure the digests match. */ |
-+ if (memcmp(b + 4, ss->ssl3.certChainDigest, 8)) { |
-+ desc = handshake_failure; |
-+ goto alert_loser; |
-+ } |
- |
-- certItem.data = b; |
-- certItem.len = size; |
-- b += size; |
-- length -= size; |
-- remaining -= size; |
-+ /* 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]); |
- |
-- 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; |
-- } |
-+ /* 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; |
- |
-- /* Now get all of the CA certs. */ |
-- while (remaining > 0) { |
-+ /* First get the peer cert. */ |
- remaining -= 3; |
- if (remaining < 0) |
- goto decode_loser; |
-@@ -7971,35 +8043,63 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) |
- |
- certItem.data = b; |
- certItem.len = size; |
-- b += 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) { |
-+ 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; |
- } |
- |
-- if (c->cert->trust) |
-- trusted = PR_TRUE; |
-+ /* Now get all of the CA certs. */ |
-+ while (remaining > 0) { |
-+ remaining -= 3; |
-+ if (remaining < 0) |
-+ goto decode_loser; |
- |
-- c->next = NULL; |
-- if (lastCert) { |
-- lastCert->next = c; |
-- } else { |
-- certs = c; |
-+ 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; |
- } |
-- lastCert = c; |
-- } |
- |
-- if (remaining != 0) |
-- goto decode_loser; |
-+ if (remaining != 0) |
-+ goto decode_loser; |
-+ |
-+ ss->ssl3.peerCertChain = certs; certs = NULL; arena = NULL; |
-+ } |
- |
- SECKEY_UpdateCertPQG(ss->sec.peerCert); |
- |
-@@ -8019,8 +8119,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; |
- } |
-@@ -8045,7 +8143,7 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) |
- } |
- |
- ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert); |
-- ssl3_CopyPeerCertsToSID(certs, ss->sec.ci.sid); |
-+ ssl3_CopyPeerCertsToSID(ss->ssl3.peerCertChain, ss->sec.ci.sid); |
- |
- if (!ss->sec.isServer) { |
- /* set the server authentication and key exchange types and sizes |
-@@ -8090,8 +8188,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; |
-@@ -8161,7 +8257,10 @@ alert_loser: |
- (void)SSL3_SendAlert(ss, alert_fatal, desc); |
- |
- loser: |
-- ss->ssl3.peerCertChain = certs; certs = NULL; arena = NULL; |
-+ 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) { |
-@@ -9647,6 +9746,21 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache) |
- 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) |
-@@ -9666,6 +9780,9 @@ ssl3_DestroySSL3Info(sslSocket *ss) |
- 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); |
-diff --git a/mozilla/security/nss/lib/ssl/ssl3ext.c b/mozilla/security/nss/lib/ssl/ssl3ext.c |
-index 4e3d9cc..17898fb 100644 |
---- a/mozilla/security/nss/lib/ssl/ssl3ext.c |
-+++ b/mozilla/security/nss/lib/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 } |
- }; |
- |
-@@ -247,6 +248,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = { |
- { ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn }, |
- { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, |
- { ssl_next_proto_neg_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, |
-+ { ssl_cached_info_xtn, &ssl3_ClientHandleCachedInfoXtn }, |
- { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn }, |
- { -1, NULL } |
- }; |
-@@ -272,6 +274,7 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = { |
- #endif |
- { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, |
- { ssl_next_proto_neg_xtn, &ssl3_ClientSendNextProtoNegoXtn }, |
-+ { ssl_cached_info_xtn, &ssl3_ClientSendCachedInfoXtn }, |
- { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn } |
- /* any extra entries will appear as { 0, NULL } */ |
- }; |
-@@ -676,6 +679,261 @@ ssl3_ClientHandleStatusRequestXtn(sslSocket *ss, PRUint16 ex_type, |
- return SECSuccess; |
- } |
- |
-+/* ssl3_ClientSendCachedInfoXtn builds the cached_info extension on the |
-+ * client side. */ |
-+PRInt32 |
-+ssl3_ClientSendCachedInfoXtn(sslSocket * ss, PRBool append, |
-+ PRUint32 maxBytes) |
-+{ |
-+ PRInt32 extension_length; |
-+ PRBool send_empty; |
-+ CERTCertificate ** predictedCertChain; |
-+ |
-+ if (!ss->opt.enableCachedInfo) |
-+ return 0; |
-+ |
-+ predictedCertChain = ss->ssl3.predictedCertChain; |
-+ send_empty = (predictedCertChain == NULL); |
-+ |
-+ /* minimum extension: |
-+ * extension_type (2-bytes) + |
-+ * length(extension_data) (2-bytes) + |
-+ * length(cached_info) (2-bytes) + |
-+ */ |
-+ extension_length = send_empty ? 6 : 16; |
-+ |
-+ if (append && maxBytes >= extension_length) { |
-+ SECStatus rv; |
-+ |
-+ /* 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; |
-+ if (send_empty) { |
-+ /* Cached Information Length */ |
-+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2); |
-+ if (rv != SECSuccess) |
-+ return -1; |
-+ } else { |
-+ PRUint64 certChainHash; |
-+ int i; |
-+ PRUint8* digestPtr = (PRUint8*) &certChainHash; |
-+ |
-+ /* Cached Information Length */ |
-+ rv = ssl3_AppendHandshakeNumber(ss, 10, 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, 8, 1); |
-+ if (rv != SECSuccess) |
-+ return -1; |
-+ /* hash */ |
-+ FNV1A64_Init(&certChainHash); |
-+ for (i = 0; predictedCertChain[i] != NULL; i++) { |
-+ unsigned int certLen = predictedCertChain[i]->derCert.len; |
-+ unsigned char certLenArray[3] = { |
-+ certLen >> 16, |
-+ certLen >> 8, |
-+ certLen |
-+ }; |
-+ FNV1A64_Update(&certChainHash, certLenArray, 3); |
-+ FNV1A64_Update(&certChainHash, |
-+ predictedCertChain[i]->derCert.data, certLen); |
-+ } |
-+ FNV1A64_Final(&certChainHash); |
-+ rv = ssl3_AppendHandshake(ss, &certChainHash, 8); |
-+ if (rv != SECSuccess) |
-+ return -1; |
-+ for (i = 0; i < 8; i++) { |
-+ ss->ssl3.certChainDigest[i] = digestPtr[i]; |
-+ } |
-+ } |
-+ |
-+ } else if (maxBytes < extension_length) { |
-+ PORT_Assert(0); |
-+ return 0; |
-+ } |
-+ ss->xtnData.advertised[ss->xtnData.numAdvertised++] = |
-+ ssl_cached_info_xtn; |
-+ return extension_length; |
-+} |
-+ |
-+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) |
-+{ |
-+ unsigned char * cached_info = data->data; |
-+ unsigned int remaining_cached_info_length; |
-+ PRBool has_correct_cert_chain = PR_FALSE; |
-+ |
-+ /* If we didn't request this extension, then the server may not echo it. */ |
-+ if (!ss->opt.enableCachedInfo) |
-+ return SECFailure; |
-+ |
-+ if (data->len == 0) { |
-+ /* The server supports information caching, but provides no information |
-+ * about what information types it supports */ |
-+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; |
-+ return SECSuccess; |
-+ } |
-+ |
-+ if (data->len < 2) |
-+ return SECFailure; |
-+ remaining_cached_info_length = (cached_info[0] << 8) | cached_info[1]; |
-+ if (remaining_cached_info_length != data->len - 2) |
-+ return SECFailure; |
-+ cached_info += 2; |
-+ while (remaining_cached_info_length >= 2) { |
-+ /* The server supports only those CachedInformationType types that are |
-+ * identified by a present CachedObject */ |
-+ unsigned char cached_object_type; |
-+ unsigned int cached_object_length; |
-+ unsigned char cached_object_digest[8]; |
-+ cached_object_type = *cached_info++; |
-+ cached_object_length = *cached_info++; |
-+ remaining_cached_info_length -= 2; |
-+ if (remaining_cached_info_length < cached_object_length) |
-+ return SECFailure; |
-+ if (cached_object_length != 0 && cached_object_length != 8) |
-+ return SECFailure; |
-+ remaining_cached_info_length -= cached_object_length; |
-+ if (cached_object_type == cached_info_certificate_chain) { |
-+ if (cached_object_length == 0) |
-+ has_correct_cert_chain = PR_TRUE; |
-+ else { /* Hashes must match */ |
-+ int i; |
-+ for (i = 0; i < 8; i++) |
-+ cached_object_digest[i] = *cached_info++; |
-+ if (!memcmp(cached_object_digest, ss->ssl3.certChainDigest, 8)) |
-+ has_correct_cert_chain = PR_TRUE; |
-+ } |
-+ } |
-+ } |
-+ |
-+ if (remaining_cached_info_length != 0) |
-+ return SECFailure; |
-+ |
-+ if (has_correct_cert_chain) { |
-+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; |
-+ return SECSuccess; |
-+ } |
-+ |
-+ return SECFailure; |
-+} |
-+ |
- /* ssl3_ClientSendStatusRequestXtn builds the status_request extension on the |
- * client side. See RFC 4366 section 3.6. */ |
- PRInt32 |
-diff --git a/mozilla/security/nss/lib/ssl/sslauth.c b/mozilla/security/nss/lib/ssl/sslauth.c |
-index df40f30..fcd15ca 100644 |
---- a/mozilla/security/nss/lib/ssl/sslauth.c |
-+++ b/mozilla/security/nss/lib/ssl/sslauth.c |
-@@ -95,6 +95,46 @@ SSL_PeerCertificateChain(PRFileDesc *fd, CERTCertificate **certs, |
- return SECSuccess; |
- } |
- |
-+SECStatus |
-+SSL_SetPredictedPeerCertificates(PRFileDesc *fd, CERTCertificate **certs, |
-+ unsigned int numCerts) |
-+{ |
-+ sslSocket *ss; |
-+ unsigned int i; |
-+ |
-+ ss = ssl_FindSocket(fd); |
-+ if (!ss) { |
-+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetPredictedPeerCertificates", |
-+ SSL_GETPID(), fd)); |
-+ return SECFailure; |
-+ } |
-+ |
-+ ss->ssl3.predictedCertChain = |
-+ PORT_NewArray(CERTCertificate*, numCerts + 1); |
-+ if (!ss->ssl3.predictedCertChain) |
-+ return SECFailure; /* error code was set */ |
-+ for (i = 0; i < numCerts; i++) |
-+ ss->ssl3.predictedCertChain[i] = CERT_DupCertificate(certs[i]); |
-+ ss->ssl3.predictedCertChain[numCerts] = NULL; |
-+ |
-+ 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/mozilla/security/nss/lib/ssl/sslimpl.h b/mozilla/security/nss/lib/ssl/sslimpl.h |
-index 8e2bd14..f1e9a3e 100644 |
---- a/mozilla/security/nss/lib/ssl/sslimpl.h |
-+++ b/mozilla/security/nss/lib/ssl/sslimpl.h |
-@@ -340,6 +340,7 @@ typedef struct sslOptionsStr { |
- unsigned int requireSafeNegotiation : 1; /* 22 */ |
- unsigned int enableFalseStart : 1; /* 23 */ |
- unsigned int enableOCSPStapling : 1; /* 24 */ |
-+ unsigned int enableCachedInfo : 1; /* 25 */ |
- } sslOptions; |
- |
- typedef enum { sslHandshakingUndetermined = 0, |
-@@ -754,6 +755,11 @@ struct TLSExtensionDataStr { |
- PRUint32 sniNameArrSize; |
- }; |
- |
-+typedef enum { |
-+ cached_info_certificate_chain = 1, |
-+ cached_info_trusted_cas = 2 |
-+} TLSCachedInfoType; |
-+ |
- /* |
- ** This is the "hs" member of the "ssl3" struct. |
- ** This entire struct is protected by ssl3HandshakeLock |
-@@ -832,6 +838,14 @@ struct ssl3StateStr { |
- CERTCertificateList *clientCertChain; /* used by client */ |
- PRBool sendEmptyCert; /* used by client */ |
- |
-+ /* TLS Cached Info Extension */ |
-+ CERTCertificate ** predictedCertChain; |
-+ /* An array terminated with a NULL. */ |
-+ PRUint8 certChainDigest[8]; |
-+ /* Used in cached info extension. Stored in network |
-+ * byte order. */ |
-+ PRBool cachedInfoCertChainDigestReceived; |
-+ |
- int policy; |
- /* This says what cipher suites we can do, and should |
- * be either SSL_ALLOWED or SSL_RESTRICTED |
-@@ -839,7 +853,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; |
-@@ -1524,6 +1541,10 @@ 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, |
- PRUint16 ex_type, SECItem *data); |
- extern SECStatus ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, |
-@@ -1545,6 +1566,10 @@ extern PRInt32 ssl3_ClientSendStatusRequestXtn(sslSocket *ss, PRBool append, |
- */ |
- 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); |
- |
- /* Assigns new cert, cert chain and keys to ss->serverCerts |
- * struct. If certChain is NULL, tries to find one. Aborts if |
-@@ -1648,6 +1673,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 |
-diff --git a/mozilla/security/nss/lib/ssl/sslsock.c b/mozilla/security/nss/lib/ssl/sslsock.c |
-index 4c4df3f..3d89d86 100644 |
---- a/mozilla/security/nss/lib/ssl/sslsock.c |
-+++ b/mozilla/security/nss/lib/ssl/sslsock.c |
-@@ -186,6 +186,7 @@ static sslOptions ssl_defaults = { |
- PR_FALSE, /* requireSafeNegotiation */ |
- PR_FALSE, /* enableFalseStart */ |
- PR_FALSE, /* enableOCSPStapling */ |
-+ PR_FALSE, /* enableCachedInfo */ |
- }; |
- |
- sslSessionIDLookupFunc ssl_sid_lookup; |
-@@ -743,6 +744,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) |
- ss->opt.enableOCSPStapling = on; |
- break; |
- |
-+ case SSL_ENABLE_CACHED_INFO: |
-+ ss->opt.enableCachedInfo = on; |
-+ break; |
-+ |
- default: |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- rv = SECFailure; |
-@@ -808,6 +813,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) |
- on = ss->opt.requireSafeNegotiation; break; |
- case SSL_ENABLE_FALSE_START: on = ss->opt.enableFalseStart; break; |
- case SSL_ENABLE_OCSP_STAPLING: on = ss->opt.enableOCSPStapling; break; |
-+ case SSL_ENABLE_CACHED_INFO: on = ss->opt.enableCachedInfo; break; |
- |
- default: |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
-@@ -862,6 +868,7 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) |
- case SSL_ENABLE_OCSP_STAPLING: |
- on = ssl_defaults.enableOCSPStapling; |
- break; |
-+ case SSL_ENABLE_CACHED_INFO: on = ssl_defaults.enableCachedInfo; break; |
- |
- default: |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
-@@ -1013,6 +1020,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on) |
- ssl_defaults.enableOCSPStapling = on; |
- break; |
- |
-+ case SSL_ENABLE_CACHED_INFO: |
-+ ssl_defaults.enableCachedInfo = on; |
-+ break; |
-+ |
- default: |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- return SECFailure; |
-diff --git a/mozilla/security/nss/lib/ssl/sslt.h b/mozilla/security/nss/lib/ssl/sslt.h |
-index 917c093..bca7496 100644 |
---- a/mozilla/security/nss/lib/ssl/sslt.h |
-+++ b/mozilla/security/nss/lib/ssl/sslt.h |
-@@ -205,9 +205,10 @@ typedef enum { |
- #endif |
- ssl_session_ticket_xtn = 35, |
- ssl_next_proto_neg_xtn = 13172, |
-+ ssl_cached_info_xtn = 13173, |
- ssl_renegotiation_info_xtn = 0xff01 /* experimental number */ |
- } SSLExtensionType; |
- |
--#define SSL_MAX_EXTENSIONS 7 |
-+#define SSL_MAX_EXTENSIONS 8 |
- |
- #endif /* __sslt_h_ */ |