diff options
author | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-10 20:32:50 +0000 |
---|---|---|
committer | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-10 20:32:50 +0000 |
commit | 815cdf2a322599b013051acf4fd890e9bc3e709a (patch) | |
tree | d8f58f713c124491bbda4894d0261fef64f3aed0 /net/third_party | |
parent | 6377a003e5948a14cf79bf6433e4c89dbc9354e0 (diff) | |
download | chromium_src-815cdf2a322599b013051acf4fd890e9bc3e709a.zip chromium_src-815cdf2a322599b013051acf4fd890e9bc3e709a.tar.gz chromium_src-815cdf2a322599b013051acf4fd890e9bc3e709a.tar.bz2 |
Add the encrypted client certificates TLS extension and enable it if
origin-bound certificates are enabled.
The patch was originally written by Adam Langley.
R=agl@chromium.org
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/8495003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@109493 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/third_party')
-rw-r--r-- | net/third_party/nss/README.chromium | 6 | ||||
-rwxr-xr-x | net/third_party/nss/patches/applypatches.sh | 2 | ||||
-rw-r--r-- | net/third_party/nss/patches/encryptedclientcerts.patch | 413 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl.h | 1 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3con.c | 123 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3ext.c | 66 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslimpl.h | 1 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslsock.c | 13 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslt.h | 3 |
9 files changed, 579 insertions, 49 deletions
diff --git a/net/third_party/nss/README.chromium b/net/third_party/nss/README.chromium index b81dd9e..4ab79e9 100644 --- a/net/third_party/nss/README.chromium +++ b/net/third_party/nss/README.chromium @@ -74,10 +74,14 @@ Patches: patches/restartclientauth.patch * Allow SSL_HandshakeNegotiatedExtension to be called before the handshake - is finished.. + is finished. https://bugzilla.mozilla.org/show_bug.cgi?id=681839 patches/negotiatedextension.patch + * Support the encrypted client certificates extension. + https://bugzilla.mozilla.org/show_bug.cgi?id=691991 + patches/encryptedclientcerts.patch + Apply the patches to NSS by running the patches/applypatches.sh script. Read the comments at the top of patches/applypatches.sh for instructions. diff --git a/net/third_party/nss/patches/applypatches.sh b/net/third_party/nss/patches/applypatches.sh index 207e396..1cdca865 100755 --- a/net/third_party/nss/patches/applypatches.sh +++ b/net/third_party/nss/patches/applypatches.sh @@ -38,3 +38,5 @@ patch -p6 < $patches_dir/handshakeshortwrite.patch patch -p6 < $patches_dir/restartclientauth.patch patch -p6 < $patches_dir/negotiatedextension.patch + +patch -p3 < $patches_dir/encryptedclientcerts.patch diff --git a/net/third_party/nss/patches/encryptedclientcerts.patch b/net/third_party/nss/patches/encryptedclientcerts.patch new file mode 100644 index 0000000..15a5e78 --- /dev/null +++ b/net/third_party/nss/patches/encryptedclientcerts.patch @@ -0,0 +1,413 @@ +Index: net/third_party/nss/ssl/ssl.h +=================================================================== +--- net/third_party/nss/ssl/ssl.h (revision 108962) ++++ net/third_party/nss/ssl/ssl.h (working copy) +@@ -143,6 +143,7 @@ + #define SSL_ENABLE_CACHED_INFO 24 /* Enable TLS cached information */ + /* extension, off by default. */ + #define SSL_ENABLE_OB_CERTS 25 /* Enable origin bound certs. */ ++#define SSL_ENCRYPT_CLIENT_CERTS 26 /* Enable encrypted client certs. */ + + #ifdef SSL_DEPRECATED_FUNCTION + /* Old deprecated function names */ +Index: net/third_party/nss/ssl/sslimpl.h +=================================================================== +--- net/third_party/nss/ssl/sslimpl.h (revision 108962) ++++ net/third_party/nss/ssl/sslimpl.h (working copy) +@@ -350,6 +350,7 @@ + unsigned int enableOCSPStapling : 1; /* 24 */ + unsigned int enableCachedInfo : 1; /* 25 */ + unsigned int enableOBCerts : 1; /* 26 */ ++ unsigned int encryptClientCerts : 1; /* 27 */ + } sslOptions; + + typedef enum { sslHandshakingUndetermined = 0, +Index: net/third_party/nss/ssl/ssl3ext.c +=================================================================== +--- net/third_party/nss/ssl/ssl3ext.c (revision 108962) ++++ net/third_party/nss/ssl/ssl3ext.c (working copy) +@@ -78,6 +78,12 @@ + PRBool append, PRUint32 maxBytes); + static SECStatus ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, + PRUint16 ex_type, SECItem *data); ++static SECStatus ssl3_ServerHandleEncryptedClientCertsXtn(sslSocket *ss, ++ PRUint16 ex_type, SECItem *data); ++static SECStatus ssl3_ClientHandleEncryptedClientCertsXtn(sslSocket *ss, ++ PRUint16 ex_type, SECItem *data); ++static PRInt32 ssl3_SendEncryptedClientCertsXtn(sslSocket *ss, ++ PRBool append, PRUint32 maxBytes); + + /* + * Write bytes. Using this function means the SECItem structure +@@ -234,6 +240,7 @@ + { ssl_ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn }, + #endif + { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn }, ++ { ssl_encrypted_client_certs, &ssl3_ServerHandleEncryptedClientCertsXtn }, + { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, + { ssl_next_proto_neg_xtn, &ssl3_ServerHandleNextProtoNegoXtn }, + { ssl_cached_info_xtn, &ssl3_ServerHandleCachedInfoXtn }, +@@ -247,6 +254,7 @@ + { ssl_server_name_xtn, &ssl3_HandleServerNameXtn }, + /* TODO: add a handler for ssl_ec_point_formats_xtn */ + { ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn }, ++ { ssl_encrypted_client_certs, &ssl3_ClientHandleEncryptedClientCertsXtn }, + { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, + { ssl_next_proto_neg_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, + { ssl_cached_info_xtn, &ssl3_ClientHandleCachedInfoXtn }, +@@ -275,6 +283,7 @@ + { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn }, + #endif + { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, ++ { ssl_encrypted_client_certs, &ssl3_SendEncryptedClientCertsXtn }, + { ssl_next_proto_neg_xtn, &ssl3_ClientSendNextProtoNegoXtn }, + { ssl_cached_info_xtn, &ssl3_ClientSendCachedInfoXtn }, + { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn }, +@@ -1318,6 +1327,18 @@ + return SECSuccess; + } + ++static SECStatus ++ssl3_ClientHandleEncryptedClientCertsXtn(sslSocket *ss, PRUint16 ex_type, ++ SECItem *data) ++{ ++ if (data->len != 0) ++ return SECFailure; ++ ++ /* Keep track of negotiated extensions. */ ++ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; ++ return SECSuccess; ++} ++ + SECStatus + ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, + SECItem *data) +@@ -1728,6 +1749,24 @@ + return rv; + } + ++static SECStatus ++ssl3_ServerHandleEncryptedClientCertsXtn(sslSocket *ss, PRUint16 ex_type, ++ SECItem *data) ++{ ++ SECStatus rv = SECSuccess; ++ ++ if (data->len != 0) ++ return SECFailure; ++ ++ if (ss->opt.encryptClientCerts) { ++ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; ++ rv = ssl3_RegisterServerHelloExtensionSender( ++ ss, ex_type, ssl3_SendEncryptedClientCertsXtn); ++ } ++ ++ return rv; ++} ++ + /* + * Read bytes. Using this function means the SECItem structure + * cannot be freed. The caller is expected to call this function +@@ -1927,6 +1966,33 @@ + return needed; + } + ++static PRInt32 ++ssl3_SendEncryptedClientCertsXtn( ++ sslSocket * ss, ++ PRBool append, ++ PRUint32 maxBytes) ++{ ++ PRInt32 needed; ++ ++ if (!ss->opt.encryptClientCerts) ++ return 0; ++ ++ needed = 4; /* two bytes of type and two of length. */ ++ if (append && maxBytes >= needed) { ++ SECStatus rv; ++ rv = ssl3_AppendHandshakeNumber(ss, ssl_encrypted_client_certs, 2); ++ if (rv != SECSuccess) ++ return -1; ++ rv = ssl3_AppendHandshakeNumber(ss, 0 /* length */, 2); ++ if (rv != SECSuccess) ++ return -1; ++ ss->xtnData.advertised[ss->xtnData.numAdvertised++] = ++ ssl_encrypted_client_certs; ++ } ++ ++ return needed; ++} ++ + /* This function runs in both the client and server. */ + static SECStatus + ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) +Index: net/third_party/nss/ssl/sslsock.c +=================================================================== +--- net/third_party/nss/ssl/sslsock.c (revision 108962) ++++ net/third_party/nss/ssl/sslsock.c (working copy) +@@ -188,6 +188,7 @@ + PR_FALSE, /* enableOCSPStapling */ + PR_FALSE, /* enableCachedInfo */ + PR_FALSE, /* enableOBCerts */ ++ PR_FALSE, /* encryptClientCerts */ + }; + + sslSessionIDLookupFunc ssl_sid_lookup; +@@ -757,6 +758,10 @@ + ss->opt.enableOBCerts = on; + break; + ++ case SSL_ENCRYPT_CLIENT_CERTS: ++ ss->opt.encryptClientCerts = on; ++ break; ++ + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); + rv = SECFailure; +@@ -824,6 +829,8 @@ + case SSL_ENABLE_OCSP_STAPLING: on = ss->opt.enableOCSPStapling; break; + case SSL_ENABLE_CACHED_INFO: on = ss->opt.enableCachedInfo; break; + case SSL_ENABLE_OB_CERTS: on = ss->opt.enableOBCerts; break; ++ case SSL_ENCRYPT_CLIENT_CERTS: ++ on = ss->opt.encryptClientCerts; break; + + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); +@@ -880,6 +887,8 @@ + break; + case SSL_ENABLE_CACHED_INFO: on = ssl_defaults.enableCachedInfo; break; + case SSL_ENABLE_OB_CERTS: on = ssl_defaults.enableOBCerts; break; ++ case SSL_ENCRYPT_CLIENT_CERTS: ++ on = ssl_defaults.encryptClientCerts; break; + + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); +@@ -1039,6 +1048,10 @@ + ssl_defaults.enableOBCerts = on; + break; + ++ case SSL_ENCRYPT_CLIENT_CERTS: ++ ssl_defaults.encryptClientCerts = on; ++ break; ++ + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; +Index: net/third_party/nss/ssl/ssl3con.c +=================================================================== +--- net/third_party/nss/ssl/ssl3con.c (revision 108962) ++++ net/third_party/nss/ssl/ssl3con.c (working copy) +@@ -2835,8 +2835,15 @@ + + ss->ssl3.prSpec = ss->ssl3.crSpec; + ss->ssl3.crSpec = prSpec; +- ss->ssl3.hs.ws = wait_finished; + ++ if (ss->sec.isServer && ++ ss->opt.requestCertificate && ++ ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { ++ ss->ssl3.hs.ws = wait_client_cert; ++ } else { ++ ss->ssl3.hs.ws = wait_finished; ++ } ++ + SSL_TRC(3, ("%d: SSL3[%d] Set Current Read Cipher Suite to Pending", + SSL_GETPID(), ss->fd )); + +@@ -4850,10 +4857,11 @@ + static SECStatus + ssl3_SendCertificateVerify(sslSocket *ss) + { +- SECStatus rv = SECFailure; +- PRBool isTLS; +- SECItem buf = {siBuffer, NULL, 0}; +- SSL3Hashes hashes; ++ SECStatus rv = SECFailure; ++ PRBool isTLS; ++ SECItem buf = {siBuffer, NULL, 0}; ++ SSL3Hashes hashes; ++ ssl3CipherSpec *spec; + + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); +@@ -4862,13 +4870,17 @@ + SSL_GETPID(), ss->fd)); + + ssl_GetSpecReadLock(ss); +- rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0); ++ spec = ss->ssl3.pwSpec; ++ if (ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { ++ spec = ss->ssl3.cwSpec; ++ } ++ rv = ssl3_ComputeHandshakeHashes(ss, spec, &hashes, 0); + ssl_ReleaseSpecReadLock(ss); + if (rv != SECSuccess) { + goto done; /* err code was set by ssl3_ComputeHandshakeHashes */ + } + +- isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); ++ isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0); + if (ss->ssl3.platformClientKey) { + #ifdef NSS_PLATFORM_CLIENT_AUTH + rv = ssl3_PlatformSignHashes(&hashes, ss->ssl3.platformClientKey, +@@ -5840,7 +5852,10 @@ + { + SECStatus rv; + SSL3WaitState ws = ss->ssl3.hs.ws; +- PRBool send_verify = PR_FALSE; ++ PRBool sendEmptyCert, sendCert; ++ int n = 0, i; ++ typedef SECStatus (*SendFunction)(sslSocket*); ++ SendFunction send_funcs[5]; + + SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello_done handshake", + SSL_GETPID(), ss->fd)); +@@ -5858,46 +5873,45 @@ + + ssl_GetXmitBufLock(ss); /*******************************/ + +- if (ss->ssl3.sendEmptyCert) { +- ss->ssl3.sendEmptyCert = PR_FALSE; +- rv = ssl3_SendEmptyCertificate(ss); +- /* Don't send verify */ +- if (rv != SECSuccess) { +- goto loser; /* error code is set. */ +- } +- } else if (ss->ssl3.clientCertChain != NULL && +- ss->ssl3.platformClientKey) { +-#ifdef NSS_PLATFORM_CLIENT_AUTH +- send_verify = PR_TRUE; +- rv = ssl3_SendCertificate(ss); +- if (rv != SECSuccess) { +- goto loser; /* error code is set. */ +- } +-#endif /* NSS_PLATFORM_CLIENT_AUTH */ +- } else if (ss->ssl3.clientCertChain != NULL && +- ss->ssl3.clientPrivateKey != NULL) { +- send_verify = PR_TRUE; +- rv = ssl3_SendCertificate(ss); +- if (rv != SECSuccess) { +- goto loser; /* error code is set. */ +- } +- } ++ sendEmptyCert = ss->ssl3.sendEmptyCert; ++ ss->ssl3.sendEmptyCert = PR_FALSE; ++ sendCert = !sendEmptyCert && ++ ss->ssl3.clientCertChain != NULL && ++ (ss->ssl3.platformClientKey || ++ ss->ssl3.clientPrivateKey != NULL); + +- rv = ssl3_SendClientKeyExchange(ss); +- if (rv != SECSuccess) { +- goto loser; /* err is set. */ ++ if (ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { ++ send_funcs[n++] = ssl3_SendClientKeyExchange; ++ send_funcs[n++] = ssl3_SendChangeCipherSpecs; ++ if (sendEmptyCert) { ++ send_funcs[n++] = ssl3_SendEmptyCertificate; ++ } ++ if (sendCert) { ++ send_funcs[n++] = ssl3_SendCertificate; ++ send_funcs[n++] = ssl3_SendCertificateVerify; ++ } ++ } else { ++ if (sendEmptyCert) { ++ send_funcs[n++] = ssl3_SendEmptyCertificate; ++ } ++ if (sendCert) { ++ send_funcs[n++] = ssl3_SendCertificate; ++ } ++ send_funcs[n++] = ssl3_SendClientKeyExchange; ++ if (sendCert) { ++ send_funcs[n++] = ssl3_SendCertificateVerify; ++ } ++ send_funcs[n++] = ssl3_SendChangeCipherSpecs; + } + +- if (send_verify) { +- rv = ssl3_SendCertificateVerify(ss); ++ PORT_Assert(n <= sizeof(send_funcs)/sizeof(send_funcs[0])); ++ ++ for (i = 0; i < n; i++) { ++ rv = send_funcs[i](ss); + if (rv != SECSuccess) { +- goto loser; /* err is set. */ +- } ++ goto loser; /* err code was set. */ ++ } + } +- rv = ssl3_SendChangeCipherSpecs(ss); +- if (rv != SECSuccess) { +- goto loser; /* err code was set. */ +- } + + /* We don't send NPN in a renegotiation as it's explicitly disallowed by + * the spec. */ +@@ -6110,8 +6124,13 @@ + return rv; /* err code is set. */ + } + +- ss->ssl3.hs.ws = (ss->opt.requestCertificate) ? wait_client_cert +- : wait_client_key; ++ if (ss->opt.requestCertificate && ++ !ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { ++ ss->ssl3.hs.ws = wait_client_cert; ++ } else { ++ ss->ssl3.hs.ws = wait_client_key; ++ } ++ + return SECSuccess; + } + +@@ -7355,7 +7374,11 @@ + desc = isTLS ? decode_error : illegal_parameter; + goto alert_loser; /* malformed */ + } +- ss->ssl3.hs.ws = wait_change_cipher; ++ if (ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { ++ ss->ssl3.hs.ws = wait_finished; ++ } else { ++ ss->ssl3.hs.ws = wait_change_cipher; ++ } + return SECSuccess; + + alert_loser: +@@ -8348,7 +8371,11 @@ + + cert_block: + if (ss->sec.isServer) { +- ss->ssl3.hs.ws = wait_client_key; ++ if (ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { ++ ss->ssl3.hs.ws = wait_cert_verify; ++ } else { ++ ss->ssl3.hs.ws = wait_client_key; ++ } + } else { + ss->ssl3.hs.ws = wait_cert_request; /* disallow server_key_exchange */ + if (ss->ssl3.hs.kea_def->is_limited || +@@ -8978,6 +9005,8 @@ + if (type == finished) { + sender = ss->sec.isServer ? sender_client : sender_server; + rSpec = ss->ssl3.crSpec; ++ } else if (ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { ++ rSpec = ss->ssl3.crSpec; + } + rv = ssl3_ComputeHandshakeHashes(ss, rSpec, &hashes, sender); + } +Index: net/third_party/nss/ssl/sslt.h +=================================================================== +--- net/third_party/nss/ssl/sslt.h (revision 108962) ++++ net/third_party/nss/ssl/sslt.h (working copy) +@@ -206,10 +206,11 @@ + ssl_session_ticket_xtn = 35, + ssl_next_proto_neg_xtn = 13172, + ssl_cached_info_xtn = 13173, ++ ssl_encrypted_client_certs = 13180, /* not IANA assigned. */ + ssl_renegotiation_info_xtn = 0xff01, /* experimental number */ + ssl_ob_cert_xtn = 13175 /* experimental number */ + } SSLExtensionType; + +-#define SSL_MAX_EXTENSIONS 9 ++#define SSL_MAX_EXTENSIONS 10 + + #endif /* __sslt_h_ */ diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h index 864226a..18193e2 100644 --- a/net/third_party/nss/ssl/ssl.h +++ b/net/third_party/nss/ssl/ssl.h @@ -143,6 +143,7 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd); #define SSL_ENABLE_CACHED_INFO 24 /* Enable TLS cached information */ /* extension, off by default. */ #define SSL_ENABLE_OB_CERTS 25 /* Enable origin bound certs. */ +#define SSL_ENCRYPT_CLIENT_CERTS 26 /* Enable encrypted client certs. */ #ifdef SSL_DEPRECATED_FUNCTION /* Old deprecated function names */ diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c index c46299e..5f920f9 100644 --- a/net/third_party/nss/ssl/ssl3con.c +++ b/net/third_party/nss/ssl/ssl3con.c @@ -2835,7 +2835,14 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) ss->ssl3.prSpec = ss->ssl3.crSpec; ss->ssl3.crSpec = prSpec; - ss->ssl3.hs.ws = wait_finished; + + if (ss->sec.isServer && + ss->opt.requestCertificate && + ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { + ss->ssl3.hs.ws = wait_client_cert; + } else { + ss->ssl3.hs.ws = wait_finished; + } SSL_TRC(3, ("%d: SSL3[%d] Set Current Read Cipher Suite to Pending", SSL_GETPID(), ss->fd )); @@ -4850,10 +4857,11 @@ loser: static SECStatus ssl3_SendCertificateVerify(sslSocket *ss) { - SECStatus rv = SECFailure; - PRBool isTLS; - SECItem buf = {siBuffer, NULL, 0}; - SSL3Hashes hashes; + SECStatus rv = SECFailure; + PRBool isTLS; + SECItem buf = {siBuffer, NULL, 0}; + SSL3Hashes hashes; + ssl3CipherSpec *spec; PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); @@ -4862,13 +4870,17 @@ ssl3_SendCertificateVerify(sslSocket *ss) SSL_GETPID(), ss->fd)); ssl_GetSpecReadLock(ss); - rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0); + spec = ss->ssl3.pwSpec; + if (ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { + spec = ss->ssl3.cwSpec; + } + rv = ssl3_ComputeHandshakeHashes(ss, spec, &hashes, 0); ssl_ReleaseSpecReadLock(ss); if (rv != SECSuccess) { goto done; /* err code was set by ssl3_ComputeHandshakeHashes */ } - isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0); if (ss->ssl3.platformClientKey) { #ifdef NSS_PLATFORM_CLIENT_AUTH rv = ssl3_PlatformSignHashes(&hashes, ss->ssl3.platformClientKey, @@ -5840,7 +5852,10 @@ ssl3_HandleServerHelloDone(sslSocket *ss) { SECStatus rv; SSL3WaitState ws = ss->ssl3.hs.ws; - PRBool send_verify = PR_FALSE; + PRBool sendEmptyCert, sendCert; + int n = 0, i; + typedef SECStatus (*SendFunction)(sslSocket*); + SendFunction send_funcs[5]; SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello_done handshake", SSL_GETPID(), ss->fd)); @@ -5858,45 +5873,44 @@ ssl3_HandleServerHelloDone(sslSocket *ss) ssl_GetXmitBufLock(ss); /*******************************/ - if (ss->ssl3.sendEmptyCert) { - ss->ssl3.sendEmptyCert = PR_FALSE; - rv = ssl3_SendEmptyCertificate(ss); - /* Don't send verify */ - if (rv != SECSuccess) { - goto loser; /* error code is set. */ - } - } else if (ss->ssl3.clientCertChain != NULL && - ss->ssl3.platformClientKey) { -#ifdef NSS_PLATFORM_CLIENT_AUTH - send_verify = PR_TRUE; - rv = ssl3_SendCertificate(ss); - if (rv != SECSuccess) { - goto loser; /* error code is set. */ - } -#endif /* NSS_PLATFORM_CLIENT_AUTH */ - } else if (ss->ssl3.clientCertChain != NULL && - ss->ssl3.clientPrivateKey != NULL) { - send_verify = PR_TRUE; - rv = ssl3_SendCertificate(ss); - if (rv != SECSuccess) { - goto loser; /* error code is set. */ - } - } + sendEmptyCert = ss->ssl3.sendEmptyCert; + ss->ssl3.sendEmptyCert = PR_FALSE; + sendCert = !sendEmptyCert && + ss->ssl3.clientCertChain != NULL && + (ss->ssl3.platformClientKey || + ss->ssl3.clientPrivateKey != NULL); - rv = ssl3_SendClientKeyExchange(ss); - if (rv != SECSuccess) { - goto loser; /* err is set. */ + if (ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { + send_funcs[n++] = ssl3_SendClientKeyExchange; + send_funcs[n++] = ssl3_SendChangeCipherSpecs; + if (sendEmptyCert) { + send_funcs[n++] = ssl3_SendEmptyCertificate; + } + if (sendCert) { + send_funcs[n++] = ssl3_SendCertificate; + send_funcs[n++] = ssl3_SendCertificateVerify; + } + } else { + if (sendEmptyCert) { + send_funcs[n++] = ssl3_SendEmptyCertificate; + } + if (sendCert) { + send_funcs[n++] = ssl3_SendCertificate; + } + send_funcs[n++] = ssl3_SendClientKeyExchange; + if (sendCert) { + send_funcs[n++] = ssl3_SendCertificateVerify; + } + send_funcs[n++] = ssl3_SendChangeCipherSpecs; } - if (send_verify) { - rv = ssl3_SendCertificateVerify(ss); + PORT_Assert(n <= sizeof(send_funcs)/sizeof(send_funcs[0])); + + for (i = 0; i < n; i++) { + rv = send_funcs[i](ss); if (rv != SECSuccess) { - goto loser; /* err is set. */ - } - } - rv = ssl3_SendChangeCipherSpecs(ss); - if (rv != SECSuccess) { - goto loser; /* err code was set. */ + goto loser; /* err code was set. */ + } } /* We don't send NPN in a renegotiation as it's explicitly disallowed by @@ -6110,8 +6124,13 @@ ssl3_SendServerHelloSequence(sslSocket *ss) return rv; /* err code is set. */ } - ss->ssl3.hs.ws = (ss->opt.requestCertificate) ? wait_client_cert - : wait_client_key; + if (ss->opt.requestCertificate && + !ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { + ss->ssl3.hs.ws = wait_client_cert; + } else { + ss->ssl3.hs.ws = wait_client_key; + } + return SECSuccess; } @@ -7355,7 +7374,11 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length, desc = isTLS ? decode_error : illegal_parameter; goto alert_loser; /* malformed */ } - ss->ssl3.hs.ws = wait_change_cipher; + if (ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { + ss->ssl3.hs.ws = wait_finished; + } else { + ss->ssl3.hs.ws = wait_change_cipher; + } return SECSuccess; alert_loser: @@ -8348,7 +8371,11 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) cert_block: if (ss->sec.isServer) { - ss->ssl3.hs.ws = wait_client_key; + if (ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { + ss->ssl3.hs.ws = wait_cert_verify; + } else { + ss->ssl3.hs.ws = wait_client_key; + } } else { ss->ssl3.hs.ws = wait_cert_request; /* disallow server_key_exchange */ if (ss->ssl3.hs.kea_def->is_limited || @@ -8978,6 +9005,8 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length) if (type == finished) { sender = ss->sec.isServer ? sender_client : sender_server; rSpec = ss->ssl3.crSpec; + } else if (ssl3_ExtensionNegotiated(ss, ssl_encrypted_client_certs)) { + rSpec = ss->ssl3.crSpec; } rv = ssl3_ComputeHandshakeHashes(ss, rSpec, &hashes, sender); } diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c index 09a1eeb..6590ffc 100644 --- a/net/third_party/nss/ssl/ssl3ext.c +++ b/net/third_party/nss/ssl/ssl3ext.c @@ -78,6 +78,12 @@ static PRInt32 ssl3_SendRenegotiationInfoXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes); static SECStatus ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data); +static SECStatus ssl3_ServerHandleEncryptedClientCertsXtn(sslSocket *ss, + PRUint16 ex_type, SECItem *data); +static SECStatus ssl3_ClientHandleEncryptedClientCertsXtn(sslSocket *ss, + PRUint16 ex_type, SECItem *data); +static PRInt32 ssl3_SendEncryptedClientCertsXtn(sslSocket *ss, + PRBool append, PRUint32 maxBytes); /* * Write bytes. Using this function means the SECItem structure @@ -234,6 +240,7 @@ static const ssl3HelloExtensionHandler clientHelloHandlers[] = { { ssl_ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn }, #endif { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn }, + { ssl_encrypted_client_certs, &ssl3_ServerHandleEncryptedClientCertsXtn }, { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, { ssl_next_proto_neg_xtn, &ssl3_ServerHandleNextProtoNegoXtn }, { ssl_cached_info_xtn, &ssl3_ServerHandleCachedInfoXtn }, @@ -247,6 +254,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = { { ssl_server_name_xtn, &ssl3_HandleServerNameXtn }, /* TODO: add a handler for ssl_ec_point_formats_xtn */ { ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn }, + { ssl_encrypted_client_certs, &ssl3_ClientHandleEncryptedClientCertsXtn }, { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, { ssl_next_proto_neg_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, { ssl_cached_info_xtn, &ssl3_ClientHandleCachedInfoXtn }, @@ -275,6 +283,7 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = { { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn }, #endif { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, + { ssl_encrypted_client_certs, &ssl3_SendEncryptedClientCertsXtn }, { ssl_next_proto_neg_xtn, &ssl3_ClientSendNextProtoNegoXtn }, { ssl_cached_info_xtn, &ssl3_ClientSendCachedInfoXtn }, { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn }, @@ -1318,6 +1327,18 @@ ssl3_ClientHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, return SECSuccess; } +static SECStatus +ssl3_ClientHandleEncryptedClientCertsXtn(sslSocket *ss, PRUint16 ex_type, + SECItem *data) +{ + if (data->len != 0) + return SECFailure; + + /* Keep track of negotiated extensions. */ + ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; + return SECSuccess; +} + SECStatus ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) @@ -1728,6 +1749,24 @@ loser: return rv; } +static SECStatus +ssl3_ServerHandleEncryptedClientCertsXtn(sslSocket *ss, PRUint16 ex_type, + SECItem *data) +{ + SECStatus rv = SECSuccess; + + if (data->len != 0) + return SECFailure; + + if (ss->opt.encryptClientCerts) { + ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; + rv = ssl3_RegisterServerHelloExtensionSender( + ss, ex_type, ssl3_SendEncryptedClientCertsXtn); + } + + return rv; +} + /* * Read bytes. Using this function means the SECItem structure * cannot be freed. The caller is expected to call this function @@ -1927,6 +1966,33 @@ ssl3_SendRenegotiationInfoXtn( return needed; } +static PRInt32 +ssl3_SendEncryptedClientCertsXtn( + sslSocket * ss, + PRBool append, + PRUint32 maxBytes) +{ + PRInt32 needed; + + if (!ss->opt.encryptClientCerts) + return 0; + + needed = 4; /* two bytes of type and two of length. */ + if (append && maxBytes >= needed) { + SECStatus rv; + rv = ssl3_AppendHandshakeNumber(ss, ssl_encrypted_client_certs, 2); + if (rv != SECSuccess) + return -1; + rv = ssl3_AppendHandshakeNumber(ss, 0 /* length */, 2); + if (rv != SECSuccess) + return -1; + ss->xtnData.advertised[ss->xtnData.numAdvertised++] = + ssl_encrypted_client_certs; + } + + return needed; +} + /* This function runs in both the client and server. */ static SECStatus ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h index d9f2bd7..ad718ef 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 enableOCSPStapling : 1; /* 24 */ unsigned int enableCachedInfo : 1; /* 25 */ unsigned int enableOBCerts : 1; /* 26 */ + unsigned int encryptClientCerts : 1; /* 27 */ } sslOptions; typedef enum { sslHandshakingUndetermined = 0, diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c index 85d1a8f..596ca3d 100644 --- a/net/third_party/nss/ssl/sslsock.c +++ b/net/third_party/nss/ssl/sslsock.c @@ -188,6 +188,7 @@ static sslOptions ssl_defaults = { PR_FALSE, /* enableOCSPStapling */ PR_FALSE, /* enableCachedInfo */ PR_FALSE, /* enableOBCerts */ + PR_FALSE, /* encryptClientCerts */ }; sslSessionIDLookupFunc ssl_sid_lookup; @@ -757,6 +758,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) ss->opt.enableOBCerts = on; break; + case SSL_ENCRYPT_CLIENT_CERTS: + ss->opt.encryptClientCerts = on; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; @@ -824,6 +829,8 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) case SSL_ENABLE_OCSP_STAPLING: on = ss->opt.enableOCSPStapling; break; case SSL_ENABLE_CACHED_INFO: on = ss->opt.enableCachedInfo; break; case SSL_ENABLE_OB_CERTS: on = ss->opt.enableOBCerts; break; + case SSL_ENCRYPT_CLIENT_CERTS: + on = ss->opt.encryptClientCerts; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -880,6 +887,8 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) break; case SSL_ENABLE_CACHED_INFO: on = ssl_defaults.enableCachedInfo; break; case SSL_ENABLE_OB_CERTS: on = ssl_defaults.enableOBCerts; break; + case SSL_ENCRYPT_CLIENT_CERTS: + on = ssl_defaults.encryptClientCerts; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -1039,6 +1048,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on) ssl_defaults.enableOBCerts = on; break; + case SSL_ENCRYPT_CLIENT_CERTS: + ssl_defaults.encryptClientCerts = on; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; diff --git a/net/third_party/nss/ssl/sslt.h b/net/third_party/nss/ssl/sslt.h index 5f852fe..4bbe1a0 100644 --- a/net/third_party/nss/ssl/sslt.h +++ b/net/third_party/nss/ssl/sslt.h @@ -206,10 +206,11 @@ typedef enum { ssl_session_ticket_xtn = 35, ssl_next_proto_neg_xtn = 13172, ssl_cached_info_xtn = 13173, + ssl_encrypted_client_certs = 13180, /* not IANA assigned. */ ssl_renegotiation_info_xtn = 0xff01, /* experimental number */ ssl_ob_cert_xtn = 13175 /* experimental number */ } SSLExtensionType; -#define SSL_MAX_EXTENSIONS 9 +#define SSL_MAX_EXTENSIONS 10 #endif /* __sslt_h_ */ |