diff options
-rw-r--r-- | net/third_party/nss/README.chromium | 3 | ||||
-rw-r--r-- | net/third_party/nss/patches/ocspstapling.patch | 508 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl.def | 1 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl.h | 18 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3con.c | 111 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3ext.c | 76 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3prot.h | 1 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslerr.h | 2 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslimpl.h | 13 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslsock.c | 43 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslt.h | 3 |
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. */ |