summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-22 21:42:38 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-22 21:42:38 +0000
commit67d9e6801ab1201732fc2a1d13e95a2f330cc0f3 (patch)
tree53a8023a177fdebe038955b43fcda0b0612f6e19 /net
parent53edc64524d217d22b175f78f8c81df0ece79a11 (diff)
downloadchromium_src-67d9e6801ab1201732fc2a1d13e95a2f330cc0f3.zip
chromium_src-67d9e6801ab1201732fc2a1d13e95a2f330cc0f3.tar.gz
chromium_src-67d9e6801ab1201732fc2a1d13e95a2f330cc0f3.tar.bz2
nss: add support for OCSP stapling.
This patch adds support in libssl for requesting and storing OCSP stapled responses. BUG=none TEST=none (yet) http://codereview.chromium.org/5045001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@67005 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/third_party/nss/README.chromium3
-rw-r--r--net/third_party/nss/patches/ocspstapling.patch508
-rw-r--r--net/third_party/nss/ssl/ssl.def1
-rw-r--r--net/third_party/nss/ssl/ssl.h18
-rw-r--r--net/third_party/nss/ssl/ssl3con.c111
-rw-r--r--net/third_party/nss/ssl/ssl3ext.c76
-rw-r--r--net/third_party/nss/ssl/ssl3prot.h1
-rw-r--r--net/third_party/nss/ssl/sslerr.h2
-rw-r--r--net/third_party/nss/ssl/sslimpl.h13
-rw-r--r--net/third_party/nss/ssl/sslsock.c43
-rw-r--r--net/third_party/nss/ssl/sslt.h3
11 files changed, 778 insertions, 1 deletions
diff --git a/net/third_party/nss/README.chromium b/net/third_party/nss/README.chromium
index d7f242f..2f0c165 100644
--- a/net/third_party/nss/README.chromium
+++ b/net/third_party/nss/README.chromium
@@ -42,5 +42,8 @@ Patches:
patches/snapstart.patch
http://tools.ietf.org/html/draft-agl-tls-snapstart-00
+ * Add OCSP stapling support
+ patches/ocspstapling.patch
+
The ssl/bodge directory contains files taken from the NSS repo that we required
for building libssl outside of its usual build environment.
diff --git a/net/third_party/nss/patches/ocspstapling.patch b/net/third_party/nss/patches/ocspstapling.patch
new file mode 100644
index 0000000..13de561
--- /dev/null
+++ b/net/third_party/nss/patches/ocspstapling.patch
@@ -0,0 +1,508 @@
+commit aa046eb9a2f5bd6fb027a1a516c01ec2a093d287
+Author: Adam Langley <agl@chromium.org>
+Date: Mon Nov 22 16:40:05 2010 -0500
+
+ nss: add support for OCSP stapling.
+
+ This patch adds support in libssl for requesting and storing OCSP
+ stapled responses.
+
+ BUG=none
+ TEST=none (yet)
+
+ http://codereview.chromium.org/5045001
+
+diff --git a/net/third_party/nss/ssl/ssl.def b/net/third_party/nss/ssl/ssl.def
+index 60ebbb1..76417d0 100644
+--- a/net/third_party/nss/ssl/ssl.def
++++ b/net/third_party/nss/ssl/ssl.def
+@@ -163,6 +163,7 @@ SSL_SetNextProtoNego;
+ ;+ global:
+ SSL_GetPredictedServerHelloData;
+ SSL_GetSnapStartResult;
++SSL_GetStapledOCSPResponse;
+ SSL_PeerCertificateChain;
+ SSL_SetPredictedPeerCertificates;
+ SSL_SetPredictedServerHelloData;
+diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h
+index 9d3da0c..3515007 100644
+--- a/net/third_party/nss/ssl/ssl.h
++++ b/net/third_party/nss/ssl/ssl.h
+@@ -148,6 +148,7 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd);
+ /* previous connection to the same server is required. See */
+ /* SSL_GetPredictedServerHelloData, SSL_SetPredictedPeerCertificates and */
+ /* SSL_SetSnapStartApplicationData. */
++#define SSL_ENABLE_OCSP_STAPLING 24 /* Request OCSP stapling (client) */
+
+ #ifdef SSL_DEPRECATED_FUNCTION
+ /* Old deprecated function names */
+@@ -283,6 +284,23 @@ SSL_IMPORT CERTCertificate *SSL_PeerCertificate(PRFileDesc *fd);
+ SSL_IMPORT SECStatus SSL_PeerCertificateChain(
+ PRFileDesc *fd, CERTCertificate **certs, unsigned int *certs_size);
+
++/* 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
++ * of the OCSP stapled response. If the stapled response is too large to fit in
++ * |out_data| then it will be truncated. If no OCSP response was given by the
++ * server then it has zero length.
++ *
++ * You must set the SSL_ENABLE_OCSP_STAPLING option in order for OCSP responses
++ * to be provided by a server.
++ *
++ * You can call this function during the certificate verification callback or
++ * any time afterwards.
++ */
++SSL_IMPORT SECStatus SSL_GetStapledOCSPResponse(PRFileDesc *fd,
++ unsigned char *out_data,
++ unsigned int *len);
++
+ /*
+ ** Authenticate certificate hook. Called when a certificate comes in
+ ** (because of SSL_REQUIRE_CERTIFICATE in SSL_Enable) to authenticate the
+diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c
+index c5ea79f..d56bb97 100644
+--- a/net/third_party/nss/ssl/ssl3con.c
++++ b/net/third_party/nss/ssl/ssl3con.c
+@@ -7945,6 +7945,57 @@ ssl3_CopyPeerCertsToSID(ssl3CertNode *certs, sslSessionID *sid)
+ }
+
+ /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
++ * ssl3 CertificateStatus message.
++ * Caller must hold Handshake and RecvBuf locks.
++ * This is always called before ssl3_HandleCertificate, even if the Certificate
++ * message is sent first.
++ */
++static SECStatus
++ssl3_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
++{
++ PRInt32 status, len;
++ int errCode;
++ SSL3AlertDescription desc;
++
++ if (!ss->ssl3.hs.may_get_cert_status ||
++ ss->ssl3.hs.ws != wait_server_cert ||
++ !ss->ssl3.hs.pending_cert_msg.data ||
++ ss->ssl3.hs.cert_status.data) {
++ errCode = SSL_ERROR_RX_UNEXPECTED_CERT_STATUS;
++ desc = unexpected_message;
++ goto alert_loser;
++ }
++
++ /* Consume the CertificateStatusType enum */
++ status = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length);
++ if (status != 1 /* ocsp */) {
++ goto format_loser;
++ }
++
++ len = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
++ if (len != length) {
++ goto format_loser;
++ }
++
++ if (SECITEM_AllocItem(NULL, &ss->ssl3.hs.cert_status, length) == NULL) {
++ return SECFailure;
++ }
++ ss->ssl3.hs.cert_status.type = siBuffer;
++ PORT_Memcpy(ss->ssl3.hs.cert_status.data, b, length);
++
++ return SECSuccess;
++
++format_loser:
++ errCode = SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT;
++ desc = bad_certificate_status_response;
++
++alert_loser:
++ (void)SSL3_SendAlert(ss, alert_fatal, desc);
++ (void)ssl_MapLowLevelError(errCode);
++ return SECFailure;
++}
++
++/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 Certificate message.
+ * Caller must hold Handshake and RecvBuf locks.
+ */
+@@ -8773,6 +8824,26 @@ xmit_loser:
+ return SECSuccess;
+ }
+
++/* This function handles any pending Certificate messages. Certificate messages
++ * can be pending if we expect a possible CertificateStatus message to follow.
++ *
++ * This function must be called immediately after handling the
++ * CertificateStatus message, and before handling any ServerKeyExchange or
++ * CertificateRequest messages.
++ */
++static SECStatus
++ssl3_MaybeHandlePendingCertificateMessage(sslSocket *ss)
++{
++ SECStatus rv = SECSuccess;
++
++ if (ss->ssl3.hs.pending_cert_msg.data) {
++ rv = ssl3_HandleCertificate(ss, ss->ssl3.hs.pending_cert_msg.data,
++ ss->ssl3.hs.pending_cert_msg.len);
++ SECITEM_FreeItem(&ss->ssl3.hs.pending_cert_msg, PR_FALSE);
++ }
++ return rv;
++}
++
+ /* Called from ssl3_HandleHandshake() when it has gathered a complete ssl3
+ * hanshake message.
+ * Caller must hold Handshake and RecvBuf locks.
+@@ -8872,14 +8943,42 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+ rv = ssl3_HandleServerHello(ss, b, length);
+ break;
+ case certificate:
++ if (ss->ssl3.hs.may_get_cert_status) {
++ /* If we might get a CertificateStatus then we want to postpone the
++ * processing of the Certificate message until after we have
++ * processed the CertificateStatus */
++ if (ss->ssl3.hs.pending_cert_msg.data ||
++ ss->ssl3.hs.ws != wait_server_cert) {
++ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
++ (void)ssl_MapLowLevelError(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE);
++ return SECFailure;
++ }
++ if (SECITEM_AllocItem(NULL, &ss->ssl3.hs.pending_cert_msg,
++ length) == NULL) {
++ return SECFailure;
++ }
++ ss->ssl3.hs.pending_cert_msg.type = siBuffer;
++ PORT_Memcpy(ss->ssl3.hs.pending_cert_msg.data, b, length);
++ break;
++ }
+ rv = ssl3_HandleCertificate(ss, b, length);
+ break;
++ case certificate_status:
++ rv = ssl3_HandleCertificateStatus(ss, b, length);
++ if (rv != SECSuccess)
++ break;
++ PORT_Assert(ss->ssl3.hs.pending_cert_msg.data);
++ rv = ssl3_MaybeHandlePendingCertificateMessage(ss);
++ break;
+ case server_key_exchange:
+ if (ss->sec.isServer) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
+ return SECFailure;
+ }
++ rv = ssl3_MaybeHandlePendingCertificateMessage(ss);
++ if (rv != SECSuccess)
++ break;
+ rv = ssl3_HandleServerKeyExchange(ss, b, length);
+ break;
+ case certificate_request:
+@@ -8888,6 +8987,9 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST);
+ return SECFailure;
+ }
++ rv = ssl3_MaybeHandlePendingCertificateMessage(ss);
++ if (rv != SECSuccess)
++ break;
+ rv = ssl3_HandleCertificateRequest(ss, b, length);
+ break;
+ case server_hello_done:
+@@ -8901,6 +9003,9 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
+ return SECFailure;
+ }
++ rv = ssl3_MaybeHandlePendingCertificateMessage(ss);
++ if (rv != SECSuccess)
++ break;
+ rv = ssl3_HandleServerHelloDone(ss);
+ break;
+ case certificate_verify:
+@@ -9767,6 +9872,12 @@ ssl3_DestroySSL3Info(sslSocket *ss)
+ if (ss->ssl3.hs.origClientHello.data) {
+ SECITEM_FreeItem(&ss->ssl3.hs.origClientHello, PR_FALSE);
+ }
++ if (ss->ssl3.hs.pending_cert_msg.data) {
++ SECITEM_FreeItem(&ss->ssl3.hs.pending_cert_msg, PR_FALSE);
++ }
++ if (ss->ssl3.hs.cert_status.data) {
++ SECITEM_FreeItem(&ss->ssl3.hs.cert_status, PR_FALSE);
++ }
+
+ /* free the SSL3Buffer (msg_body) */
+ PORT_Free(ss->ssl3.hs.msg_body.buf);
+diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c
+index f044e1c..b93671e 100644
+--- a/net/third_party/nss/ssl/ssl3ext.c
++++ b/net/third_party/nss/ssl/ssl3ext.c
+@@ -247,6 +247,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_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
+ { ssl_snap_start_xtn, &ssl3_ClientHandleSnapStartXtn },
+ { -1, NULL }
+ };
+@@ -272,6 +273,7 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = {
+ #endif
+ { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn },
+ { ssl_next_proto_neg_xtn, &ssl3_ClientSendNextProtoNegoXtn },
++ { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
+ { ssl_snap_start_xtn, &ssl3_SendSnapStartXtn }
+ /* NOTE: The Snap Start sender MUST be the last extension in the list. */
+ /* any extra entries will appear as { 0, NULL } */
+@@ -659,6 +661,80 @@ ssl3_ClientSendNextProtoNegoXtn(sslSocket * ss,
+ return -1;
+ }
+
++SECStatus
++ssl3_ClientHandleStatusRequestXtn(sslSocket *ss, PRUint16 ex_type,
++ SECItem *data)
++{
++ /* If we didn't request this extension, then the server may not echo it. */
++ if (!ss->opt.enableOCSPStapling)
++ return SECFailure;
++
++ /* The echoed extension must be empty. */
++ if (data->len != 0)
++ return SECFailure;
++
++ ss->ssl3.hs.may_get_cert_status = PR_TRUE;
++
++ /* Keep track of negotiated extensions. */
++ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
++
++ return SECSuccess;
++}
++
++/* ssl3_ClientSendStatusRequestXtn builds the status_request extension on the
++ * client side. See RFC 4366 section 3.6. */
++PRInt32
++ssl3_ClientSendStatusRequestXtn(sslSocket * ss, PRBool append,
++ PRUint32 maxBytes)
++{
++ PRInt32 extension_length;
++
++ if (!ss->opt.enableOCSPStapling)
++ return 0;
++
++ /* extension_type (2-bytes) +
++ * length(extension_data) (2-bytes) +
++ * status_type (1) +
++ * responder_id_list length (2) +
++ * request_extensions length (2)
++ */
++ extension_length = 9;
++
++ if (append && maxBytes >= extension_length) {
++ SECStatus rv;
++ TLSExtensionData *xtnData;
++
++ /* extension_type */
++ rv = ssl3_AppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
++ if (rv != SECSuccess)
++ return -1;
++ rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
++ if (rv != SECSuccess)
++ return -1;
++ rv = ssl3_AppendHandshakeNumber(ss, 1 /* status_type ocsp */, 1);
++ if (rv != SECSuccess)
++ return -1;
++ /* A zero length responder_id_list means that the responders are
++ * implicitly known to the server. */
++ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
++ if (rv != SECSuccess)
++ return -1;
++ /* A zero length request_extensions means that there are no extensions.
++ * Specifically, we don't set the id-pkix-ocsp-nonce extension. This
++ * means that the server can replay a cached OCSP response to us. */
++ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
++ if (rv != SECSuccess)
++ return -1;
++
++ xtnData = &ss->xtnData;
++ xtnData->advertised[xtnData->numAdvertised++] = ssl_cert_status_xtn;
++ } else if (maxBytes < extension_length) {
++ PORT_Assert(0);
++ return 0;
++ }
++ return extension_length;
++}
++
+ /*
+ * NewSessionTicket
+ * Called from ssl3_HandleFinished
+diff --git a/net/third_party/nss/ssl/ssl3prot.h b/net/third_party/nss/ssl/ssl3prot.h
+index f3c950e..aeaacdd 100644
+--- a/net/third_party/nss/ssl/ssl3prot.h
++++ b/net/third_party/nss/ssl/ssl3prot.h
+@@ -158,6 +158,7 @@ typedef enum {
+ certificate_verify = 15,
+ client_key_exchange = 16,
+ finished = 20,
++ certificate_status = 22,
+ next_proto = 67
+ } SSL3HandshakeType;
+
+diff --git a/net/third_party/nss/ssl/sslerr.h b/net/third_party/nss/ssl/sslerr.h
+index bd72f97..eb56ea9 100644
+--- a/net/third_party/nss/ssl/sslerr.h
++++ b/net/third_party/nss/ssl/sslerr.h
+@@ -203,6 +203,8 @@ SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD = (SSL_ERROR_BASE + 114),
+
+ SSL_ERROR_WEAK_SERVER_KEY = (SSL_ERROR_BASE + 115),
+
++SSL_ERROR_RX_UNEXPECTED_CERT_STATUS = (SSL_ERROR_BASE + 116),
++
+ SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
+ } SSLErrorCodes;
+ #endif /* NO_SECURITY_ERROR_ENUM */
+diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h
+index b84511b..c656f65 100644
+--- a/net/third_party/nss/ssl/sslimpl.h
++++ b/net/third_party/nss/ssl/sslimpl.h
+@@ -350,6 +350,7 @@ typedef struct sslOptionsStr {
+ unsigned int requireSafeNegotiation : 1; /* 22 */
+ unsigned int enableFalseStart : 1; /* 23 */
+ unsigned int enableSnapStart : 1; /* 24 */
++ unsigned int enableOCSPStapling : 1; /* 25 */
+ } sslOptions;
+
+ typedef enum { sslHandshakingUndetermined = 0,
+@@ -820,6 +821,14 @@ const ssl3CipherSuiteDef *suite_def;
+ * when this one finishes */
+ PRBool usedStepDownKey; /* we did a server key exchange. */
+ PRBool sendingSCSV; /* instead of empty RI */
++ PRBool may_get_cert_status; /* the server echoed a
++ * status_request extension so
++ * may send a CertificateStatus
++ * handshake message. */
++ SECItem pending_cert_msg; /* a Certificate message which we
++ * save temporarily if we may get
++ * a CertificateStatus message */
++ SECItem cert_status; /* an OCSP response */
+ sslBuffer msgState; /* current state for handshake messages*/
+ /* protected by recvBufLock */
+ sslBuffer messages; /* Accumulated handshake messages */
+@@ -1620,6 +1629,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_ClientHandleStatusRequestXtn(sslSocket *ss,
++ PRUint16 ex_type, SECItem *data);
+ extern SECStatus ssl3_ServerHandleSessionTicketXtn(sslSocket *ss,
+ PRUint16 ex_type, SECItem *data);
+ extern SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss,
+@@ -1631,6 +1642,8 @@ extern SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss,
+ */
+ extern PRInt32 ssl3_SendSessionTicketXtn(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
++extern PRInt32 ssl3_ClientSendStatusRequestXtn(sslSocket *ss, PRBool append,
++ PRUint32 maxBytes);
+
+ /* ClientHello and ServerHello extension senders.
+ * The code is in ssl3ext.c.
+diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c
+index 33e7f3e..b14a935 100644
+--- a/net/third_party/nss/ssl/sslsock.c
++++ b/net/third_party/nss/ssl/sslsock.c
+@@ -185,6 +185,7 @@ static sslOptions ssl_defaults = {
+ 2, /* enableRenegotiation (default: requires extension) */
+ PR_FALSE, /* requireSafeNegotiation */
+ PR_FALSE, /* enableFalseStart */
++ PR_FALSE, /* enableOCSPStapling */
+ };
+
+ sslSessionIDLookupFunc ssl_sid_lookup;
+@@ -746,6 +747,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on)
+ ss->opt.enableSnapStart = on;
+ break;
+
++ case SSL_ENABLE_OCSP_STAPLING:
++ ss->opt.enableOCSPStapling = on;
++ break;
++
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+@@ -811,6 +816,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_SNAP_START: on = ss->opt.enableSnapStart; break;
++ case SSL_ENABLE_OCSP_STAPLING: on = ss->opt.enableOCSPStapling; break;
+
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+@@ -863,6 +869,9 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn)
+ break;
+ case SSL_ENABLE_FALSE_START: on = ssl_defaults.enableFalseStart; break;
+ case SSL_ENABLE_SNAP_START: on = ssl_defaults.enableSnapStart; break;
++ case SSL_ENABLE_OCSP_STAPLING:
++ on = ssl_defaults.enableOCSPStapling;
++ break;
+
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+@@ -1014,6 +1023,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on)
+ ssl_defaults.enableSnapStart = on;
+ break;
+
++ case SSL_ENABLE_OCSP_STAPLING:
++ ssl_defaults.enableOCSPStapling = on;
++ break;
++
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+@@ -1473,6 +1486,36 @@ loser:
+ #endif
+ }
+
++SECStatus
++SSL_GetStapledOCSPResponse(PRFileDesc *fd, unsigned char *out_data,
++ unsigned int *len) {
++ sslSocket *ss = ssl_FindSocket(fd);
++
++ if (!ss) {
++ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetStapledOCSPResponse",
++ SSL_GETPID(), fd));
++ return SECFailure;
++ }
++
++ ssl_Get1stHandshakeLock(ss);
++ ssl_GetSSL3HandshakeLock(ss);
++
++ if (ss->ssl3.hs.cert_status.data) {
++ unsigned int todo = ss->ssl3.hs.cert_status.len;
++ if (todo > *len)
++ todo = *len;
++ *len = ss->ssl3.hs.cert_status.len;
++ PORT_Memcpy(out_data, ss->ssl3.hs.cert_status.data, todo);
++ } else {
++ *len = 0;
++ }
++
++ ssl_ReleaseSSL3HandshakeLock(ss);
++ ssl_Release1stHandshakeLock(ss);
++
++ return SECSuccess;
++}
++
+ /************************************************************************/
+ /* The following functions are the TOP LEVEL SSL functions.
+ ** They all get called through the NSPRIOMethods table below.
+diff --git a/net/third_party/nss/ssl/sslt.h b/net/third_party/nss/ssl/sslt.h
+index 68cbf87..3fa3f9b 100644
+--- a/net/third_party/nss/ssl/sslt.h
++++ b/net/third_party/nss/ssl/sslt.h
+@@ -198,6 +198,7 @@ typedef enum {
+ /* Update SSL_MAX_EXTENSIONS whenever a new extension type is added. */
+ typedef enum {
+ ssl_server_name_xtn = 0,
++ ssl_cert_status_xtn = 5,
+ #ifdef NSS_ENABLE_ECC
+ ssl_elliptic_curves_xtn = 10,
+ ssl_ec_point_formats_xtn = 11,
+@@ -208,7 +209,7 @@ typedef enum {
+ ssl_renegotiation_info_xtn = 0xff01 /* experimental number */
+ } SSLExtensionType;
+
+-#define SSL_MAX_EXTENSIONS 7
++#define SSL_MAX_EXTENSIONS 8
+
+ typedef enum {
+ /* No Snap Start handshake was attempted. */
diff --git a/net/third_party/nss/ssl/ssl.def b/net/third_party/nss/ssl/ssl.def
index 60ebbb1..76417d0 100644
--- a/net/third_party/nss/ssl/ssl.def
+++ b/net/third_party/nss/ssl/ssl.def
@@ -163,6 +163,7 @@ SSL_SetNextProtoNego;
;+ global:
SSL_GetPredictedServerHelloData;
SSL_GetSnapStartResult;
+SSL_GetStapledOCSPResponse;
SSL_PeerCertificateChain;
SSL_SetPredictedPeerCertificates;
SSL_SetPredictedServerHelloData;
diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h
index 9d3da0c..3515007 100644
--- a/net/third_party/nss/ssl/ssl.h
+++ b/net/third_party/nss/ssl/ssl.h
@@ -148,6 +148,7 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd);
/* previous connection to the same server is required. See */
/* SSL_GetPredictedServerHelloData, SSL_SetPredictedPeerCertificates and */
/* SSL_SetSnapStartApplicationData. */
+#define SSL_ENABLE_OCSP_STAPLING 24 /* Request OCSP stapling (client) */
#ifdef SSL_DEPRECATED_FUNCTION
/* Old deprecated function names */
@@ -283,6 +284,23 @@ SSL_IMPORT CERTCertificate *SSL_PeerCertificate(PRFileDesc *fd);
SSL_IMPORT SECStatus SSL_PeerCertificateChain(
PRFileDesc *fd, CERTCertificate **certs, unsigned int *certs_size);
+/* 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
+ * of the OCSP stapled response. If the stapled response is too large to fit in
+ * |out_data| then it will be truncated. If no OCSP response was given by the
+ * server then it has zero length.
+ *
+ * You must set the SSL_ENABLE_OCSP_STAPLING option in order for OCSP responses
+ * to be provided by a server.
+ *
+ * You can call this function during the certificate verification callback or
+ * any time afterwards.
+ */
+SSL_IMPORT SECStatus SSL_GetStapledOCSPResponse(PRFileDesc *fd,
+ unsigned char *out_data,
+ unsigned int *len);
+
/*
** Authenticate certificate hook. Called when a certificate comes in
** (because of SSL_REQUIRE_CERTIFICATE in SSL_Enable) to authenticate the
diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c
index c5ea79f..d56bb97 100644
--- a/net/third_party/nss/ssl/ssl3con.c
+++ b/net/third_party/nss/ssl/ssl3con.c
@@ -7945,6 +7945,57 @@ ssl3_CopyPeerCertsToSID(ssl3CertNode *certs, sslSessionID *sid)
}
/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
+ * ssl3 CertificateStatus message.
+ * Caller must hold Handshake and RecvBuf locks.
+ * This is always called before ssl3_HandleCertificate, even if the Certificate
+ * message is sent first.
+ */
+static SECStatus
+ssl3_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+ PRInt32 status, len;
+ int errCode;
+ SSL3AlertDescription desc;
+
+ if (!ss->ssl3.hs.may_get_cert_status ||
+ ss->ssl3.hs.ws != wait_server_cert ||
+ !ss->ssl3.hs.pending_cert_msg.data ||
+ ss->ssl3.hs.cert_status.data) {
+ errCode = SSL_ERROR_RX_UNEXPECTED_CERT_STATUS;
+ desc = unexpected_message;
+ goto alert_loser;
+ }
+
+ /* Consume the CertificateStatusType enum */
+ status = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length);
+ if (status != 1 /* ocsp */) {
+ goto format_loser;
+ }
+
+ len = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);
+ if (len != length) {
+ goto format_loser;
+ }
+
+ if (SECITEM_AllocItem(NULL, &ss->ssl3.hs.cert_status, length) == NULL) {
+ return SECFailure;
+ }
+ ss->ssl3.hs.cert_status.type = siBuffer;
+ PORT_Memcpy(ss->ssl3.hs.cert_status.data, b, length);
+
+ return SECSuccess;
+
+format_loser:
+ errCode = SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT;
+ desc = bad_certificate_status_response;
+
+alert_loser:
+ (void)SSL3_SendAlert(ss, alert_fatal, desc);
+ (void)ssl_MapLowLevelError(errCode);
+ return SECFailure;
+}
+
+/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
* ssl3 Certificate message.
* Caller must hold Handshake and RecvBuf locks.
*/
@@ -8773,6 +8824,26 @@ xmit_loser:
return SECSuccess;
}
+/* This function handles any pending Certificate messages. Certificate messages
+ * can be pending if we expect a possible CertificateStatus message to follow.
+ *
+ * This function must be called immediately after handling the
+ * CertificateStatus message, and before handling any ServerKeyExchange or
+ * CertificateRequest messages.
+ */
+static SECStatus
+ssl3_MaybeHandlePendingCertificateMessage(sslSocket *ss)
+{
+ SECStatus rv = SECSuccess;
+
+ if (ss->ssl3.hs.pending_cert_msg.data) {
+ rv = ssl3_HandleCertificate(ss, ss->ssl3.hs.pending_cert_msg.data,
+ ss->ssl3.hs.pending_cert_msg.len);
+ SECITEM_FreeItem(&ss->ssl3.hs.pending_cert_msg, PR_FALSE);
+ }
+ return rv;
+}
+
/* Called from ssl3_HandleHandshake() when it has gathered a complete ssl3
* hanshake message.
* Caller must hold Handshake and RecvBuf locks.
@@ -8872,14 +8943,42 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
rv = ssl3_HandleServerHello(ss, b, length);
break;
case certificate:
+ if (ss->ssl3.hs.may_get_cert_status) {
+ /* If we might get a CertificateStatus then we want to postpone the
+ * processing of the Certificate message until after we have
+ * processed the CertificateStatus */
+ if (ss->ssl3.hs.pending_cert_msg.data ||
+ ss->ssl3.hs.ws != wait_server_cert) {
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ (void)ssl_MapLowLevelError(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE);
+ return SECFailure;
+ }
+ if (SECITEM_AllocItem(NULL, &ss->ssl3.hs.pending_cert_msg,
+ length) == NULL) {
+ return SECFailure;
+ }
+ ss->ssl3.hs.pending_cert_msg.type = siBuffer;
+ PORT_Memcpy(ss->ssl3.hs.pending_cert_msg.data, b, length);
+ break;
+ }
rv = ssl3_HandleCertificate(ss, b, length);
break;
+ case certificate_status:
+ rv = ssl3_HandleCertificateStatus(ss, b, length);
+ if (rv != SECSuccess)
+ break;
+ PORT_Assert(ss->ssl3.hs.pending_cert_msg.data);
+ rv = ssl3_MaybeHandlePendingCertificateMessage(ss);
+ break;
case server_key_exchange:
if (ss->sec.isServer) {
(void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
return SECFailure;
}
+ rv = ssl3_MaybeHandlePendingCertificateMessage(ss);
+ if (rv != SECSuccess)
+ break;
rv = ssl3_HandleServerKeyExchange(ss, b, length);
break;
case certificate_request:
@@ -8888,6 +8987,9 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST);
return SECFailure;
}
+ rv = ssl3_MaybeHandlePendingCertificateMessage(ss);
+ if (rv != SECSuccess)
+ break;
rv = ssl3_HandleCertificateRequest(ss, b, length);
break;
case server_hello_done:
@@ -8901,6 +9003,9 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
return SECFailure;
}
+ rv = ssl3_MaybeHandlePendingCertificateMessage(ss);
+ if (rv != SECSuccess)
+ break;
rv = ssl3_HandleServerHelloDone(ss);
break;
case certificate_verify:
@@ -9767,6 +9872,12 @@ ssl3_DestroySSL3Info(sslSocket *ss)
if (ss->ssl3.hs.origClientHello.data) {
SECITEM_FreeItem(&ss->ssl3.hs.origClientHello, PR_FALSE);
}
+ if (ss->ssl3.hs.pending_cert_msg.data) {
+ SECITEM_FreeItem(&ss->ssl3.hs.pending_cert_msg, PR_FALSE);
+ }
+ if (ss->ssl3.hs.cert_status.data) {
+ SECITEM_FreeItem(&ss->ssl3.hs.cert_status, PR_FALSE);
+ }
/* free the SSL3Buffer (msg_body) */
PORT_Free(ss->ssl3.hs.msg_body.buf);
diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c
index f044e1c..b93671e 100644
--- a/net/third_party/nss/ssl/ssl3ext.c
+++ b/net/third_party/nss/ssl/ssl3ext.c
@@ -247,6 +247,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_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
{ ssl_snap_start_xtn, &ssl3_ClientHandleSnapStartXtn },
{ -1, NULL }
};
@@ -272,6 +273,7 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = {
#endif
{ ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn },
{ ssl_next_proto_neg_xtn, &ssl3_ClientSendNextProtoNegoXtn },
+ { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
{ ssl_snap_start_xtn, &ssl3_SendSnapStartXtn }
/* NOTE: The Snap Start sender MUST be the last extension in the list. */
/* any extra entries will appear as { 0, NULL } */
@@ -659,6 +661,80 @@ ssl3_ClientSendNextProtoNegoXtn(sslSocket * ss,
return -1;
}
+SECStatus
+ssl3_ClientHandleStatusRequestXtn(sslSocket *ss, PRUint16 ex_type,
+ SECItem *data)
+{
+ /* If we didn't request this extension, then the server may not echo it. */
+ if (!ss->opt.enableOCSPStapling)
+ return SECFailure;
+
+ /* The echoed extension must be empty. */
+ if (data->len != 0)
+ return SECFailure;
+
+ ss->ssl3.hs.may_get_cert_status = PR_TRUE;
+
+ /* Keep track of negotiated extensions. */
+ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+
+ return SECSuccess;
+}
+
+/* ssl3_ClientSendStatusRequestXtn builds the status_request extension on the
+ * client side. See RFC 4366 section 3.6. */
+PRInt32
+ssl3_ClientSendStatusRequestXtn(sslSocket * ss, PRBool append,
+ PRUint32 maxBytes)
+{
+ PRInt32 extension_length;
+
+ if (!ss->opt.enableOCSPStapling)
+ return 0;
+
+ /* extension_type (2-bytes) +
+ * length(extension_data) (2-bytes) +
+ * status_type (1) +
+ * responder_id_list length (2) +
+ * request_extensions length (2)
+ */
+ extension_length = 9;
+
+ if (append && maxBytes >= extension_length) {
+ SECStatus rv;
+ TLSExtensionData *xtnData;
+
+ /* extension_type */
+ rv = ssl3_AppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
+ if (rv != SECSuccess)
+ return -1;
+ rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+ if (rv != SECSuccess)
+ return -1;
+ rv = ssl3_AppendHandshakeNumber(ss, 1 /* status_type ocsp */, 1);
+ if (rv != SECSuccess)
+ return -1;
+ /* A zero length responder_id_list means that the responders are
+ * implicitly known to the server. */
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+ if (rv != SECSuccess)
+ return -1;
+ /* A zero length request_extensions means that there are no extensions.
+ * Specifically, we don't set the id-pkix-ocsp-nonce extension. This
+ * means that the server can replay a cached OCSP response to us. */
+ rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+ if (rv != SECSuccess)
+ return -1;
+
+ xtnData = &ss->xtnData;
+ xtnData->advertised[xtnData->numAdvertised++] = ssl_cert_status_xtn;
+ } else if (maxBytes < extension_length) {
+ PORT_Assert(0);
+ return 0;
+ }
+ return extension_length;
+}
+
/*
* NewSessionTicket
* Called from ssl3_HandleFinished
diff --git a/net/third_party/nss/ssl/ssl3prot.h b/net/third_party/nss/ssl/ssl3prot.h
index f3c950e..aeaacdd 100644
--- a/net/third_party/nss/ssl/ssl3prot.h
+++ b/net/third_party/nss/ssl/ssl3prot.h
@@ -158,6 +158,7 @@ typedef enum {
certificate_verify = 15,
client_key_exchange = 16,
finished = 20,
+ certificate_status = 22,
next_proto = 67
} SSL3HandshakeType;
diff --git a/net/third_party/nss/ssl/sslerr.h b/net/third_party/nss/ssl/sslerr.h
index bd72f97..eb56ea9 100644
--- a/net/third_party/nss/ssl/sslerr.h
+++ b/net/third_party/nss/ssl/sslerr.h
@@ -203,6 +203,8 @@ SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD = (SSL_ERROR_BASE + 114),
SSL_ERROR_WEAK_SERVER_KEY = (SSL_ERROR_BASE + 115),
+SSL_ERROR_RX_UNEXPECTED_CERT_STATUS = (SSL_ERROR_BASE + 116),
+
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h
index b84511b..c656f65 100644
--- a/net/third_party/nss/ssl/sslimpl.h
+++ b/net/third_party/nss/ssl/sslimpl.h
@@ -350,6 +350,7 @@ typedef struct sslOptionsStr {
unsigned int requireSafeNegotiation : 1; /* 22 */
unsigned int enableFalseStart : 1; /* 23 */
unsigned int enableSnapStart : 1; /* 24 */
+ unsigned int enableOCSPStapling : 1; /* 25 */
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
@@ -820,6 +821,14 @@ const ssl3CipherSuiteDef *suite_def;
* when this one finishes */
PRBool usedStepDownKey; /* we did a server key exchange. */
PRBool sendingSCSV; /* instead of empty RI */
+ PRBool may_get_cert_status; /* the server echoed a
+ * status_request extension so
+ * may send a CertificateStatus
+ * handshake message. */
+ SECItem pending_cert_msg; /* a Certificate message which we
+ * save temporarily if we may get
+ * a CertificateStatus message */
+ SECItem cert_status; /* an OCSP response */
sslBuffer msgState; /* current state for handshake messages*/
/* protected by recvBufLock */
sslBuffer messages; /* Accumulated handshake messages */
@@ -1620,6 +1629,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_ClientHandleStatusRequestXtn(sslSocket *ss,
+ PRUint16 ex_type, SECItem *data);
extern SECStatus ssl3_ServerHandleSessionTicketXtn(sslSocket *ss,
PRUint16 ex_type, SECItem *data);
extern SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss,
@@ -1631,6 +1642,8 @@ extern SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss,
*/
extern PRInt32 ssl3_SendSessionTicketXtn(sslSocket *ss, PRBool append,
PRUint32 maxBytes);
+extern PRInt32 ssl3_ClientSendStatusRequestXtn(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
/* ClientHello and ServerHello extension senders.
* The code is in ssl3ext.c.
diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c
index 33e7f3e..b14a935 100644
--- a/net/third_party/nss/ssl/sslsock.c
+++ b/net/third_party/nss/ssl/sslsock.c
@@ -185,6 +185,7 @@ static sslOptions ssl_defaults = {
2, /* enableRenegotiation (default: requires extension) */
PR_FALSE, /* requireSafeNegotiation */
PR_FALSE, /* enableFalseStart */
+ PR_FALSE, /* enableOCSPStapling */
};
sslSessionIDLookupFunc ssl_sid_lookup;
@@ -746,6 +747,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on)
ss->opt.enableSnapStart = on;
break;
+ case SSL_ENABLE_OCSP_STAPLING:
+ ss->opt.enableOCSPStapling = on;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -811,6 +816,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_SNAP_START: on = ss->opt.enableSnapStart; break;
+ case SSL_ENABLE_OCSP_STAPLING: on = ss->opt.enableOCSPStapling; break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -863,6 +869,9 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn)
break;
case SSL_ENABLE_FALSE_START: on = ssl_defaults.enableFalseStart; break;
case SSL_ENABLE_SNAP_START: on = ssl_defaults.enableSnapStart; break;
+ case SSL_ENABLE_OCSP_STAPLING:
+ on = ssl_defaults.enableOCSPStapling;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -1014,6 +1023,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on)
ssl_defaults.enableSnapStart = on;
break;
+ case SSL_ENABLE_OCSP_STAPLING:
+ ssl_defaults.enableOCSPStapling = on;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
@@ -1473,6 +1486,36 @@ loser:
#endif
}
+SECStatus
+SSL_GetStapledOCSPResponse(PRFileDesc *fd, unsigned char *out_data,
+ unsigned int *len) {
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetStapledOCSPResponse",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ if (ss->ssl3.hs.cert_status.data) {
+ unsigned int todo = ss->ssl3.hs.cert_status.len;
+ if (todo > *len)
+ todo = *len;
+ *len = ss->ssl3.hs.cert_status.len;
+ PORT_Memcpy(out_data, ss->ssl3.hs.cert_status.data, todo);
+ } else {
+ *len = 0;
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return SECSuccess;
+}
+
/************************************************************************/
/* The following functions are the TOP LEVEL SSL functions.
** They all get called through the NSPRIOMethods table below.
diff --git a/net/third_party/nss/ssl/sslt.h b/net/third_party/nss/ssl/sslt.h
index 68cbf87..3fa3f9b 100644
--- a/net/third_party/nss/ssl/sslt.h
+++ b/net/third_party/nss/ssl/sslt.h
@@ -198,6 +198,7 @@ typedef enum {
/* Update SSL_MAX_EXTENSIONS whenever a new extension type is added. */
typedef enum {
ssl_server_name_xtn = 0,
+ ssl_cert_status_xtn = 5,
#ifdef NSS_ENABLE_ECC
ssl_elliptic_curves_xtn = 10,
ssl_ec_point_formats_xtn = 11,
@@ -208,7 +209,7 @@ typedef enum {
ssl_renegotiation_info_xtn = 0xff01 /* experimental number */
} SSLExtensionType;
-#define SSL_MAX_EXTENSIONS 7
+#define SSL_MAX_EXTENSIONS 8
typedef enum {
/* No Snap Start handshake was attempted. */