blob: 0abbfe2b7e5b4ee9f51bc74452ad22b81c6ab524 [file] [log] [blame]
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_ */