diff -pu -r a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c --- a/net/third_party/nss/ssl/ssl3con.c 2012-11-09 15:21:56.747322689 -0800 +++ b/net/third_party/nss/ssl/ssl3con.c 2012-11-09 15:28:27.933078020 -0800 @@ -8365,6 +8365,57 @@ ssl3_CopyPeerCertsToSID(ssl3CertNode *ce } /* 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. */ @@ -9248,6 +9299,26 @@ ssl3_FinishHandshake(sslSocket * ss) 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. @@ -9376,14 +9447,42 @@ ssl3_HandleHandshakeMessage(sslSocket *s rv = dtls_HandleHelloVerifyRequest(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: @@ -9392,6 +9491,9 @@ ssl3_HandleHandshakeMessage(sslSocket *s 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: @@ -9405,6 +9507,9 @@ ssl3_HandleHandshakeMessage(sslSocket *s 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: @@ -10369,6 +10474,12 @@ ssl3_DestroySSL3Info(sslSocket *ss) ss->ssl3.hs.messages.len = 0; ss->ssl3.hs.messages.space = 0; } + 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 -pu -r a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c --- a/net/third_party/nss/ssl/ssl3ext.c 2012-09-20 17:28:05.000000000 -0700 +++ b/net/third_party/nss/ssl/ssl3ext.c 2012-11-09 15:32:11.606363256 -0800 @@ -234,6 +234,7 @@ static const ssl3HelloExtensionHandler s { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, { ssl_next_proto_nego_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, { ssl_use_srtp_xtn, &ssl3_HandleUseSRTPXtn }, + { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn }, { -1, NULL } }; @@ -258,7 +259,8 @@ ssl3HelloExtensionSender clientHelloSend #endif { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn }, - { ssl_use_srtp_xtn, &ssl3_SendUseSRTPXtn } + { ssl_use_srtp_xtn, &ssl3_SendUseSRTPXtn }, + { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn } /* any extra entries will appear as { 0, NULL } */ }; @@ -640,6 +642,80 @@ loser: 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 -pu -r a/net/third_party/nss/ssl/ssl3prot.h b/net/third_party/nss/ssl/ssl3prot.h --- a/net/third_party/nss/ssl/ssl3prot.h 2012-04-25 07:50:12.000000000 -0700 +++ b/net/third_party/nss/ssl/ssl3prot.h 2012-11-09 15:28:27.933078020 -0800 @@ -129,6 +129,7 @@ typedef enum { certificate_verify = 15, client_key_exchange = 16, finished = 20, + certificate_status = 22, next_proto = 67 } SSL3HandshakeType; diff -pu -r a/net/third_party/nss/ssl/sslerr.h b/net/third_party/nss/ssl/sslerr.h --- a/net/third_party/nss/ssl/sslerr.h 2012-07-12 17:51:57.000000000 -0700 +++ b/net/third_party/nss/ssl/sslerr.h 2012-11-09 15:30:36.804971319 -0800 @@ -188,6 +188,8 @@ SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQ SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION = (SSL_ERROR_BASE + 124), +SSL_ERROR_RX_UNEXPECTED_CERT_STATUS = (SSL_ERROR_BASE + 125), + SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ } SSLErrorCodes; #endif /* NO_SECURITY_ERROR_ENUM */ diff -pu -r a/net/third_party/nss/ssl/SSLerrs.h b/net/third_party/nss/ssl/SSLerrs.h --- a/net/third_party/nss/ssl/SSLerrs.h 2012-07-12 17:51:57.000000000 -0700 +++ b/net/third_party/nss/ssl/SSLerrs.h 2012-11-09 15:30:19.924723400 -0800 @@ -400,3 +400,6 @@ ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION, (SSL_ERROR_BASE + 124), "SSL feature not supported for the protocol version.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERT_STATUS, (SSL_ERROR_BASE + 125), +"SSL received an unexpected Certificate Status handshake message.") diff -pu -r a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h --- a/net/third_party/nss/ssl/ssl.h 2012-11-09 15:27:15.952019947 -0800 +++ b/net/third_party/nss/ssl/ssl.h 2012-11-09 15:28:27.933078020 -0800 @@ -158,6 +158,7 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRF * accept fragmented alerts). */ #define SSL_CBC_RANDOM_IV 23 +#define SSL_ENABLE_OCSP_STAPLING 24 /* Request OCSP stapling (client) */ #ifdef SSL_DEPRECATED_FUNCTION /* Old deprecated function names */ @@ -409,6 +410,23 @@ SSL_IMPORT SECStatus SSL_PeerCertificate PRFileDesc *fd, CERTCertificate **certs, unsigned int *numCerts, unsigned int maxNumCerts); +/* 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 -pu -r a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h --- a/net/third_party/nss/ssl/sslimpl.h 2012-11-09 15:21:56.747322689 -0800 +++ b/net/third_party/nss/ssl/sslimpl.h 2012-11-09 15:28:27.943078167 -0800 @@ -316,6 +316,7 @@ typedef struct sslOptionsStr { unsigned int requireSafeNegotiation : 1; /* 22 */ unsigned int enableFalseStart : 1; /* 23 */ unsigned int cbcRandomIV : 1; /* 24 */ + unsigned int enableOCSPStapling : 1; /* 25 */ } sslOptions; typedef enum { sslHandshakingUndetermined = 0, @@ -795,6 +796,14 @@ const ssl3CipherSuiteDef *suite_def; PRBool isResuming; /* are we resuming a session */ 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 */ @@ -1625,6 +1634,8 @@ extern SECStatus ssl3_HandleSupportedPoi PRUint16 ex_type, SECItem *data); extern SECStatus ssl3_ClientHandleSessionTicketXtn(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); @@ -1634,6 +1645,8 @@ extern SECStatus ssl3_ServerHandleSessio */ 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 -pu -r a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c --- a/net/third_party/nss/ssl/sslsock.c 2012-11-09 15:17:00.432983977 -0800 +++ b/net/third_party/nss/ssl/sslsock.c 2012-11-09 15:28:27.943078167 -0800 @@ -153,7 +153,8 @@ static sslOptions ssl_defaults = { 2, /* enableRenegotiation (default: requires extension) */ PR_FALSE, /* requireSafeNegotiation */ PR_FALSE, /* enableFalseStart */ - PR_TRUE /* cbcRandomIV */ + PR_TRUE, /* cbcRandomIV */ + PR_FALSE, /* enableOCSPStapling */ }; /* @@ -827,6 +828,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 wh ss->opt.cbcRandomIV = on; break; + case SSL_ENABLE_OCSP_STAPLING: + ss->opt.enableOCSPStapling = on; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; @@ -896,6 +901,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 wh on = ss->opt.requireSafeNegotiation; break; case SSL_ENABLE_FALSE_START: on = ss->opt.enableFalseStart; break; case SSL_CBC_RANDOM_IV: on = ss->opt.cbcRandomIV; break; + case SSL_ENABLE_OCSP_STAPLING: on = ss->opt.enableOCSPStapling; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -954,6 +960,9 @@ SSL_OptionGetDefault(PRInt32 which, PRBo break; case SSL_ENABLE_FALSE_START: on = ssl_defaults.enableFalseStart; break; case SSL_CBC_RANDOM_IV: on = ssl_defaults.cbcRandomIV; break; + case SSL_ENABLE_OCSP_STAPLING: + on = ssl_defaults.enableOCSPStapling; + break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -1117,6 +1126,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBo ssl_defaults.cbcRandomIV = on; break; + case SSL_ENABLE_OCSP_STAPLING: + ssl_defaults.enableOCSPStapling = on; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; @@ -1859,6 +1872,36 @@ SSL_VersionRangeSet(PRFileDesc *fd, cons return SECSuccess; } +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 -pu -r a/net/third_party/nss/ssl/sslt.h b/net/third_party/nss/ssl/sslt.h --- a/net/third_party/nss/ssl/sslt.h 2012-06-06 19:06:19.000000000 -0700 +++ b/net/third_party/nss/ssl/sslt.h 2012-11-09 15:29:10.333701086 -0800 @@ -175,6 +175,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, @@ -185,6 +186,6 @@ typedef enum { ssl_renegotiation_info_xtn = 0xff01 /* experimental number */ } SSLExtensionType; -#define SSL_MAX_EXTENSIONS 7 +#define SSL_MAX_EXTENSIONS 8 #endif /* __sslt_h_ */