diff options
author | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-30 05:52:51 +0000 |
---|---|---|
committer | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-30 05:52:51 +0000 |
commit | 7799de1ae747dcbd2e54f650539850fb6c139b1a (patch) | |
tree | 68e30cfd82a1b9ee944ecbb922994589caac1a77 /net | |
parent | e67140ee9ee65723732edb6a145b38030e142807 (diff) | |
download | chromium_src-7799de1ae747dcbd2e54f650539850fb6c139b1a.zip chromium_src-7799de1ae747dcbd2e54f650539850fb6c139b1a.tar.gz chromium_src-7799de1ae747dcbd2e54f650539850fb6c139b1a.tar.bz2 |
Implement TLS 1.2.
Patch by Adam Langley.
R=agl@chromium.org
BUG=90392
TEST=net_unittests
Review URL: https://chromiumcodereview.appspot.com/14772023
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203090 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/http/http_network_transaction_spdy2_unittest.cc | 15 | ||||
-rw-r--r-- | net/http/http_network_transaction_spdy3_unittest.cc | 15 | ||||
-rw-r--r-- | net/ssl/ssl_config_service.cc | 6 | ||||
-rw-r--r-- | net/third_party/nss/README.chromium | 7 | ||||
-rwxr-xr-x | net/third_party/nss/patches/applypatches.sh | 4 | ||||
-rw-r--r-- | net/third_party/nss/patches/tls12.patch | 1942 | ||||
-rw-r--r-- | net/third_party/nss/patches/tls12chromium.patch | 317 | ||||
-rw-r--r-- | net/third_party/nss/ssl/SSLerrs.h | 9 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3con.c | 852 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3ecc.c | 102 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3ext.c | 139 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3prot.h | 44 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslerr.h | 4 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslimpl.h | 26 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslplatf.c | 117 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslproto.h | 1 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslsock.c | 54 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslt.h | 3 |
18 files changed, 3467 insertions, 190 deletions
diff --git a/net/http/http_network_transaction_spdy2_unittest.cc b/net/http/http_network_transaction_spdy2_unittest.cc index a59f959..c6e0052 100644 --- a/net/http/http_network_transaction_spdy2_unittest.cc +++ b/net/http/http_network_transaction_spdy2_unittest.cc @@ -10117,6 +10117,13 @@ TEST_F(HttpNetworkTransactionSpdy2Test, net::StaticSocketDataProvider data4(NULL, 0, NULL, 0); session_deps_.socket_factory->AddSocketDataProvider(&data4); + // Need one more if TLSv1.2 is enabled. + SSLSocketDataProvider ssl_data5(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); + ssl_data5.cert_request_info = cert_request.get(); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data5); + net::StaticSocketDataProvider data5(NULL, 0, NULL, 0); + session_deps_.socket_factory->AddSocketDataProvider(&data5); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); scoped_ptr<HttpTransaction> trans( new HttpNetworkTransaction(DEFAULT_PRIORITY, session)); @@ -10230,6 +10237,14 @@ TEST_F(HttpNetworkTransactionSpdy2Test, data2_reads, arraysize(data2_reads), NULL, 0); session_deps_.socket_factory->AddSocketDataProvider(&data4); + // Need one more if TLSv1.2 is enabled. + SSLSocketDataProvider ssl_data5(ASYNC, net::OK); + ssl_data5.cert_request_info = cert_request.get(); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data5); + net::StaticSocketDataProvider data5( + data2_reads, arraysize(data2_reads), NULL, 0); + session_deps_.socket_factory->AddSocketDataProvider(&data5); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); scoped_ptr<HttpTransaction> trans( new HttpNetworkTransaction(DEFAULT_PRIORITY, session)); diff --git a/net/http/http_network_transaction_spdy3_unittest.cc b/net/http/http_network_transaction_spdy3_unittest.cc index 0b50e6f..ac59b50 100644 --- a/net/http/http_network_transaction_spdy3_unittest.cc +++ b/net/http/http_network_transaction_spdy3_unittest.cc @@ -10102,6 +10102,13 @@ TEST_F(HttpNetworkTransactionSpdy3Test, net::StaticSocketDataProvider data4(NULL, 0, NULL, 0); session_deps_.socket_factory->AddSocketDataProvider(&data4); + // Need one more if TLSv1.2 is enabled. + SSLSocketDataProvider ssl_data5(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); + ssl_data5.cert_request_info = cert_request.get(); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data5); + net::StaticSocketDataProvider data5(NULL, 0, NULL, 0); + session_deps_.socket_factory->AddSocketDataProvider(&data5); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); scoped_ptr<HttpTransaction> trans( new HttpNetworkTransaction(DEFAULT_PRIORITY, session)); @@ -10215,6 +10222,14 @@ TEST_F(HttpNetworkTransactionSpdy3Test, ClientAuthCertCache_Direct_FalseStart) { data2_reads, arraysize(data2_reads), NULL, 0); session_deps_.socket_factory->AddSocketDataProvider(&data4); + // Need one more if TLSv1.2 is enabled. + SSLSocketDataProvider ssl_data5(ASYNC, net::OK); + ssl_data5.cert_request_info = cert_request.get(); + session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data5); + net::StaticSocketDataProvider data5( + data2_reads, arraysize(data2_reads), NULL, 0); + session_deps_.socket_factory->AddSocketDataProvider(&data5); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); scoped_ptr<HttpTransaction> trans( new HttpNetworkTransaction(DEFAULT_PRIORITY, session)); diff --git a/net/ssl/ssl_config_service.cc b/net/ssl/ssl_config_service.cc index f195887..0561e7f 100644 --- a/net/ssl/ssl_config_service.cc +++ b/net/ssl/ssl_config_service.cc @@ -20,13 +20,15 @@ static uint16 g_default_version_min = SSL_PROTOCOL_VERSION_SSL3; static uint16 g_default_version_max = #if defined(USE_OPENSSL) -#if defined(SSL_OP_NO_TLSv1_1) +#if defined(SSL_OP_NO_TLSv1_2) + SSL_PROTOCOL_VERSION_TLS1_2; +#elif defined(SSL_OP_NO_TLSv1_1) SSL_PROTOCOL_VERSION_TLS1_1; #else SSL_PROTOCOL_VERSION_TLS1; #endif #else - SSL_PROTOCOL_VERSION_TLS1_1; + SSL_PROTOCOL_VERSION_TLS1_2; #endif SSLConfig::CertAndStatus::CertAndStatus() : cert_status(0) {} diff --git a/net/third_party/nss/README.chromium b/net/third_party/nss/README.chromium index da795cd..1abc5b7 100644 --- a/net/third_party/nss/README.chromium +++ b/net/third_party/nss/README.chromium @@ -100,6 +100,13 @@ Patches: patches/handlecertstatus.patch https://bugzilla.mozilla.org/show_bug.cgi?id=867795 + * Implement TLS 1.2. + patches/tls12.patch + https://bugzilla.mozilla.org/show_bug.cgi?id=480514 + + * Update Chromium-specific code for TLS 1.2. + patches/tls12chromium.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 00f9449..fc5fcfa 100755 --- a/net/third_party/nss/patches/applypatches.sh +++ b/net/third_party/nss/patches/applypatches.sh @@ -47,3 +47,7 @@ patch -p4 < $patches_dir/secitemarray.patch patch -p4 < $patches_dir/unusedvariables.patch patch -p4 < $patches_dir/handlecertstatus.patch + +patch -p4 < $patches_dir/tls12.patch + +patch -p4 < $patches_dir/tls12chromium.patch diff --git a/net/third_party/nss/patches/tls12.patch b/net/third_party/nss/patches/tls12.patch new file mode 100644 index 0000000..c385c00 --- /dev/null +++ b/net/third_party/nss/patches/tls12.patch @@ -0,0 +1,1942 @@ +Index: net/third_party/nss/ssl/sslt.h +=================================================================== +--- net/third_party/nss/ssl/sslt.h (revision 202696) ++++ net/third_party/nss/ssl/sslt.h (working copy) +@@ -193,6 +193,7 @@ + ssl_elliptic_curves_xtn = 10, + ssl_ec_point_formats_xtn = 11, + #endif ++ ssl_signature_algorithms_xtn = 13, + ssl_use_srtp_xtn = 14, + ssl_session_ticket_xtn = 35, + ssl_next_proto_nego_xtn = 13172, +@@ -200,6 +201,6 @@ + ssl_renegotiation_info_xtn = 0xff01 /* experimental number */ + } SSLExtensionType; + +-#define SSL_MAX_EXTENSIONS 9 ++#define SSL_MAX_EXTENSIONS 10 + + #endif /* __sslt_h_ */ +Index: net/third_party/nss/ssl/sslproto.h +=================================================================== +--- net/third_party/nss/ssl/sslproto.h (revision 202696) ++++ net/third_party/nss/ssl/sslproto.h (working copy) +@@ -16,6 +16,7 @@ + #define SSL_LIBRARY_VERSION_3_0 0x0300 + #define SSL_LIBRARY_VERSION_TLS_1_0 0x0301 + #define SSL_LIBRARY_VERSION_TLS_1_1 0x0302 ++#define SSL_LIBRARY_VERSION_TLS_1_2 0x0303 + /* Note: this is the internal format, not the wire format */ + #define SSL_LIBRARY_VERSION_DTLS_1_0 0x0302 + +Index: net/third_party/nss/ssl/SSLerrs.h +=================================================================== +--- net/third_party/nss/ssl/SSLerrs.h (revision 202696) ++++ net/third_party/nss/ssl/SSLerrs.h (working copy) +@@ -412,3 +412,12 @@ + + ER3(SSL_ERROR_GET_CHANNEL_ID_FAILED, (SSL_ERROR_BASE + 128), + "The application could not get a TLS Channel ID.") ++ ++ER3(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM, (SSL_ERROR_BASE + 129), ++"Unsupported hash algorithm used by TLS peer.") ++ ++ER3(SSL_ERROR_DIGEST_FAILURE, (SSL_ERROR_BASE + 130), ++"Digest function failed.") ++ ++ER3(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, (SSL_ERROR_BASE + 131), ++"Incorrect signature algorithm specified in a digitally-signed element.") +Index: net/third_party/nss/ssl/sslerr.h +=================================================================== +--- net/third_party/nss/ssl/sslerr.h (revision 202696) ++++ net/third_party/nss/ssl/sslerr.h (working copy) +@@ -194,6 +194,10 @@ + SSL_ERROR_INVALID_CHANNEL_ID_KEY = (SSL_ERROR_BASE + 127), + SSL_ERROR_GET_CHANNEL_ID_FAILED = (SSL_ERROR_BASE + 128), + ++SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM = (SSL_ERROR_BASE + 129), ++SSL_ERROR_DIGEST_FAILURE = (SSL_ERROR_BASE + 130), ++SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 131), ++ + SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ + } SSLErrorCodes; + #endif /* NO_SECURITY_ERROR_ENUM */ +Index: net/third_party/nss/ssl/sslimpl.h +=================================================================== +--- net/third_party/nss/ssl/sslimpl.h (revision 202696) ++++ net/third_party/nss/ssl/sslimpl.h (working copy) +@@ -799,6 +799,7 @@ + PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS]; + PK11Context * md5; /* handshake running hashes */ + PK11Context * sha; ++ PK11Context * tls12_handshake_hash; + const ssl3KEADef * kea_def; + ssl3CipherSuite cipher_suite; + const ssl3CipherSuiteDef *suite_def; +@@ -820,7 +821,7 @@ + PRUint16 finishedBytes; /* size of single finished below */ + union { + TLSFinished tFinished[2]; /* client, then server */ +- SSL3Hashes sFinished[2]; ++ SSL3Finished sFinished[2]; + SSL3Opaque data[72]; + } finishedMsgs; + #ifdef NSS_ENABLE_ECC +@@ -835,6 +836,12 @@ + /* Shared state between ssl3_HandleFinished and ssl3_FinishHandshake */ + PRBool cacheSID; + ++ /* clientSigAndHash contains the contents of the signature_algorithms ++ * extension (if any) from the client. This is only valid for TLS 1.2 ++ * or later. */ ++ SSL3SignatureAndHashAlgorithm *clientSigAndHash; ++ unsigned int numClientSigAndHash; ++ + /* This group of values is used for DTLS */ + PRUint16 sendMessageSeq; /* The sending message sequence + * number */ +@@ -1473,7 +1480,7 @@ + * runtime to determine which versions are supported by the version of libssl + * in use. + */ +-#define SSL_LIBRARY_VERSION_MAX_SUPPORTED SSL_LIBRARY_VERSION_TLS_1_1 ++#define SSL_LIBRARY_VERSION_MAX_SUPPORTED SSL_LIBRARY_VERSION_TLS_1_2 + + /* Rename this macro SSL_ALL_VERSIONS_DISABLED when SSL 2.0 is removed. */ + #define SSL3_ALL_VERSIONS_DISABLED(vrange) \ +@@ -1639,10 +1646,12 @@ + SSL3Opaque *b, PRUint32 length, + SECKEYPublicKey *srvrPubKey, + SECKEYPrivateKey *srvrPrivKey); +-extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss); ++extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss, ++ const SSL3SignatureAndHashAlgorithm *sigAndHash); + #endif + +-extern SECStatus ssl3_ComputeCommonKeyHash(PRUint8 * hashBuf, ++extern SECStatus ssl3_ComputeCommonKeyHash(SECOidTag hashAlg, ++ PRUint8 * hashBuf, + unsigned int bufLen, SSL3Hashes *hashes, + PRBool bypassPKCS11); + extern void ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName); +@@ -1655,12 +1664,21 @@ + PRInt32 lenSize); + extern SECStatus ssl3_AppendHandshakeVariable( sslSocket *ss, + const SSL3Opaque *src, PRInt32 bytes, PRInt32 lenSize); ++extern SECStatus ssl3_AppendSignatureAndHashAlgorithm(sslSocket *ss, ++ const SSL3SignatureAndHashAlgorithm* sigAndHash); + extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, + SSL3Opaque **b, PRUint32 *length); + extern PRInt32 ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, + SSL3Opaque **b, PRUint32 *length); + extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, + PRInt32 bytes, SSL3Opaque **b, PRUint32 *length); ++extern SECOidTag ssl3_TLSHashAlgorithmToOID(int hashFunc); ++extern SECStatus ssl3_CheckSignatureAndHashAlgorithmConsistency( ++ const SSL3SignatureAndHashAlgorithm *sigAndHash, ++ CERTCertificate* cert); ++extern SECStatus ssl3_ConsumeSignatureAndHashAlgorithm(sslSocket *ss, ++ SSL3Opaque **b, PRUint32 *length, ++ SSL3SignatureAndHashAlgorithm *out); + extern SECStatus ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, + SECItem *buf, PRBool isTLS); + extern SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash, +Index: net/third_party/nss/ssl/ssl3prot.h +=================================================================== +--- net/third_party/nss/ssl/ssl3prot.h (revision 202696) ++++ net/third_party/nss/ssl/ssl3prot.h (working copy) +@@ -212,11 +212,51 @@ + } u; + } SSL3ServerParams; + ++/* This enum reflects HashAlgorithm enum from ++ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 ++ * ++ * When updating, be sure to also update ssl3_TLSHashAlgorithmToOID. */ ++enum { ++ tls_hash_md5 = 1, ++ tls_hash_sha1 = 2, ++ tls_hash_sha224 = 3, ++ tls_hash_sha256 = 4, ++ tls_hash_sha384 = 5, ++ tls_hash_sha512 = 6 ++}; ++ ++/* This enum reflects SignatureAlgorithm enum from ++ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ ++typedef enum { ++ tls_sig_rsa = 1, ++ tls_sig_dsa = 2, ++ tls_sig_ecdsa = 3 ++} TLSSignatureAlgorithm; ++ + typedef struct { ++ SECOidTag hashAlg; ++ TLSSignatureAlgorithm sigAlg; ++} SSL3SignatureAndHashAlgorithm; ++ ++/* SSL3HashesIndividually contains a combination MD5/SHA1 hash, as used in TLS ++ * prior to 1.2. */ ++typedef struct { + uint8 md5[16]; + uint8 sha[20]; ++} SSL3HashesIndividually; ++ ++/* SSL3Hashes contains an SSL hash value. The digest is contained in |u.raw| ++ * which, if |hashAlg==SEC_OID_UNKNOWN| is also a SSL3HashesIndividually ++ * struct. */ ++typedef struct { ++ unsigned int len; ++ SECOidTag hashAlg; ++ union { ++ PRUint8 raw[64]; ++ SSL3HashesIndividually s; ++ } u; + } SSL3Hashes; +- ++ + typedef struct { + union { + SSL3Opaque anonymous; +@@ -274,7 +314,7 @@ + sender_server = 0x53525652 + } SSL3Sender; + +-typedef SSL3Hashes SSL3Finished; ++typedef SSL3HashesIndividually SSL3Finished; + + typedef struct { + SSL3Opaque verify_data[12]; +Index: net/third_party/nss/ssl/ssl3ecc.c +=================================================================== +--- net/third_party/nss/ssl/ssl3ecc.c (revision 202696) ++++ net/third_party/nss/ssl/ssl3ecc.c (working copy) +@@ -217,9 +223,10 @@ + + /* Caller must set hiLevel error code. */ + static SECStatus +-ssl3_ComputeECDHKeyHash(SECItem ec_params, SECItem server_ecpoint, +- SSL3Random *client_rand, SSL3Random *server_rand, +- SSL3Hashes *hashes, PRBool bypassPKCS11) ++ssl3_ComputeECDHKeyHash(SECOidTag hashAlg, ++ SECItem ec_params, SECItem server_ecpoint, ++ SSL3Random *client_rand, SSL3Random *server_rand, ++ SSL3Hashes *hashes, PRBool bypassPKCS11) + { + PRUint8 * hashBuf; + PRUint8 * pBuf; +@@ -255,11 +262,14 @@ + pBuf += server_ecpoint.len; + PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); + +- rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11); ++ rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, ++ bypassPKCS11); + + PRINT_BUF(95, (NULL, "ECDHkey hash: ", hashBuf, bufLen)); +- PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", hashes->md5, MD5_LENGTH)); +- PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); ++ PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", ++ hashes->u.s.md5, MD5_LENGTH)); ++ PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", ++ hashes->u.s.sha, SHA1_LENGTH)); + + if (hashBuf != buf) + PORT_Free(hashBuf); +@@ -273,7 +283,7 @@ + { + PK11SymKey * pms = NULL; + SECStatus rv = SECFailure; +- PRBool isTLS; ++ PRBool isTLS, isTLS12; + CK_MECHANISM_TYPE target; + SECKEYPublicKey *pubKey = NULL; /* Ephemeral ECDH key */ + SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */ +@@ -282,6 +292,7 @@ + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); ++ isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + + /* Generate ephemeral EC keypair */ + if (svrPubKey->keyType != ecKey) { +@@ -300,8 +311,13 @@ + pubKey->u.ec.publicValue.data, + pubKey->u.ec.publicValue.len)); + +- if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; +- else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; ++ if (isTLS12) { ++ target = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256; ++ } else if (isTLS) { ++ target = CKM_TLS_MASTER_KEY_DERIVE_DH; ++ } else { ++ target = CKM_SSL3_MASTER_KEY_DERIVE_DH; ++ } + + /* Determine the PMS */ + pms = PK11_PubDeriveWithKDF(privKey, svrPubKey, PR_FALSE, NULL, NULL, +@@ -365,7 +381,7 @@ + SECStatus rv; + SECKEYPublicKey clntPubKey; + CK_MECHANISM_TYPE target; +- PRBool isTLS; ++ PRBool isTLS, isTLS12; + + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); +@@ -384,9 +400,15 @@ + } + + isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); ++ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + +- if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; +- else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; ++ if (isTLS12) { ++ target = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256; ++ } else if (isTLS) { ++ target = CKM_TLS_MASTER_KEY_DERIVE_DH; ++ } else { ++ target = CKM_SSL3_MASTER_KEY_DERIVE_DH; ++ } + + /* Determine the PMS */ + pms = PK11_PubDeriveWithKDF(srvrPrivKey, &clntPubKey, PR_FALSE, NULL, NULL, +@@ -582,7 +604,7 @@ + { + PRArenaPool * arena = NULL; + SECKEYPublicKey *peerKey = NULL; +- PRBool isTLS; ++ PRBool isTLS, isTLS12; + SECStatus rv; + int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; + SSL3AlertDescription desc = illegal_parameter; +@@ -592,8 +614,12 @@ + SECItem ec_params = {siBuffer, NULL, 0}; + SECItem ec_point = {siBuffer, NULL, 0}; + unsigned char paramBuf[3]; /* only for curve_type == named_curve */ ++ SSL3SignatureAndHashAlgorithm sigAndHash; + ++ sigAndHash.hashAlg = SEC_OID_UNKNOWN; ++ + isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); ++ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + + /* XXX This works only for named curves, revisit this when + * we support generic curves. +@@ -625,6 +651,19 @@ + goto alert_loser; + } + ++ if (isTLS12) { ++ rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, ++ &sigAndHash); ++ if (rv != SECSuccess) { ++ goto loser; /* malformed or unsupported. */ ++ } ++ rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( ++ &sigAndHash, ss->sec.peerCert); ++ if (rv != SECSuccess) { ++ goto loser; ++ } ++ } ++ + rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed. */ +@@ -647,10 +686,10 @@ + /* + * check to make sure the hash is signed by right guy + */ +- rv = ssl3_ComputeECDHKeyHash(ec_params, ec_point, +- &ss->ssl3.hs.client_random, +- &ss->ssl3.hs.server_random, +- &hashes, ss->opt.bypassPKCS11); ++ rv = ssl3_ComputeECDHKeyHash(sigAndHash.hashAlg, ec_params, ec_point, ++ &ss->ssl3.hs.client_random, ++ &ss->ssl3.hs.server_random, ++ &hashes, ss->opt.bypassPKCS11); + + if (rv != SECSuccess) { + errCode = +@@ -714,12 +753,14 @@ + } + + SECStatus +-ssl3_SendECDHServerKeyExchange(sslSocket *ss) ++ssl3_SendECDHServerKeyExchange( ++ sslSocket *ss, ++ const SSL3SignatureAndHashAlgorithm *sigAndHash) + { +-const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; ++ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; + SECStatus rv = SECFailure; + int length; +- PRBool isTLS; ++ PRBool isTLS, isTLS12; + SECItem signed_hash = {siBuffer, NULL, 0}; + SSL3Hashes hashes; + +@@ -729,7 +770,6 @@ + ECName curve; + SSL3KEAType certIndex; + +- + /* Generate ephemeral ECDH key pair and send the public key */ + curve = ssl3_GetCurveNameForServerSocket(ss); + if (curve == ec_noName) { +@@ -758,16 +798,19 @@ + goto loser; + } + +- rv = ssl3_ComputeECDHKeyHash(ec_params, ecdhePub->u.ec.publicValue, +- &ss->ssl3.hs.client_random, +- &ss->ssl3.hs.server_random, +- &hashes, ss->opt.bypassPKCS11); ++ rv = ssl3_ComputeECDHKeyHash(sigAndHash->hashAlg, ++ ec_params, ++ ecdhePub->u.ec.publicValue, ++ &ss->ssl3.hs.client_random, ++ &ss->ssl3.hs.server_random, ++ &hashes, ss->opt.bypassPKCS11); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); + goto loser; + } + + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); ++ isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + + /* XXX SSLKEAType isn't really a good choice for + * indexing certificates but that's all we have +@@ -791,7 +834,7 @@ + + length = ec_params.len + + 1 + ecdhePub->u.ec.publicValue.len + +- 2 + signed_hash.len; ++ (isTLS12 ? 2 : 0) + 2 + signed_hash.len; + + rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); + if (rv != SECSuccess) { +@@ -809,6 +852,13 @@ + goto loser; /* err set by AppendHandshake. */ + } + ++ if (isTLS12) { ++ rv = ssl3_AppendSignatureAndHashAlgorithm(ss, sigAndHash); ++ if (rv != SECSuccess) { ++ goto loser; /* err set by AppendHandshake. */ ++ } ++ } ++ + rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, + signed_hash.len, 2); + if (rv != SECSuccess) { +Index: net/third_party/nss/ssl/ssl3ext.c +=================================================================== +--- net/third_party/nss/ssl/ssl3ext.c (revision 202696) ++++ net/third_party/nss/ssl/ssl3ext.c (working copy) +@@ -74,6 +74,10 @@ + SECItem *data); + static PRInt32 ssl3_ClientSendStatusRequestXtn(sslSocket * ss, PRBool append, + PRUint32 maxBytes); ++static PRInt32 ssl3_ClientSendSigAlgsXtn(sslSocket *ss, PRBool append, ++ PRUint32 maxBytes); ++static SECStatus ssl3_ServerHandleSigAlgsXtn(sslSocket *ss, PRUint16 ex_type, ++ SECItem *data); + + /* + * Write bytes. Using this function means the SECItem structure +@@ -236,6 +240,7 @@ + { ssl_next_proto_nego_xtn, &ssl3_ServerHandleNextProtoNegoXtn }, + { ssl_use_srtp_xtn, &ssl3_HandleUseSRTPXtn }, + { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn }, ++ { ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn }, + { -1, NULL } + }; + +@@ -276,7 +281,8 @@ + { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn }, + { ssl_use_srtp_xtn, &ssl3_SendUseSRTPXtn }, + { ssl_channel_id_xtn, &ssl3_ClientSendChannelIDXtn }, +- { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn } ++ { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn }, ++ { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn } + /* any extra entries will appear as { 0, NULL } */ + }; + +@@ -2039,3 +2045,134 @@ + return ssl3_RegisterServerHelloExtensionSender(ss, ssl_use_srtp_xtn, + ssl3_SendUseSRTPXtn); + } ++ ++/* ssl3_ServerHandleSigAlgsXtn handles the signature_algorithms extension ++ * from a client. ++ * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ ++static SECStatus ++ssl3_ServerHandleSigAlgsXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) ++{ ++ SECStatus rv; ++ SECItem algorithms; ++ const unsigned char *b; ++ unsigned int numAlgorithms, i; ++ ++ /* Ignore this extension if we aren't doing TLS 1.2 or greater. */ ++ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) { ++ return SECSuccess; ++ } ++ ++ /* Keep track of negotiated extensions. */ ++ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; ++ ++ rv = ssl3_ConsumeHandshakeVariable(ss, &algorithms, 2, &data->data, ++ &data->len); ++ if (rv != SECSuccess) { ++ return SECFailure; ++ } ++ /* Trailing data or odd-length parameters is invalid. */ ++ if (data->len != 0 || (algorithms.len & 1) != 0) { ++ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); ++ return SECFailure; ++ } ++ ++ numAlgorithms = algorithms.len/2; ++ ++ if (numAlgorithms == 0) { ++ return SECSuccess; ++ } ++ /* We don't care to process excessive numbers of algorithms. */ ++ if (numAlgorithms > 512) { ++ numAlgorithms = 512; ++ } ++ ++ ss->ssl3.hs.clientSigAndHash = ++ PORT_NewArray(SSL3SignatureAndHashAlgorithm, numAlgorithms); ++ if (!ss->ssl3.hs.clientSigAndHash) { ++ return SECFailure; ++ } ++ ss->ssl3.hs.numClientSigAndHash = 0; ++ ++ b = algorithms.data; ++ for (i = 0; i < numAlgorithms; i++) { ++ unsigned char tls_hash = *(b++); ++ unsigned char tls_sig = *(b++); ++ SECOidTag hash = ssl3_TLSHashAlgorithmToOID(tls_hash); ++ ++ if (hash == SEC_OID_UNKNOWN) { ++ /* We ignore formats that we don't understand. */ ++ continue; ++ } ++ /* tls_sig support will be checked later in ++ * ssl3_PickSignatureHashAlgorithm. */ ++ ss->ssl3.hs.clientSigAndHash[i].hashAlg = hash; ++ ss->ssl3.hs.clientSigAndHash[i].sigAlg = tls_sig; ++ ss->ssl3.hs.numClientSigAndHash++; ++ } ++ ++ if (!ss->ssl3.hs.numClientSigAndHash) { ++ /* We didn't understand any of the client's requested signature ++ * formats. We'll use the defaults. */ ++ PORT_Free(ss->ssl3.hs.clientSigAndHash); ++ ss->ssl3.hs.clientSigAndHash = NULL; ++ } ++ ++ return SECSuccess; ++} ++ ++/* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS ++ * 1.2 ClientHellos. */ ++static PRInt32 ++ssl3_ClientSendSigAlgsXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes) ++{ ++ static const unsigned char signatureAlgorithms[] = { ++ /* This block is the contents of our signature_algorithms extension, in ++ * wire format. See ++ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ ++ tls_hash_sha256, tls_sig_rsa, ++ tls_hash_sha384, tls_sig_rsa, ++ tls_hash_sha1, tls_sig_rsa, ++#ifdef NSS_ENABLE_ECC ++ tls_hash_sha256, tls_sig_ecdsa, ++ tls_hash_sha384, tls_sig_ecdsa, ++ tls_hash_sha1, tls_sig_ecdsa, ++#endif ++ tls_hash_sha256, tls_sig_dsa, ++ tls_hash_sha1, tls_sig_dsa, ++ }; ++ PRInt32 extension_length; ++ ++ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) { ++ return 0; ++ } ++ ++ extension_length = ++ 2 /* extension type */ + ++ 2 /* extension length */ + ++ 2 /* supported_signature_algorithms length */ + ++ sizeof(signatureAlgorithms); ++ ++ if (append && maxBytes >= extension_length) { ++ SECStatus rv; ++ rv = ssl3_AppendHandshakeNumber(ss, ssl_signature_algorithms_xtn, 2); ++ if (rv != SECSuccess) ++ goto loser; ++ rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); ++ if (rv != SECSuccess) ++ goto loser; ++ rv = ssl3_AppendHandshakeVariable(ss, signatureAlgorithms, ++ sizeof(signatureAlgorithms), 2); ++ if (rv != SECSuccess) ++ goto loser; ++ ss->xtnData.advertised[ss->xtnData.numAdvertised++] = ++ ssl_signature_algorithms_xtn; ++ } else if (maxBytes < extension_length) { ++ PORT_Assert(0); ++ return 0; ++ } ++ ++ return extension_length; ++ ++loser: ++ return -1; ++} +Index: net/third_party/nss/ssl/sslsock.c +=================================================================== +--- net/third_party/nss/ssl/sslsock.c (revision 202696) ++++ net/third_party/nss/ssl/sslsock.c (working copy) +@@ -782,6 +789,17 @@ + rv = SECFailure; + } else { + if (PR_FALSE != on) { ++ /* TLS 1.2 isn't supported in bypass mode. */ ++ if (ss->vrange.min >= SSL_LIBRARY_VERSION_TLS_1_2) { ++ /* If the user requested a minimum version of TLS 1.2 then ++ * we don't silently downgrade. */ ++ PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE); ++ rv = SECFailure; ++ break; ++ } ++ if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_2) { ++ ss->vrange.max = SSL_LIBRARY_VERSION_TLS_1_1; ++ } + if (PR_SUCCESS == SSL_BypassSetup() ) { + #ifdef NO_PKCS11_BYPASS + ss->opt.bypassPKCS11 = PR_FALSE; +Index: net/third_party/nss/ssl/ssl3con.c +=================================================================== +--- net/third_party/nss/ssl/ssl3con.c (revision 202696) ++++ net/third_party/nss/ssl/ssl3con.c (working copy) +@@ -15,6 +15,7 @@ + #include "keyhi.h" + #include "secder.h" + #include "secitem.h" ++#include "sechash.h" + + #include "sslimpl.h" + #include "sslproto.h" +@@ -64,6 +74,7 @@ + const unsigned char *b, + unsigned int l); + static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags); ++static int ssl3_OIDToTLSHashAlgorithm(SECOidTag oid); + + static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen, + int maxOutputLen, const unsigned char *input, +@@ -811,32 +822,36 @@ + SECItem hashItem; + + buf->data = NULL; +- signatureLen = PK11_SignatureLen(key); +- if (signatureLen <= 0) { +- PORT_SetError(SEC_ERROR_INVALID_KEY); +- goto done; +- } + +- buf->len = (unsigned)signatureLen; +- buf->data = (unsigned char *)PORT_Alloc(signatureLen); +- if (!buf->data) +- goto done; /* error code was set. */ +- + switch (key->keyType) { + case rsaKey: +- hashItem.data = hash->md5; +- hashItem.len = sizeof(SSL3Hashes); ++ hashItem.data = hash->u.raw; ++ hashItem.len = hash->len; + break; + case dsaKey: + doDerEncode = isTLS; +- hashItem.data = hash->sha; +- hashItem.len = sizeof(hash->sha); ++ /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash. ++ * In that case, we use just the SHA1 part. */ ++ if (hash->hashAlg == SEC_OID_UNKNOWN) { ++ hashItem.data = hash->u.s.sha; ++ hashItem.len = sizeof(hash->u.s.sha); ++ } else { ++ hashItem.data = hash->u.raw; ++ hashItem.len = hash->len; ++ } + break; + #ifdef NSS_ENABLE_ECC + case ecKey: + doDerEncode = PR_TRUE; +- hashItem.data = hash->sha; +- hashItem.len = sizeof(hash->sha); ++ /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash. ++ * In that case, we use just the SHA1 part. */ ++ if (hash->hashAlg == SEC_OID_UNKNOWN) { ++ hashItem.data = hash->u.s.sha; ++ hashItem.len = sizeof(hash->u.s.sha); ++ } else { ++ hashItem.data = hash->u.raw; ++ hashItem.len = hash->len; ++ } + break; + #endif /* NSS_ENABLE_ECC */ + default: +@@ -845,7 +860,22 @@ + } + PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len)); + +- rv = PK11_Sign(key, buf, &hashItem); ++ if (hash->hashAlg == SEC_OID_UNKNOWN) { ++ signatureLen = PK11_SignatureLen(key); ++ if (signatureLen <= 0) { ++ PORT_SetError(SEC_ERROR_INVALID_KEY); ++ goto done; ++ } ++ ++ buf->len = (unsigned)signatureLen; ++ buf->data = (unsigned char *)PORT_Alloc(signatureLen); ++ if (!buf->data) ++ goto done; /* error code was set. */ ++ ++ rv = PK11_Sign(key, buf, &hashItem); ++ } else { ++ rv = SGN_Digest(key, hash->hashAlg, buf, &hashItem); ++ } + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + } else if (doDerEncode) { +@@ -879,9 +909,8 @@ + SECItem * signature = NULL; + SECStatus rv; + SECItem hashItem; +-#ifdef NSS_ENABLE_ECC +- unsigned int len; +-#endif /* NSS_ENABLE_ECC */ ++ SECOidTag encAlg; ++ SECOidTag hashAlg; + + + PRINT_BUF(60, (NULL, "check signed hashes", +@@ -893,14 +922,24 @@ + return SECFailure; + } + ++ hashAlg = hash->hashAlg; + switch (key->keyType) { + case rsaKey: +- hashItem.data = hash->md5; +- hashItem.len = sizeof(SSL3Hashes); ++ encAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; ++ hashItem.data = hash->u.raw; ++ hashItem.len = hash->len; + break; + case dsaKey: +- hashItem.data = hash->sha; +- hashItem.len = sizeof(hash->sha); ++ encAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; ++ /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash. ++ * In that case, we use just the SHA1 part. */ ++ if (hash->hashAlg == SEC_OID_UNKNOWN) { ++ hashItem.data = hash->u.s.sha; ++ hashItem.len = sizeof(hash->u.s.sha); ++ } else { ++ hashItem.data = hash->u.raw; ++ hashItem.len = hash->len; ++ } + /* Allow DER encoded DSA signatures in SSL 3.0 */ + if (isTLS || buf->len != SECKEY_SignatureLen(key)) { + signature = DSAU_DecodeDerSig(buf); +@@ -914,25 +953,21 @@ + + #ifdef NSS_ENABLE_ECC + case ecKey: +- hashItem.data = hash->sha; +- hashItem.len = sizeof(hash->sha); +- /* +- * ECDSA signatures always encode the integers r and s +- * using ASN (unlike DSA where ASN encoding is used +- * with TLS but not with SSL3) ++ encAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; ++ /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash. ++ * In that case, we use just the SHA1 part. ++ * ECDSA signatures always encode the integers r and s using ASN.1 ++ * (unlike DSA where ASN.1 encoding is used with TLS but not with ++ * SSL3). So we can use VFY_VerifyDigestDirect for ECDSA. + */ +- len = SECKEY_SignatureLen(key); +- if (len == 0) { +- SECKEY_DestroyPublicKey(key); +- PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); +- return SECFailure; ++ if (hash->hashAlg == SEC_OID_UNKNOWN) { ++ hashAlg = SEC_OID_SHA1; ++ hashItem.data = hash->u.s.sha; ++ hashItem.len = sizeof(hash->u.s.sha); ++ } else { ++ hashItem.data = hash->u.raw; ++ hashItem.len = hash->len; + } +- signature = DSAU_DecodeDerSigToLen(buf, len); +- if (!signature) { +- PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); +- return SECFailure; +- } +- buf = signature; + break; + #endif /* NSS_ENABLE_ECC */ + +@@ -945,7 +980,17 @@ + PRINT_BUF(60, (NULL, "hash(es) to be verified", + hashItem.data, hashItem.len)); + +- rv = PK11_Verify(key, buf, &hashItem, pwArg); ++ if (hashAlg == SEC_OID_UNKNOWN || key->keyType == dsaKey) { ++ /* VFY_VerifyDigestDirect requires DSA signatures to be DER-encoded. ++ * DSA signatures are DER-encoded in TLS but not in SSL3 and the code ++ * above always removes the DER encoding of DSA signatures when ++ * present. Thus DSA signatures are always verified with PK11_Verify. ++ */ ++ rv = PK11_Verify(key, buf, &hashItem, pwArg); ++ } else { ++ rv = VFY_VerifyDigestDirect(&hashItem, key, buf, encAlg, hashAlg, ++ pwArg); ++ } + SECKEY_DestroyPublicKey(key); + if (signature) { + SECITEM_FreeItem(signature, PR_TRUE); +@@ -961,33 +1006,69 @@ + /* Called from ssl3_ComputeExportRSAKeyHash + * ssl3_ComputeDHKeyHash + * which are called from ssl3_HandleServerKeyExchange. ++ * ++ * hashAlg: either the OID for a hash algorithm or SEC_OID_UNKNOWN to specify ++ * the pre-1.2, MD5/SHA1 combination hash. + */ + SECStatus +-ssl3_ComputeCommonKeyHash(PRUint8 * hashBuf, unsigned int bufLen, +- SSL3Hashes *hashes, PRBool bypassPKCS11) ++ssl3_ComputeCommonKeyHash(SECOidTag hashAlg, ++ PRUint8 * hashBuf, unsigned int bufLen, ++ SSL3Hashes *hashes, PRBool bypassPKCS11) + { + SECStatus rv = SECSuccess; + + #ifndef NO_PKCS11_BYPASS + if (bypassPKCS11) { +- MD5_HashBuf (hashes->md5, hashBuf, bufLen); +- SHA1_HashBuf(hashes->sha, hashBuf, bufLen); ++ if (hashAlg == SEC_OID_UNKNOWN) { ++ MD5_HashBuf (hashes->u.s.md5, hashBuf, bufLen); ++ SHA1_HashBuf(hashes->u.s.sha, hashBuf, bufLen); ++ hashes->len = MD5_LENGTH + SHA1_LENGTH; ++ } else if (hashAlg == SEC_OID_SHA1) { ++ SHA1_HashBuf(hashes->u.raw, hashBuf, bufLen); ++ hashes->len = SHA1_LENGTH; ++ } else if (hashAlg == SEC_OID_SHA256) { ++ SHA256_HashBuf(hashes->u.raw, hashBuf, bufLen); ++ hashes->len = SHA256_LENGTH; ++ } else if (hashAlg == SEC_OID_SHA384) { ++ SHA384_HashBuf(hashes->u.raw, hashBuf, bufLen); ++ hashes->len = SHA384_LENGTH; ++ } else { ++ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); ++ return SECFailure; ++ } + } else + #endif + { +- rv = PK11_HashBuf(SEC_OID_MD5, hashes->md5, hashBuf, bufLen); +- if (rv != SECSuccess) { +- ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); +- rv = SECFailure; +- goto done; +- } ++ if (hashAlg == SEC_OID_UNKNOWN) { ++ rv = PK11_HashBuf(SEC_OID_MD5, hashes->u.s.md5, hashBuf, bufLen); ++ if (rv != SECSuccess) { ++ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); ++ rv = SECFailure; ++ goto done; ++ } + +- rv = PK11_HashBuf(SEC_OID_SHA1, hashes->sha, hashBuf, bufLen); +- if (rv != SECSuccess) { +- ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); +- rv = SECFailure; ++ rv = PK11_HashBuf(SEC_OID_SHA1, hashes->u.s.sha, hashBuf, bufLen); ++ if (rv != SECSuccess) { ++ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); ++ rv = SECFailure; ++ } ++ hashes->len = MD5_LENGTH + SHA1_LENGTH; ++ } else { ++ hashes->len = HASH_ResultLenByOidTag(hashAlg); ++ if (hashes->len > sizeof(hashes->u.raw)) { ++ ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); ++ rv = SECFailure; ++ goto done; ++ } ++ rv = PK11_HashBuf(hashAlg, hashes->u.raw, hashBuf, bufLen); ++ if (rv != SECSuccess) { ++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); ++ rv = SECFailure; ++ } + } + } ++ hashes->hashAlg = hashAlg; ++ + done: + return rv; + } +@@ -997,7 +1078,8 @@ + ** ssl3_HandleServerKeyExchange. + */ + static SECStatus +-ssl3_ComputeExportRSAKeyHash(SECItem modulus, SECItem publicExponent, ++ssl3_ComputeExportRSAKeyHash(SECOidTag hashAlg, ++ SECItem modulus, SECItem publicExponent, + SSL3Random *client_rand, SSL3Random *server_rand, + SSL3Hashes *hashes, PRBool bypassPKCS11) + { +@@ -1033,11 +1115,19 @@ + pBuf += publicExponent.len; + PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); + +- rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11); ++ rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, ++ bypassPKCS11); + + PRINT_BUF(95, (NULL, "RSAkey hash: ", hashBuf, bufLen)); +- PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result", hashes->md5, MD5_LENGTH)); +- PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); ++ if (hashAlg == SEC_OID_UNKNOWN) { ++ PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result", ++ hashes->u.s.md5, MD5_LENGTH)); ++ PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result", ++ hashes->u.s.sha, SHA1_LENGTH)); ++ } else { ++ PRINT_BUF(95, (NULL, "RSAkey hash: result", ++ hashes->u.raw, hashes->len)); ++ } + + if (hashBuf != buf && hashBuf != NULL) + PORT_Free(hashBuf); +@@ -1047,9 +1137,10 @@ + /* Caller must set hiLevel error code. */ + /* Called from ssl3_HandleServerKeyExchange. */ + static SECStatus +-ssl3_ComputeDHKeyHash(SECItem dh_p, SECItem dh_g, SECItem dh_Ys, +- SSL3Random *client_rand, SSL3Random *server_rand, +- SSL3Hashes *hashes, PRBool bypassPKCS11) ++ssl3_ComputeDHKeyHash(SECOidTag hashAlg, ++ SECItem dh_p, SECItem dh_g, SECItem dh_Ys, ++ SSL3Random *client_rand, SSL3Random *server_rand, ++ SSL3Hashes *hashes, PRBool bypassPKCS11) + { + PRUint8 * hashBuf; + PRUint8 * pBuf; +@@ -1088,11 +1179,19 @@ + pBuf += dh_Ys.len; + PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); + +- rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11); ++ rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, ++ bypassPKCS11); + + PRINT_BUF(95, (NULL, "DHkey hash: ", hashBuf, bufLen)); +- PRINT_BUF(95, (NULL, "DHkey hash: MD5 result", hashes->md5, MD5_LENGTH)); +- PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); ++ if (hashAlg == SEC_OID_UNKNOWN) { ++ PRINT_BUF(95, (NULL, "DHkey hash: MD5 result", ++ hashes->u.s.md5, MD5_LENGTH)); ++ PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result", ++ hashes->u.s.sha, SHA1_LENGTH)); ++ } else { ++ PRINT_BUF(95, (NULL, "DHkey hash: result", ++ hashes->u.raw, hashes->len)); ++ } + + if (hashBuf != buf && hashBuf != NULL) + PORT_Free(hashBuf); +@@ -3190,6 +3289,8 @@ + unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random; + PRBool isTLS = (PRBool)(kea_def->tls_keygen || + (pwSpec->version > SSL_LIBRARY_VERSION_3_0)); ++ PRBool isTLS12= ++ (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + /* + * Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH + * which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size +@@ -3208,7 +3309,12 @@ + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); + PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); +- if (isTLS) { ++ if (isTLS12) { ++ if(isDH) master_derive = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256; ++ else master_derive = CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256; ++ key_derive = CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256; ++ keyFlags = CKF_SIGN | CKF_VERIFY; ++ } else if (isTLS) { + if(isDH) master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH; + else master_derive = CKM_TLS_MASTER_KEY_DERIVE; + key_derive = CKM_TLS_KEY_AND_MAC_DERIVE; +@@ -3366,6 +3472,8 @@ + unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random; + PRBool isTLS = (PRBool)(kea_def->tls_keygen || + (pwSpec->version > SSL_LIBRARY_VERSION_3_0)); ++ PRBool isTLS12= ++ (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + /* following variables used in PKCS11 path */ + const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def; + PK11SlotInfo * slot = NULL; +@@ -3423,7 +3531,9 @@ + params.data = (unsigned char *)&key_material_params; + params.len = sizeof(key_material_params); + +- if (isTLS) { ++ if (isTLS12) { ++ key_derive = CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256; ++ } else if (isTLS) { + key_derive = CKM_TLS_KEY_AND_MAC_DERIVE; + } else { + key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE; +@@ -3480,19 +3590,63 @@ + return SECFailure; + } + ++/* ssl3_InitTLS12HandshakeHash creates a handshake hash context for TLS 1.2, ++ * if needed, and hashes in any buffered messages in ss->ssl3.hs.messages. */ ++static SECStatus ++ssl3_InitTLS12HandshakeHash(sslSocket *ss) ++{ ++ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2 && ++ ss->ssl3.hs.tls12_handshake_hash == NULL) { ++ /* If we ever support ciphersuites where the PRF hash isn't SHA-256 ++ * then this will need to be updated. */ ++ ss->ssl3.hs.tls12_handshake_hash = ++ PK11_CreateDigestContext(SEC_OID_SHA256); ++ if (!ss->ssl3.hs.tls12_handshake_hash || ++ PK11_DigestBegin(ss->ssl3.hs.tls12_handshake_hash) != SECSuccess) { ++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); ++ return SECFailure; ++ } ++ } ++ ++ if (ss->ssl3.hs.tls12_handshake_hash && ss->ssl3.hs.messages.len > 0) { ++ if (PK11_DigestOp(ss->ssl3.hs.tls12_handshake_hash, ++ ss->ssl3.hs.messages.buf, ++ ss->ssl3.hs.messages.len) != SECSuccess) { ++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); ++ return SECFailure; ++ } ++ } ++ ++ if (ss->ssl3.hs.messages.buf && !ss->opt.bypassPKCS11) { ++ PORT_Free(ss->ssl3.hs.messages.buf); ++ ss->ssl3.hs.messages.buf = NULL; ++ ss->ssl3.hs.messages.len = 0; ++ ss->ssl3.hs.messages.space = 0; ++ } ++ ++ return SECSuccess; ++} ++ + static SECStatus + ssl3_RestartHandshakeHashes(sslSocket *ss) + { + SECStatus rv = SECSuccess; + ++ ss->ssl3.hs.messages.len = 0; + #ifndef NO_PKCS11_BYPASS + if (ss->opt.bypassPKCS11) { +- ss->ssl3.hs.messages.len = 0; + MD5_Begin((MD5Context *)ss->ssl3.hs.md5_cx); + SHA1_Begin((SHA1Context *)ss->ssl3.hs.sha_cx); + } else + #endif + { ++ if (ss->ssl3.hs.tls12_handshake_hash) { ++ rv = PK11_DigestBegin(ss->ssl3.hs.tls12_handshake_hash); ++ if (rv != SECSuccess) { ++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); ++ return rv; ++ } ++ } + rv = PK11_DigestBegin(ss->ssl3.hs.md5); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); +@@ -3519,25 +3673,21 @@ + * that the master secret will wind up in ... + */ + SSL_TRC(30,("%d: SSL3[%d]: start handshake hashes", SSL_GETPID(), ss->fd)); +-#ifndef NO_PKCS11_BYPASS +- if (ss->opt.bypassPKCS11) { +- PORT_Assert(!ss->ssl3.hs.messages.buf && !ss->ssl3.hs.messages.space); +- ss->ssl3.hs.messages.buf = NULL; +- ss->ssl3.hs.messages.space = 0; +- } else +-#endif +- { +- ss->ssl3.hs.md5 = md5 = PK11_CreateDigestContext(SEC_OID_MD5); +- ss->ssl3.hs.sha = sha = PK11_CreateDigestContext(SEC_OID_SHA1); +- if (md5 == NULL) { +- ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); +- goto loser; +- } +- if (sha == NULL) { +- ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); +- goto loser; +- } ++ PORT_Assert(!ss->ssl3.hs.messages.buf && !ss->ssl3.hs.messages.space); ++ ss->ssl3.hs.messages.buf = NULL; ++ ss->ssl3.hs.messages.space = 0; ++ ++ ss->ssl3.hs.md5 = md5 = PK11_CreateDigestContext(SEC_OID_MD5); ++ ss->ssl3.hs.sha = sha = PK11_CreateDigestContext(SEC_OID_SHA1); ++ ss->ssl3.hs.tls12_handshake_hash = NULL; ++ if (md5 == NULL) { ++ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); ++ goto loser; + } ++ if (sha == NULL) { ++ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); ++ goto loser; ++ } + if (SECSuccess == ssl3_RestartHandshakeHashes(ss)) { + return SECSuccess; + } +@@ -3574,6 +3724,17 @@ + + PRINT_BUF(90, (NULL, "MD5 & SHA handshake hash input:", b, l)); + ++ if ((ss->version == 0 || ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) && ++ !ss->opt.bypassPKCS11 && ++ ss->ssl3.hs.tls12_handshake_hash == NULL) { ++ /* For TLS 1.2 connections we need to buffer the handshake messages ++ * until we have established which PRF hash function to use. */ ++ rv = sslBuffer_Append(&ss->ssl3.hs.messages, b, l); ++ if (rv != SECSuccess) { ++ return rv; ++ } ++ } ++ + #ifndef NO_PKCS11_BYPASS + if (ss->opt.bypassPKCS11) { + MD5_Update((MD5Context *)ss->ssl3.hs.md5_cx, b, l); +@@ -3584,16 +3745,24 @@ + return rv; + } + #endif +- rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l); +- if (rv != SECSuccess) { +- ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); +- return rv; ++ if (ss->ssl3.hs.tls12_handshake_hash) { ++ rv = PK11_DigestOp(ss->ssl3.hs.tls12_handshake_hash, b, l); ++ if (rv != SECSuccess) { ++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); ++ return rv; ++ } ++ } else { ++ rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l); ++ if (rv != SECSuccess) { ++ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); ++ return rv; ++ } ++ rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l); ++ if (rv != SECSuccess) { ++ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); ++ return rv; ++ } + } +- rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l); +- if (rv != SECSuccess) { +- ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); +- return rv; +- } + return rv; + } + +@@ -3744,6 +3913,25 @@ + return rv; /* error code set by AppendHandshake, if applicable. */ + } + ++/* ssl3_AppendSignatureAndHashAlgorithm appends the serialisation of ++ * |sigAndHash| to the current handshake message. */ ++SECStatus ++ssl3_AppendSignatureAndHashAlgorithm( ++ sslSocket *ss, const SSL3SignatureAndHashAlgorithm* sigAndHash) ++{ ++ unsigned char serialized[2]; ++ ++ serialized[0] = ssl3_OIDToTLSHashAlgorithm(sigAndHash->hashAlg); ++ if (serialized[0] == 0) { ++ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); ++ return SECFailure; ++ } ++ ++ serialized[1] = sigAndHash->sigAlg; ++ ++ return ssl3_AppendHandshake(ss, serialized, sizeof(serialized)); ++} ++ + /************************************************************************** + * Consume Handshake functions. + * +@@ -3850,6 +4038,147 @@ + return SECSuccess; + } + ++/* tlsHashOIDMap contains the mapping between TLS hash identifiers and the ++ * SECOidTag used internally by NSS. */ ++static const struct { ++ int tlsHash; ++ SECOidTag oid; ++} tlsHashOIDMap[] = { ++ { tls_hash_md5, SEC_OID_MD5 }, ++ { tls_hash_sha1, SEC_OID_SHA1 }, ++ { tls_hash_sha224, SEC_OID_SHA224 }, ++ { tls_hash_sha256, SEC_OID_SHA256 }, ++ { tls_hash_sha384, SEC_OID_SHA384 }, ++ { tls_hash_sha512, SEC_OID_SHA512 } ++}; ++ ++/* ssl3_TLSHashAlgorithmToOID converts a TLS hash identifier into an OID value. ++ * If the hash is not recognised, SEC_OID_UNKNOWN is returned. ++ * ++ * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ ++SECOidTag ++ssl3_TLSHashAlgorithmToOID(int hashFunc) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < PR_ARRAY_SIZE(tlsHashOIDMap); i++) { ++ if (hashFunc == tlsHashOIDMap[i].tlsHash) { ++ return tlsHashOIDMap[i].oid; ++ } ++ } ++ return SEC_OID_UNKNOWN; ++} ++ ++/* ssl3_OIDToTLSHashAlgorithm converts an OID to a TLS hash algorithm ++ * identifier. If the hash is not recognised, zero is returned. ++ * ++ * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ ++static int ++ssl3_OIDToTLSHashAlgorithm(SECOidTag oid) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < PR_ARRAY_SIZE(tlsHashOIDMap); i++) { ++ if (oid == tlsHashOIDMap[i].oid) { ++ return tlsHashOIDMap[i].tlsHash; ++ } ++ } ++ return 0; ++} ++ ++/* ssl3_TLSSignatureAlgorithmForKeyType returns the TLS 1.2 signature algorithm ++ * identifier for a given KeyType. */ ++static SECStatus ++ssl3_TLSSignatureAlgorithmForKeyType(KeyType keyType, ++ TLSSignatureAlgorithm *out) ++{ ++ switch (keyType) { ++ case rsaKey: ++ *out = tls_sig_rsa; ++ return SECSuccess; ++ case dsaKey: ++ *out = tls_sig_dsa; ++ return SECSuccess; ++ case ecKey: ++ *out = tls_sig_ecdsa; ++ return SECSuccess; ++ default: ++ PORT_SetError(SEC_ERROR_INVALID_KEY); ++ return SECFailure; ++ } ++} ++ ++/* ssl3_TLSSignatureAlgorithmForCertificate returns the TLS 1.2 signature ++ * algorithm identifier for the given certificate. */ ++static SECStatus ++ssl3_TLSSignatureAlgorithmForCertificate(CERTCertificate *cert, ++ TLSSignatureAlgorithm *out) ++{ ++ SECKEYPublicKey *key; ++ KeyType keyType; ++ ++ key = CERT_ExtractPublicKey(cert); ++ if (key == NULL) { ++ ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); ++ return SECFailure; ++ } ++ ++ keyType = key->keyType; ++ SECKEY_DestroyPublicKey(key); ++ return ssl3_TLSSignatureAlgorithmForKeyType(keyType, out); ++} ++ ++/* ssl3_CheckSignatureAndHashAlgorithmConsistency checks that the signature ++ * algorithm identifier in |sigAndHash| is consistent with the public key in ++ * |cert|. If so, SECSuccess is returned. Otherwise, PORT_SetError is called ++ * and SECFailure is returned. */ ++SECStatus ++ssl3_CheckSignatureAndHashAlgorithmConsistency( ++ const SSL3SignatureAndHashAlgorithm *sigAndHash, CERTCertificate* cert) ++{ ++ SECStatus rv; ++ TLSSignatureAlgorithm sigAlg; ++ ++ rv = ssl3_TLSSignatureAlgorithmForCertificate(cert, &sigAlg); ++ if (rv != SECSuccess) { ++ return rv; ++ } ++ if (sigAlg != sigAndHash->sigAlg) { ++ PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); ++ return SECFailure; ++ } ++ return SECSuccess; ++} ++ ++/* ssl3_ConsumeSignatureAndHashAlgorithm reads a SignatureAndHashAlgorithm ++ * structure from |b| and puts the resulting value into |out|. |b| and |length| ++ * are updated accordingly. ++ * ++ * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ ++SECStatus ++ssl3_ConsumeSignatureAndHashAlgorithm(sslSocket *ss, ++ SSL3Opaque **b, ++ PRUint32 *length, ++ SSL3SignatureAndHashAlgorithm *out) ++{ ++ unsigned char bytes[2]; ++ SECStatus rv; ++ ++ rv = ssl3_ConsumeHandshake(ss, bytes, sizeof(bytes), b, length); ++ if (rv != SECSuccess) { ++ return rv; ++ } ++ ++ out->hashAlg = ssl3_TLSHashAlgorithmToOID(bytes[0]); ++ if (out->hashAlg == SEC_OID_UNKNOWN) { ++ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); ++ return SECFailure; ++ } ++ ++ out->sigAlg = bytes[1]; ++ return SECSuccess; ++} ++ + /************************************************************************** + * end of Consume Handshake functions. + **************************************************************************/ +@@ -3876,6 +4205,7 @@ + SSL3Opaque sha_inner[MAX_MAC_LENGTH]; + + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); ++ hashes->hashAlg = SEC_OID_UNKNOWN; + + #ifndef NO_PKCS11_BYPASS + if (ss->opt.bypassPKCS11) { +@@ -3939,9 +4269,9 @@ + MD5_Update(md5cx, mac_pad_2, mac_defs[mac_md5].pad_size); + MD5_Update(md5cx, md5_inner, MD5_LENGTH); + } +- MD5_End(md5cx, hashes->md5, &outLength, MD5_LENGTH); ++ MD5_End(md5cx, hashes->u.s.md5, &outLength, MD5_LENGTH); + +- PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->md5, MD5_LENGTH)); ++ PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH)); + + if (!isTLS) { + PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, +@@ -3953,16 +4283,58 @@ + SHA1_Update(shacx, mac_pad_2, mac_defs[mac_sha].pad_size); + SHA1_Update(shacx, sha_inner, SHA1_LENGTH); + } +- SHA1_End(shacx, hashes->sha, &outLength, SHA1_LENGTH); ++ SHA1_End(shacx, hashes->u.s.sha, &outLength, SHA1_LENGTH); + +- PRINT_BUF(60, (NULL, "SHA outer: result", hashes->sha, SHA1_LENGTH)); ++ PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH)); + ++ hashes->len = MD5_LENGTH + SHA1_LENGTH; + rv = SECSuccess; + #undef md5cx + #undef shacx + } else + #endif +- { ++ if (ss->ssl3.hs.tls12_handshake_hash) { ++ PK11Context *h; ++ unsigned int stateLen; ++ unsigned char stackBuf[1024]; ++ unsigned char *stateBuf = NULL; ++ ++ if (!spec->master_secret) { ++ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE); ++ return SECFailure; ++ } ++ ++ h = ss->ssl3.hs.tls12_handshake_hash; ++ stateBuf = PK11_SaveContextAlloc(h, stackBuf, ++ sizeof(stackBuf), &stateLen); ++ if (stateBuf == NULL) { ++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); ++ goto tls12_loser; ++ } ++ rv |= PK11_DigestFinal(h, hashes->u.raw, &hashes->len, ++ sizeof(hashes->u.raw)); ++ if (rv != SECSuccess) { ++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); ++ rv = SECFailure; ++ goto tls12_loser; ++ } ++ /* If we ever support ciphersuites where the PRF hash isn't SHA-256 ++ * then this will need to be updated. */ ++ hashes->hashAlg = SEC_OID_SHA256; ++ rv = SECSuccess; ++ ++tls12_loser: ++ if (stateBuf) { ++ if (PK11_RestoreContext(ss->ssl3.hs.tls12_handshake_hash, stateBuf, ++ stateLen) != SECSuccess) { ++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); ++ rv = SECFailure; ++ } ++ if (stateBuf != stackBuf) { ++ PORT_ZFree(stateBuf, stateLen); ++ } ++ } ++ } else { + /* compute hases with PKCS11 */ + PK11Context * md5; + PK11Context * sha = NULL; +@@ -4051,7 +4423,7 @@ + rv |= PK11_DigestOp(md5, mac_pad_2, mac_defs[mac_md5].pad_size); + rv |= PK11_DigestOp(md5, md5_inner, MD5_LENGTH); + } +- rv |= PK11_DigestFinal(md5, hashes->md5, &outLength, MD5_LENGTH); ++ rv |= PK11_DigestFinal(md5, hashes->u.s.md5, &outLength, MD5_LENGTH); + PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); +@@ -4059,7 +4431,7 @@ + goto loser; + } + +- PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->md5, MD5_LENGTH)); ++ PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH)); + + if (!isTLS) { + PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, +@@ -4071,7 +4443,7 @@ + rv |= PK11_DigestOp(sha, mac_pad_2, mac_defs[mac_sha].pad_size); + rv |= PK11_DigestOp(sha, sha_inner, SHA1_LENGTH); + } +- rv |= PK11_DigestFinal(sha, hashes->sha, &outLength, SHA1_LENGTH); ++ rv |= PK11_DigestFinal(sha, hashes->u.s.sha, &outLength, SHA1_LENGTH); + PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); +@@ -4079,8 +4451,9 @@ + goto loser; + } + +- PRINT_BUF(60, (NULL, "SHA outer: result", hashes->sha, SHA1_LENGTH)); ++ PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH)); + ++ hashes->len = MD5_LENGTH + SHA1_LENGTH; + rv = SECSuccess; + + loser: +@@ -5343,8 +5716,12 @@ + { + SECStatus rv = SECFailure; + PRBool isTLS; ++ PRBool isTLS12; + SECItem buf = {siBuffer, NULL, 0}; + SSL3Hashes hashes; ++ KeyType keyType; ++ unsigned int len; ++ SSL3SignatureAndHashAlgorithm sigAndHash; + + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); +@@ -5393,10 +5772,30 @@ + goto done; /* err code was set by ssl3_SignHashes */ + } + +- rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, buf.len + 2); ++ len = buf.len + 2 + (isTLS12 ? 2 : 0); ++ ++ rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len); + if (rv != SECSuccess) { + goto done; /* error code set by AppendHandshake */ + } ++ if (isTLS12) { ++ rv = ssl3_TLSSignatureAlgorithmForKeyType(keyType, ++ &sigAndHash.sigAlg); ++ if (rv != SECSuccess) { ++ goto done; ++ } ++ /* We always sign using the handshake hash function. It's possible that ++ * a server could support SHA-256 as the handshake hash but not as a ++ * signature hash. In that case we wouldn't be able to do client ++ * certificates with it. The alternative is to buffer all handshake ++ * messages. */ ++ sigAndHash.hashAlg = hashes.hashAlg; ++ ++ rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash); ++ if (rv != SECSuccess) { ++ goto done; /* err set by AppendHandshake. */ ++ } ++ } + rv = ssl3_AppendHandshakeVariable(ss, buf.data, buf.len, 2); + if (rv != SECSuccess) { + goto done; /* error code set by AppendHandshake */ +@@ -5504,6 +5903,13 @@ + } + isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0); + ++ rv = ssl3_InitTLS12HandshakeHash(ss); ++ if (rv != SECSuccess) { ++ desc = internal_error; ++ errCode = PORT_GetError(); ++ goto alert_loser; ++ } ++ + rv = ssl3_ConsumeHandshake( + ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length); + if (rv != SECSuccess) { +@@ -5834,13 +6240,16 @@ + { + PRArenaPool * arena = NULL; + SECKEYPublicKey *peerKey = NULL; +- PRBool isTLS; ++ PRBool isTLS, isTLS12; + SECStatus rv; + int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; + SSL3AlertDescription desc = illegal_parameter; + SSL3Hashes hashes; + SECItem signature = {siBuffer, NULL, 0}; ++ SSL3SignatureAndHashAlgorithm sigAndHash; + ++ sigAndHash.hashAlg = SEC_OID_UNKNOWN; ++ + SSL_TRC(3, ("%d: SSL3[%d]: handle server_key_exchange handshake", + SSL_GETPID(), ss->fd)); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); +@@ -5859,6 +6268,7 @@ + } + + isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); ++ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + + switch (ss->ssl3.hs.kea_def->exchKeyType) { + +@@ -5874,6 +6284,18 @@ + if (rv != SECSuccess) { + goto loser; /* malformed. */ + } ++ if (isTLS12) { ++ rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, ++ &sigAndHash); ++ if (rv != SECSuccess) { ++ goto loser; /* malformed or unsupported. */ ++ } ++ rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( ++ &sigAndHash, ss->sec.peerCert); ++ if (rv != SECSuccess) { ++ goto loser; ++ } ++ } + rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed. */ +@@ -5891,7 +6313,7 @@ + /* + * check to make sure the hash is signed by right guy + */ +- rv = ssl3_ComputeExportRSAKeyHash(modulus, exponent, ++ rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg, modulus, exponent, + &ss->ssl3.hs.client_random, + &ss->ssl3.hs.server_random, + &hashes, ss->opt.bypassPKCS11); +@@ -5964,6 +6386,18 @@ + } + if (dh_Ys.len > dh_p.len || !ssl3_BigIntGreaterThanOne(&dh_Ys)) + goto alert_loser; ++ if (isTLS12) { ++ rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, ++ &sigAndHash); ++ if (rv != SECSuccess) { ++ goto loser; /* malformed or unsupported. */ ++ } ++ rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( ++ &sigAndHash, ss->sec.peerCert); ++ if (rv != SECSuccess) { ++ goto loser; ++ } ++ } + rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed. */ +@@ -5985,7 +6419,7 @@ + /* + * check to make sure the hash is signed by right guy + */ +- rv = ssl3_ComputeDHKeyHash(dh_p, dh_g, dh_Ys, ++ rv = ssl3_ComputeDHKeyHash(sigAndHash.hashAlg, dh_p, dh_g, dh_Ys, + &ss->ssl3.hs.client_random, + &ss->ssl3.hs.server_random, + &hashes, ss->opt.bypassPKCS11); +@@ -6862,6 +7296,13 @@ + goto alert_loser; + } + ++ rv = ssl3_InitTLS12HandshakeHash(ss); ++ if (rv != SECSuccess) { ++ desc = internal_error; ++ errCode = PORT_GetError(); ++ goto alert_loser; ++ } ++ + /* grab the client random data. */ + rv = ssl3_ConsumeHandshake( + ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length); +@@ -7604,6 +8045,13 @@ + goto alert_loser; + } + ++ rv = ssl3_InitTLS12HandshakeHash(ss); ++ if (rv != SECSuccess) { ++ desc = internal_error; ++ errCode = PORT_GetError(); ++ goto alert_loser; ++ } ++ + /* if we get a non-zero SID, just ignore it. */ + if (length != + SSL_HL_CLIENT_HELLO_HBYTES + suite_length + sid_length + rand_length) { +@@ -7851,7 +8299,86 @@ + return SECSuccess; + } + ++/* ssl3_PickSignatureHashAlgorithm selects a hash algorithm to use when signing ++ * elements of the handshake. (The negotiated cipher suite determines the ++ * signature algorithm.) Prior to TLS 1.2, the MD5/SHA1 combination is always ++ * used. With TLS 1.2, a client may advertise its support for signature and ++ * hash combinations. */ ++static SECStatus ++ssl3_PickSignatureHashAlgorithm(sslSocket *ss, ++ SSL3SignatureAndHashAlgorithm* out) ++{ ++ TLSSignatureAlgorithm sigAlg; ++ unsigned int i, j; ++ /* hashPreference expresses our preferences for hash algorithms, most ++ * preferable first. */ ++ static const PRUint8 hashPreference[] = { ++ tls_hash_sha256, ++ tls_hash_sha384, ++ tls_hash_sha512, ++ tls_hash_sha1, ++ }; + ++ switch (ss->ssl3.hs.kea_def->kea) { ++ case kea_rsa: ++ case kea_rsa_export: ++ case kea_rsa_export_1024: ++ case kea_dh_rsa: ++ case kea_dh_rsa_export: ++ case kea_dhe_rsa: ++ case kea_dhe_rsa_export: ++ case kea_rsa_fips: ++ case kea_ecdh_rsa: ++ case kea_ecdhe_rsa: ++ sigAlg = tls_sig_rsa; ++ break; ++ case kea_dh_dss: ++ case kea_dh_dss_export: ++ case kea_dhe_dss: ++ case kea_dhe_dss_export: ++ sigAlg = tls_sig_dsa; ++ break; ++ case kea_ecdh_ecdsa: ++ case kea_ecdhe_ecdsa: ++ sigAlg = tls_sig_ecdsa; ++ break; ++ default: ++ PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); ++ return SECFailure; ++ } ++ out->sigAlg = sigAlg; ++ ++ if (ss->version <= SSL_LIBRARY_VERSION_TLS_1_1) { ++ /* SEC_OID_UNKNOWN means the MD5/SHA1 combo hash used in TLS 1.1 and ++ * prior. */ ++ out->hashAlg = SEC_OID_UNKNOWN; ++ return SECSuccess; ++ } ++ ++ if (ss->ssl3.hs.numClientSigAndHash == 0) { ++ /* If the client didn't provide any signature_algorithms extension then ++ * we can assume that they support SHA-1: ++ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ ++ out->hashAlg = SEC_OID_SHA1; ++ return SECSuccess; ++ } ++ ++ for (i = 0; i < PR_ARRAY_SIZE(hashPreference); i++) { ++ for (j = 0; j < ss->ssl3.hs.numClientSigAndHash; j++) { ++ const SSL3SignatureAndHashAlgorithm* sh = ++ &ss->ssl3.hs.clientSigAndHash[j]; ++ if (sh->sigAlg == sigAlg && sh->hashAlg == hashPreference[i]) { ++ out->hashAlg = sh->hashAlg; ++ return SECSuccess; ++ } ++ } ++ } ++ ++ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); ++ return SECFailure; ++} ++ ++ + static SECStatus + ssl3_SendServerKeyExchange(sslSocket *ss) + { +@@ -7862,6 +8389,7 @@ + SECItem signed_hash = {siBuffer, NULL, 0}; + SSL3Hashes hashes; + SECKEYPublicKey * sdPub; /* public key for step-down */ ++ SSL3SignatureAndHashAlgorithm sigAndHash; + + SSL_TRC(3, ("%d: SSL3[%d]: send server_key_exchange handshake", + SSL_GETPID(), ss->fd)); +@@ -7869,6 +8397,10 @@ + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + ++ if (ssl3_PickSignatureHashAlgorithm(ss, &sigAndHash) != SECSuccess) { ++ return SECFailure; ++ } ++ + switch (kea_def->exchKeyType) { + case kt_rsa: + /* Perform SSL Step-Down here. */ +@@ -7878,7 +8410,8 @@ + PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); + return SECFailure; + } +- rv = ssl3_ComputeExportRSAKeyHash(sdPub->u.rsa.modulus, ++ rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg, ++ sdPub->u.rsa.modulus, + sdPub->u.rsa.publicExponent, + &ss->ssl3.hs.client_random, + &ss->ssl3.hs.server_random, +@@ -7921,6 +8454,13 @@ + goto loser; /* err set by AppendHandshake. */ + } + ++ if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { ++ rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash); ++ if (rv != SECSuccess) { ++ goto loser; /* err set by AppendHandshake. */ ++ } ++ } ++ + rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, + signed_hash.len, 2); + if (rv != SECSuccess) { +@@ -7931,7 +8471,7 @@ + + #ifdef NSS_ENABLE_ECC + case kt_ecdh: { +- rv = ssl3_SendECDHServerKeyExchange(ss); ++ rv = ssl3_SendECDHServerKeyExchange(ss, &sigAndHash); + return rv; + } + #endif /* NSS_ENABLE_ECC */ +@@ -8045,26 +8585,51 @@ + SECStatus rv; + int errCode = SSL_ERROR_RX_MALFORMED_CERT_VERIFY; + SSL3AlertDescription desc = handshake_failure; +- PRBool isTLS; ++ PRBool isTLS, isTLS12; ++ SSL3SignatureAndHashAlgorithm sigAndHash; + + SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake", + SSL_GETPID(), ss->fd)); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); + ++ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); ++ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); ++ + if (ss->ssl3.hs.ws != wait_cert_verify || ss->sec.peerCert == NULL) { + desc = unexpected_message; + errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY; + goto alert_loser; + } + ++ if (isTLS12) { ++ rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, ++ &sigAndHash); ++ if (rv != SECSuccess) { ++ goto loser; /* malformed or unsupported. */ ++ } ++ rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( ++ &sigAndHash, ss->sec.peerCert); ++ if (rv != SECSuccess) { ++ errCode = PORT_GetError(); ++ desc = decrypt_error; ++ goto alert_loser; ++ } ++ ++ /* We only support CertificateVerify messages that use the handshake ++ * hash. */ ++ if (sigAndHash.hashAlg != hashes->hashAlg) { ++ errCode = SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM; ++ desc = decrypt_error; ++ goto alert_loser; ++ } ++ } ++ + rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed. */ + } + +- isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); +- + /* XXX verify that the key & kea match */ + rv = ssl3_VerifySignedHashes(hashes, ss->sec.peerCert, &signed_hash, + isTLS, ss->pkcs11PinArg); +@@ -9163,7 +9728,7 @@ + static SECStatus + ssl3_ComputeTLSFinished(ssl3CipherSpec *spec, + PRBool isServer, +- const SSL3Finished * hashes, ++ const SSL3Hashes * hashes, + TLSFinished * tlsFinished) + { + const char * label; +@@ -9173,8 +9738,8 @@ + label = isServer ? "server finished" : "client finished"; + len = 15; + +- rv = ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->md5, +- sizeof *hashes, tlsFinished->verify_data, ++ rv = ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->u.raw, ++ hashes->len, tlsFinished->verify_data, + sizeof tlsFinished->verify_data); + + return rv; +@@ -9192,12 +9757,16 @@ + SECStatus rv = SECSuccess; + + if (spec->master_secret && !spec->bypassCiphers) { +- SECItem param = {siBuffer, NULL, 0}; +- PK11Context *prf_context = +- PK11_CreateContextBySymKey(CKM_TLS_PRF_GENERAL, CKA_SIGN, +- spec->master_secret, ¶m); ++ SECItem param = {siBuffer, NULL, 0}; ++ CK_MECHANISM_TYPE mech = CKM_TLS_PRF_GENERAL; ++ PK11Context *prf_context; + unsigned int retLen; + ++ if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { ++ mech = CKM_NSS_TLS_PRF_GENERAL_SHA256; ++ } ++ prf_context = PK11_CreateContextBySymKey(mech, CKA_SIGN, ++ spec->master_secret, ¶m); + if (!prf_context) + return SECFailure; + +@@ -9496,7 +10066,7 @@ + PRBool isServer = ss->sec.isServer; + SECStatus rv; + SSL3Sender sender = isServer ? sender_server : sender_client; +- SSL3Finished hashes; ++ SSL3Hashes hashes; + TLSFinished tlsFinished; + + SSL_TRC(3, ("%d: SSL3[%d]: send finished handshake", SSL_GETPID(), ss->fd)); +@@ -9530,14 +10100,15 @@ + goto fail; /* err set by AppendHandshake. */ + } else { + if (isServer) +- ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes; ++ ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes.u.s; + else +- ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes; +- ss->ssl3.hs.finishedBytes = sizeof hashes; +- rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes); ++ ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes.u.s; ++ PORT_Assert(hashes.len == sizeof hashes.u.s); ++ ss->ssl3.hs.finishedBytes = sizeof hashes.u.s; ++ rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes.u.s); + if (rv != SECSuccess) + goto fail; /* err set by AppendHandshake. */ +- rv = ssl3_AppendHandshake(ss, &hashes, sizeof hashes); ++ rv = ssl3_AppendHandshake(ss, &hashes.u.s, sizeof hashes.u.s); + if (rv != SECSuccess) + goto fail; /* err set by AppendHandshake. */ + } +@@ -9686,18 +10257,19 @@ + return SECFailure; + } + } else { +- if (length != sizeof(SSL3Hashes)) { ++ if (length != sizeof(SSL3Finished)) { + (void)ssl3_IllegalParameter(ss); + PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED); + return SECFailure; + } + + if (!isServer) +- ss->ssl3.hs.finishedMsgs.sFinished[1] = *hashes; ++ ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes->u.s; + else +- ss->ssl3.hs.finishedMsgs.sFinished[0] = *hashes; +- ss->ssl3.hs.finishedBytes = sizeof *hashes; +- if (0 != NSS_SecureMemcmp(hashes, b, length)) { ++ ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes->u.s; ++ PORT_Assert(hashes->len == sizeof hashes->u.s); ++ ss->ssl3.hs.finishedBytes = sizeof hashes->u.s; ++ if (0 != NSS_SecureMemcmp(&hashes->u.s, b, length)) { + (void)ssl3_HandshakeFailure(ss); + PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); + return SECFailure; +@@ -11286,6 +11858,12 @@ + if (ss->ssl3.hs.sha) { + PK11_DestroyContext(ss->ssl3.hs.sha,PR_TRUE); + } ++ if (ss->ssl3.hs.tls12_handshake_hash) { ++ PK11_DestroyContext(ss->ssl3.hs.tls12_handshake_hash,PR_TRUE); ++ } ++ if (ss->ssl3.hs.clientSigAndHash) { ++ PORT_Free(ss->ssl3.hs.clientSigAndHash); ++ } + if (ss->ssl3.hs.messages.buf) { + PORT_Free(ss->ssl3.hs.messages.buf); + ss->ssl3.hs.messages.buf = NULL; diff --git a/net/third_party/nss/patches/tls12chromium.patch b/net/third_party/nss/patches/tls12chromium.patch new file mode 100644 index 0000000..217111b --- /dev/null +++ b/net/third_party/nss/patches/tls12chromium.patch @@ -0,0 +1,317 @@ +Index: net/third_party/nss/ssl/sslplatf.c +=================================================================== +--- net/third_party/nss/ssl/sslplatf.c (revision 202696) ++++ net/third_party/nss/ssl/sslplatf.c (working copy) +@@ -212,9 +212,8 @@ + DWORD dwFlags = 0; + VOID *pPaddingInfo = NULL; + +- /* Always encode using PKCS#1 block type, with no OID/encoded DigestInfo */ ++ /* Always encode using PKCS#1 block type. */ + BCRYPT_PKCS1_PADDING_INFO rsaPaddingInfo; +- rsaPaddingInfo.pszAlgId = NULL; + + if (key->dwKeySpec != CERT_NCRYPT_KEY_SPEC) { + PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); +@@ -227,8 +226,29 @@ + + switch (keyType) { + case rsaKey: +- hashItem.data = hash->md5; +- hashItem.len = sizeof(SSL3Hashes); ++ switch (hash->hashAlg) { ++ case SEC_OID_UNKNOWN: ++ /* No OID/encoded DigestInfo. */ ++ rsaPaddingInfo.pszAlgId = NULL; ++ break; ++ case SEC_OID_SHA1: ++ rsaPaddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM; ++ break; ++ case SEC_OID_SHA256: ++ rsaPaddingInfo.pszAlgId = BCRYPT_SHA256_ALGORITHM; ++ break; ++ case SEC_OID_SHA384: ++ rsaPaddingInfo.pszAlgId = BCRYPT_SHA384_ALGORITHM; ++ break; ++ case SEC_OID_SHA512: ++ rsaPaddingInfo.pszAlgId = BCRYPT_SHA512_ALGORITHM; ++ break; ++ default: ++ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); ++ return SECFailure; ++ } ++ hashItem.data = hash->u.raw; ++ hashItem.len = hash->len; + dwFlags = BCRYPT_PAD_PKCS1; + pPaddingInfo = &rsaPaddingInfo; + break; +@@ -239,8 +259,13 @@ + } else { + doDerEncode = isTLS; + } +- hashItem.data = hash->sha; +- hashItem.len = sizeof(hash->sha); ++ if (hash->hashAlg == SEC_OID_UNKNOWN) { ++ hashItem.data = hash->u.s.sha; ++ hashItem.len = sizeof(hash->u.s.sha); ++ } else { ++ hashItem.data = hash->u.raw; ++ hashItem.len = hash->len; ++ } + break; + default: + PORT_SetError(SEC_ERROR_INVALID_KEY); +@@ -315,11 +340,34 @@ + + buf->data = NULL; + ++ switch (hash->hashAlg) { ++ case SEC_OID_UNKNOWN: ++ hashAlg = 0; ++ break; ++ case SEC_OID_SHA1: ++ hashAlg = CALG_SHA1; ++ break; ++ case SEC_OID_SHA256: ++ hashAlg = CALG_SHA_256; ++ break; ++ case SEC_OID_SHA384: ++ hashAlg = CALG_SHA_384; ++ break; ++ case SEC_OID_SHA512: ++ hashAlg = CALG_SHA_512; ++ break; ++ default: ++ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); ++ return SECFailure; ++ } ++ + switch (keyType) { + case rsaKey: +- hashAlg = CALG_SSL3_SHAMD5; +- hashItem.data = hash->md5; +- hashItem.len = sizeof(SSL3Hashes); ++ if (hashAlg == 0) { ++ hashAlg = CALG_SSL3_SHAMD5; ++ } ++ hashItem.data = hash->u.raw; ++ hashItem.len = hash->len; + break; + case dsaKey: + case ecKey: +@@ -328,9 +376,14 @@ + } else { + doDerEncode = isTLS; + } +- hashAlg = CALG_SHA1; +- hashItem.data = hash->sha; +- hashItem.len = sizeof(hash->sha); ++ if (hashAlg == 0) { ++ hashAlg = CALG_SHA1; ++ hashItem.data = hash->u.s.sha; ++ hashItem.len = sizeof(hash->u.s.sha); ++ } else { ++ hashItem.data = hash->u.raw; ++ hashItem.len = hash->len; ++ } + break; + default: + PORT_SetError(SEC_ERROR_INVALID_KEY); +@@ -468,11 +521,36 @@ + goto done; /* error code was set. */ + + sigAlg = cssmKey->KeyHeader.AlgorithmId; ++ if (keyType == rsaKey) { ++ PORT_Assert(sigAlg == CSSM_ALGID_RSA); ++ switch (hash->hashAlg) { ++ case SEC_OID_UNKNOWN: ++ break; ++ case SEC_OID_SHA1: ++ sigAlg = CSSM_ALGID_SHA1WithRSA; ++ break; ++ case SEC_OID_SHA224: ++ sigAlg = CSSM_ALGID_SHA224WithRSA; ++ break; ++ case SEC_OID_SHA256: ++ sigAlg = CSSM_ALGID_SHA256WithRSA; ++ break; ++ case SEC_OID_SHA384: ++ sigAlg = CSSM_ALGID_SHA384WithRSA; ++ break; ++ case SEC_OID_SHA512: ++ sigAlg = CSSM_ALGID_SHA512WithRSA; ++ break; ++ default: ++ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); ++ goto done; ++ } ++ } ++ + switch (keyType) { + case rsaKey: +- PORT_Assert(sigAlg == CSSM_ALGID_RSA); +- hashData.Data = hash->md5; +- hashData.Length = sizeof(SSL3Hashes); ++ hashData.Data = hash->u.raw; ++ hashData.Length = hash->len; + break; + case dsaKey: + case ecKey: +@@ -483,8 +561,13 @@ + PORT_Assert(sigAlg == CSSM_ALGID_DSA); + doDerEncode = isTLS; + } +- hashData.Data = hash->sha; +- hashData.Length = sizeof(hash->sha); ++ if (hash->hashAlg == SEC_OID_UNKNOWN) { ++ hashData.Data = hash->u.s.sha; ++ hashData.Length = sizeof(hash->u.s.sha); ++ } else { ++ hashData.Data = hash->u.raw; ++ hashData.Length = hash->len; ++ } + break; + default: + PORT_SetError(SEC_ERROR_INVALID_KEY); +Index: net/third_party/nss/ssl/ssl3ecc.c +=================================================================== +--- net/third_party/nss/ssl/ssl3ecc.c (revision 202696) ++++ net/third_party/nss/ssl/ssl3ecc.c (working copy) +@@ -31,6 +31,12 @@ + + #include <stdio.h> + ++/* This is a bodge to allow this code to be compiled against older NSS headers ++ * that don't contain the TLS 1.2 changes. */ ++#ifndef CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 ++#define CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 (CKM_NSS + 24) ++#endif ++ + #ifdef NSS_ENABLE_ECC + + /* +Index: net/third_party/nss/ssl/sslsock.c +=================================================================== +--- net/third_party/nss/ssl/sslsock.c (revision 202696) ++++ net/third_party/nss/ssl/sslsock.c (working copy) +@@ -18,8 +18,15 @@ + #ifndef NO_PKCS11_BYPASS + #include "blapi.h" + #endif ++#include "pk11pub.h" + #include "nss.h" + ++/* This is a bodge to allow this code to be compiled against older NSS headers ++ * that don't contain the TLS 1.2 changes. */ ++#ifndef CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 ++#define CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 (CKM_NSS + 24) ++#endif ++ + #define SET_ERROR_CODE /* reminder */ + + struct cipherPolicyStr { +@@ -1895,6 +1913,24 @@ + return SECSuccess; + } + ++static PRCallOnceType checkTLS12TokenOnce; ++static PRBool tls12TokenExists; ++ ++static PRStatus ++ssl_CheckTLS12Token(void) ++{ ++ tls12TokenExists = ++ PK11_TokenExists(CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256); ++ return PR_SUCCESS; ++} ++ ++static PRBool ++ssl_TLS12TokenExists(void) ++{ ++ (void) PR_CallOnce(&checkTLS12TokenOnce, ssl_CheckTLS12Token); ++ return tls12TokenExists; ++} ++ + SECStatus + SSL_VersionRangeSet(PRFileDesc *fd, const SSLVersionRange *vrange) + { +@@ -1915,6 +1951,24 @@ + ssl_GetSSL3HandshakeLock(ss); + + ss->vrange = *vrange; ++ /* If we don't have a sufficiently up-to-date softoken then we cannot do ++ * TLS 1.2. */ ++ if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_2 && ++ !ssl_TLS12TokenExists()) { ++ /* If the user requested a minimum version of 1.2, then we don't ++ * silently downgrade. */ ++ if (ss->vrange.min >= SSL_LIBRARY_VERSION_TLS_1_2) { ++ ssl_ReleaseSSL3HandshakeLock(ss); ++ ssl_Release1stHandshakeLock(ss); ++ PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE); ++ return SECFailure; ++ } ++ ss->vrange.max = SSL_LIBRARY_VERSION_TLS_1_1; ++ } ++ /* PKCS#11 bypass is not supported with TLS 1.2. */ ++ if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_2) { ++ ss->opt.bypassPKCS11 = PR_FALSE; ++ } + + ssl_ReleaseSSL3HandshakeLock(ss); + ssl_Release1stHandshakeLock(ss); +Index: net/third_party/nss/ssl/ssl3con.c +=================================================================== +--- net/third_party/nss/ssl/ssl3con.c (revision 202696) ++++ net/third_party/nss/ssl/ssl3con.c (working copy) +@@ -31,6 +32,15 @@ + #include "blapi.h" + #endif + ++/* This is a bodge to allow this code to be compiled against older NSS headers ++ * that don't contain the TLS 1.2 changes. */ ++#ifndef CKM_NSS_TLS_PRF_GENERAL_SHA256 ++#define CKM_NSS_TLS_PRF_GENERAL_SHA256 (CKM_NSS + 21) ++#define CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256 (CKM_NSS + 22) ++#define CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256 (CKM_NSS + 23) ++#define CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 (CKM_NSS + 24) ++#endif ++ + #include <stdio.h> + #ifdef NSS_ENABLE_ZLIB + #include "zlib.h" +@@ -5360,16 +5737,18 @@ + } + + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); ++ isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + if (ss->ssl3.platformClientKey) { + #ifdef NSS_PLATFORM_CLIENT_AUTH ++ keyType = CERT_GetCertKeyType( ++ &ss->ssl3.clientCertificate->subjectPublicKeyInfo); + rv = ssl3_PlatformSignHashes( +- &hashes, ss->ssl3.platformClientKey, &buf, isTLS, +- CERT_GetCertKeyType( +- &ss->ssl3.clientCertificate->subjectPublicKeyInfo)); ++ &hashes, ss->ssl3.platformClientKey, &buf, isTLS, keyType); + ssl_FreePlatformKey(ss->ssl3.platformClientKey); + ss->ssl3.platformClientKey = (PlatformKey)NULL; + #endif /* NSS_PLATFORM_CLIENT_AUTH */ + } else { ++ keyType = ss->ssl3.clientPrivateKey->keyType; + rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS); + if (rv == SECSuccess) { + PK11SlotInfo * slot; +@@ -9409,9 +9978,10 @@ + pub_bytes = spki->data + sizeof(P256_SPKI_PREFIX); + + memcpy(signed_data, CHANNEL_ID_MAGIC, sizeof(CHANNEL_ID_MAGIC)); +- memcpy(signed_data + sizeof(CHANNEL_ID_MAGIC), &hashes, sizeof(hashes)); ++ memcpy(signed_data + sizeof(CHANNEL_ID_MAGIC), hashes.u.raw, hashes.len); + +- rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, sizeof(signed_data)); ++ rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, ++ sizeof(CHANNEL_ID_MAGIC) + hashes.len); + if (rv != SECSuccess) + goto loser; + diff --git a/net/third_party/nss/ssl/SSLerrs.h b/net/third_party/nss/ssl/SSLerrs.h index 9124549..dc22f76 100644 --- a/net/third_party/nss/ssl/SSLerrs.h +++ b/net/third_party/nss/ssl/SSLerrs.h @@ -412,3 +412,12 @@ ER3(SSL_ERROR_INVALID_CHANNEL_ID_KEY, (SSL_ERROR_BASE + 127), ER3(SSL_ERROR_GET_CHANNEL_ID_FAILED, (SSL_ERROR_BASE + 128), "The application could not get a TLS Channel ID.") + +ER3(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM, (SSL_ERROR_BASE + 129), +"Unsupported hash algorithm used by TLS peer.") + +ER3(SSL_ERROR_DIGEST_FAILURE, (SSL_ERROR_BASE + 130), +"Digest function failed.") + +ER3(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, (SSL_ERROR_BASE + 131), +"Incorrect signature algorithm specified in a digitally-signed element.") diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c index 5e149e0..a5bb7bf 100644 --- a/net/third_party/nss/ssl/ssl3con.c +++ b/net/third_party/nss/ssl/ssl3con.c @@ -15,6 +15,7 @@ #include "keyhi.h" #include "secder.h" #include "secitem.h" +#include "sechash.h" #include "sslimpl.h" #include "sslproto.h" @@ -31,6 +32,15 @@ #include "blapi.h" #endif +/* This is a bodge to allow this code to be compiled against older NSS headers + * that don't contain the TLS 1.2 changes. */ +#ifndef CKM_NSS_TLS_PRF_GENERAL_SHA256 +#define CKM_NSS_TLS_PRF_GENERAL_SHA256 (CKM_NSS + 21) +#define CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256 (CKM_NSS + 22) +#define CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256 (CKM_NSS + 23) +#define CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 (CKM_NSS + 24) +#endif + #include <stdio.h> #ifdef NSS_ENABLE_ZLIB #include "zlib.h" @@ -64,6 +74,7 @@ static SECStatus ssl3_UpdateHandshakeHashes( sslSocket *ss, const unsigned char *b, unsigned int l); static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags); +static int ssl3_OIDToTLSHashAlgorithm(SECOidTag oid); static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen, const unsigned char *input, @@ -811,32 +822,36 @@ ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf, SECItem hashItem; buf->data = NULL; - signatureLen = PK11_SignatureLen(key); - if (signatureLen <= 0) { - PORT_SetError(SEC_ERROR_INVALID_KEY); - goto done; - } - - buf->len = (unsigned)signatureLen; - buf->data = (unsigned char *)PORT_Alloc(signatureLen); - if (!buf->data) - goto done; /* error code was set. */ switch (key->keyType) { case rsaKey: - hashItem.data = hash->md5; - hashItem.len = sizeof(SSL3Hashes); + hashItem.data = hash->u.raw; + hashItem.len = hash->len; break; case dsaKey: doDerEncode = isTLS; - hashItem.data = hash->sha; - hashItem.len = sizeof(hash->sha); + /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash. + * In that case, we use just the SHA1 part. */ + if (hash->hashAlg == SEC_OID_UNKNOWN) { + hashItem.data = hash->u.s.sha; + hashItem.len = sizeof(hash->u.s.sha); + } else { + hashItem.data = hash->u.raw; + hashItem.len = hash->len; + } break; #ifdef NSS_ENABLE_ECC case ecKey: doDerEncode = PR_TRUE; - hashItem.data = hash->sha; - hashItem.len = sizeof(hash->sha); + /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash. + * In that case, we use just the SHA1 part. */ + if (hash->hashAlg == SEC_OID_UNKNOWN) { + hashItem.data = hash->u.s.sha; + hashItem.len = sizeof(hash->u.s.sha); + } else { + hashItem.data = hash->u.raw; + hashItem.len = hash->len; + } break; #endif /* NSS_ENABLE_ECC */ default: @@ -845,7 +860,22 @@ ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf, } PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len)); - rv = PK11_Sign(key, buf, &hashItem); + if (hash->hashAlg == SEC_OID_UNKNOWN) { + signatureLen = PK11_SignatureLen(key); + if (signatureLen <= 0) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + goto done; + } + + buf->len = (unsigned)signatureLen; + buf->data = (unsigned char *)PORT_Alloc(signatureLen); + if (!buf->data) + goto done; /* error code was set. */ + + rv = PK11_Sign(key, buf, &hashItem); + } else { + rv = SGN_Digest(key, hash->hashAlg, buf, &hashItem); + } if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); } else if (doDerEncode) { @@ -879,9 +909,8 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, SECItem * signature = NULL; SECStatus rv; SECItem hashItem; -#ifdef NSS_ENABLE_ECC - unsigned int len; -#endif /* NSS_ENABLE_ECC */ + SECOidTag encAlg; + SECOidTag hashAlg; PRINT_BUF(60, (NULL, "check signed hashes", @@ -893,14 +922,24 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, return SECFailure; } + hashAlg = hash->hashAlg; switch (key->keyType) { case rsaKey: - hashItem.data = hash->md5; - hashItem.len = sizeof(SSL3Hashes); + encAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; + hashItem.data = hash->u.raw; + hashItem.len = hash->len; break; case dsaKey: - hashItem.data = hash->sha; - hashItem.len = sizeof(hash->sha); + encAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; + /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash. + * In that case, we use just the SHA1 part. */ + if (hash->hashAlg == SEC_OID_UNKNOWN) { + hashItem.data = hash->u.s.sha; + hashItem.len = sizeof(hash->u.s.sha); + } else { + hashItem.data = hash->u.raw; + hashItem.len = hash->len; + } /* Allow DER encoded DSA signatures in SSL 3.0 */ if (isTLS || buf->len != SECKEY_SignatureLen(key)) { signature = DSAU_DecodeDerSig(buf); @@ -914,25 +953,21 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, #ifdef NSS_ENABLE_ECC case ecKey: - hashItem.data = hash->sha; - hashItem.len = sizeof(hash->sha); - /* - * ECDSA signatures always encode the integers r and s - * using ASN (unlike DSA where ASN encoding is used - * with TLS but not with SSL3) + encAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; + /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash. + * In that case, we use just the SHA1 part. + * ECDSA signatures always encode the integers r and s using ASN.1 + * (unlike DSA where ASN.1 encoding is used with TLS but not with + * SSL3). So we can use VFY_VerifyDigestDirect for ECDSA. */ - len = SECKEY_SignatureLen(key); - if (len == 0) { - SECKEY_DestroyPublicKey(key); - PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); - return SECFailure; - } - signature = DSAU_DecodeDerSigToLen(buf, len); - if (!signature) { - PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); - return SECFailure; + if (hash->hashAlg == SEC_OID_UNKNOWN) { + hashAlg = SEC_OID_SHA1; + hashItem.data = hash->u.s.sha; + hashItem.len = sizeof(hash->u.s.sha); + } else { + hashItem.data = hash->u.raw; + hashItem.len = hash->len; } - buf = signature; break; #endif /* NSS_ENABLE_ECC */ @@ -945,7 +980,17 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, PRINT_BUF(60, (NULL, "hash(es) to be verified", hashItem.data, hashItem.len)); - rv = PK11_Verify(key, buf, &hashItem, pwArg); + if (hashAlg == SEC_OID_UNKNOWN || key->keyType == dsaKey) { + /* VFY_VerifyDigestDirect requires DSA signatures to be DER-encoded. + * DSA signatures are DER-encoded in TLS but not in SSL3 and the code + * above always removes the DER encoding of DSA signatures when + * present. Thus DSA signatures are always verified with PK11_Verify. + */ + rv = PK11_Verify(key, buf, &hashItem, pwArg); + } else { + rv = VFY_VerifyDigestDirect(&hashItem, key, buf, encAlg, hashAlg, + pwArg); + } SECKEY_DestroyPublicKey(key); if (signature) { SECITEM_FreeItem(signature, PR_TRUE); @@ -961,33 +1006,69 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, /* Called from ssl3_ComputeExportRSAKeyHash * ssl3_ComputeDHKeyHash * which are called from ssl3_HandleServerKeyExchange. + * + * hashAlg: either the OID for a hash algorithm or SEC_OID_UNKNOWN to specify + * the pre-1.2, MD5/SHA1 combination hash. */ SECStatus -ssl3_ComputeCommonKeyHash(PRUint8 * hashBuf, unsigned int bufLen, - SSL3Hashes *hashes, PRBool bypassPKCS11) +ssl3_ComputeCommonKeyHash(SECOidTag hashAlg, + PRUint8 * hashBuf, unsigned int bufLen, + SSL3Hashes *hashes, PRBool bypassPKCS11) { SECStatus rv = SECSuccess; #ifndef NO_PKCS11_BYPASS if (bypassPKCS11) { - MD5_HashBuf (hashes->md5, hashBuf, bufLen); - SHA1_HashBuf(hashes->sha, hashBuf, bufLen); + if (hashAlg == SEC_OID_UNKNOWN) { + MD5_HashBuf (hashes->u.s.md5, hashBuf, bufLen); + SHA1_HashBuf(hashes->u.s.sha, hashBuf, bufLen); + hashes->len = MD5_LENGTH + SHA1_LENGTH; + } else if (hashAlg == SEC_OID_SHA1) { + SHA1_HashBuf(hashes->u.raw, hashBuf, bufLen); + hashes->len = SHA1_LENGTH; + } else if (hashAlg == SEC_OID_SHA256) { + SHA256_HashBuf(hashes->u.raw, hashBuf, bufLen); + hashes->len = SHA256_LENGTH; + } else if (hashAlg == SEC_OID_SHA384) { + SHA384_HashBuf(hashes->u.raw, hashBuf, bufLen); + hashes->len = SHA384_LENGTH; + } else { + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); + return SECFailure; + } } else #endif { - rv = PK11_HashBuf(SEC_OID_MD5, hashes->md5, hashBuf, bufLen); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - rv = SECFailure; - goto done; - } + if (hashAlg == SEC_OID_UNKNOWN) { + rv = PK11_HashBuf(SEC_OID_MD5, hashes->u.s.md5, hashBuf, bufLen); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); + rv = SECFailure; + goto done; + } - rv = PK11_HashBuf(SEC_OID_SHA1, hashes->sha, hashBuf, bufLen); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - rv = SECFailure; + rv = PK11_HashBuf(SEC_OID_SHA1, hashes->u.s.sha, hashBuf, bufLen); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); + rv = SECFailure; + } + hashes->len = MD5_LENGTH + SHA1_LENGTH; + } else { + hashes->len = HASH_ResultLenByOidTag(hashAlg); + if (hashes->len > sizeof(hashes->u.raw)) { + ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); + rv = SECFailure; + goto done; + } + rv = PK11_HashBuf(hashAlg, hashes->u.raw, hashBuf, bufLen); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); + rv = SECFailure; + } } } + hashes->hashAlg = hashAlg; + done: return rv; } @@ -997,7 +1078,8 @@ done: ** ssl3_HandleServerKeyExchange. */ static SECStatus -ssl3_ComputeExportRSAKeyHash(SECItem modulus, SECItem publicExponent, +ssl3_ComputeExportRSAKeyHash(SECOidTag hashAlg, + SECItem modulus, SECItem publicExponent, SSL3Random *client_rand, SSL3Random *server_rand, SSL3Hashes *hashes, PRBool bypassPKCS11) { @@ -1033,11 +1115,19 @@ ssl3_ComputeExportRSAKeyHash(SECItem modulus, SECItem publicExponent, pBuf += publicExponent.len; PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); - rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11); + rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, + bypassPKCS11); PRINT_BUF(95, (NULL, "RSAkey hash: ", hashBuf, bufLen)); - PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result", hashes->md5, MD5_LENGTH)); - PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); + if (hashAlg == SEC_OID_UNKNOWN) { + PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result", + hashes->u.s.md5, MD5_LENGTH)); + PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result", + hashes->u.s.sha, SHA1_LENGTH)); + } else { + PRINT_BUF(95, (NULL, "RSAkey hash: result", + hashes->u.raw, hashes->len)); + } if (hashBuf != buf && hashBuf != NULL) PORT_Free(hashBuf); @@ -1047,9 +1137,10 @@ ssl3_ComputeExportRSAKeyHash(SECItem modulus, SECItem publicExponent, /* Caller must set hiLevel error code. */ /* Called from ssl3_HandleServerKeyExchange. */ static SECStatus -ssl3_ComputeDHKeyHash(SECItem dh_p, SECItem dh_g, SECItem dh_Ys, - SSL3Random *client_rand, SSL3Random *server_rand, - SSL3Hashes *hashes, PRBool bypassPKCS11) +ssl3_ComputeDHKeyHash(SECOidTag hashAlg, + SECItem dh_p, SECItem dh_g, SECItem dh_Ys, + SSL3Random *client_rand, SSL3Random *server_rand, + SSL3Hashes *hashes, PRBool bypassPKCS11) { PRUint8 * hashBuf; PRUint8 * pBuf; @@ -1088,11 +1179,19 @@ ssl3_ComputeDHKeyHash(SECItem dh_p, SECItem dh_g, SECItem dh_Ys, pBuf += dh_Ys.len; PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); - rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11); + rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, + bypassPKCS11); PRINT_BUF(95, (NULL, "DHkey hash: ", hashBuf, bufLen)); - PRINT_BUF(95, (NULL, "DHkey hash: MD5 result", hashes->md5, MD5_LENGTH)); - PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); + if (hashAlg == SEC_OID_UNKNOWN) { + PRINT_BUF(95, (NULL, "DHkey hash: MD5 result", + hashes->u.s.md5, MD5_LENGTH)); + PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result", + hashes->u.s.sha, SHA1_LENGTH)); + } else { + PRINT_BUF(95, (NULL, "DHkey hash: result", + hashes->u.raw, hashes->len)); + } if (hashBuf != buf && hashBuf != NULL) PORT_Free(hashBuf); @@ -3190,6 +3289,8 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms) unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random; PRBool isTLS = (PRBool)(kea_def->tls_keygen || (pwSpec->version > SSL_LIBRARY_VERSION_3_0)); + PRBool isTLS12= + (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); /* * Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH * which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size @@ -3208,7 +3309,12 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms) PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - if (isTLS) { + if (isTLS12) { + if(isDH) master_derive = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256; + else master_derive = CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256; + key_derive = CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256; + keyFlags = CKF_SIGN | CKF_VERIFY; + } else if (isTLS) { if(isDH) master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH; else master_derive = CKM_TLS_MASTER_KEY_DERIVE; key_derive = CKM_TLS_KEY_AND_MAC_DERIVE; @@ -3366,6 +3472,8 @@ ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss) unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random; PRBool isTLS = (PRBool)(kea_def->tls_keygen || (pwSpec->version > SSL_LIBRARY_VERSION_3_0)); + PRBool isTLS12= + (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); /* following variables used in PKCS11 path */ const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def; PK11SlotInfo * slot = NULL; @@ -3423,7 +3531,9 @@ ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss) params.data = (unsigned char *)&key_material_params; params.len = sizeof(key_material_params); - if (isTLS) { + if (isTLS12) { + key_derive = CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256; + } else if (isTLS) { key_derive = CKM_TLS_KEY_AND_MAC_DERIVE; } else { key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE; @@ -3480,19 +3590,63 @@ loser: return SECFailure; } +/* ssl3_InitTLS12HandshakeHash creates a handshake hash context for TLS 1.2, + * if needed, and hashes in any buffered messages in ss->ssl3.hs.messages. */ +static SECStatus +ssl3_InitTLS12HandshakeHash(sslSocket *ss) +{ + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2 && + ss->ssl3.hs.tls12_handshake_hash == NULL) { + /* If we ever support ciphersuites where the PRF hash isn't SHA-256 + * then this will need to be updated. */ + ss->ssl3.hs.tls12_handshake_hash = + PK11_CreateDigestContext(SEC_OID_SHA256); + if (!ss->ssl3.hs.tls12_handshake_hash || + PK11_DigestBegin(ss->ssl3.hs.tls12_handshake_hash) != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); + return SECFailure; + } + } + + if (ss->ssl3.hs.tls12_handshake_hash && ss->ssl3.hs.messages.len > 0) { + if (PK11_DigestOp(ss->ssl3.hs.tls12_handshake_hash, + ss->ssl3.hs.messages.buf, + ss->ssl3.hs.messages.len) != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); + return SECFailure; + } + } + + if (ss->ssl3.hs.messages.buf && !ss->opt.bypassPKCS11) { + PORT_Free(ss->ssl3.hs.messages.buf); + ss->ssl3.hs.messages.buf = NULL; + ss->ssl3.hs.messages.len = 0; + ss->ssl3.hs.messages.space = 0; + } + + return SECSuccess; +} + static SECStatus ssl3_RestartHandshakeHashes(sslSocket *ss) { SECStatus rv = SECSuccess; + ss->ssl3.hs.messages.len = 0; #ifndef NO_PKCS11_BYPASS if (ss->opt.bypassPKCS11) { - ss->ssl3.hs.messages.len = 0; MD5_Begin((MD5Context *)ss->ssl3.hs.md5_cx); SHA1_Begin((SHA1Context *)ss->ssl3.hs.sha_cx); } else #endif { + if (ss->ssl3.hs.tls12_handshake_hash) { + rv = PK11_DigestBegin(ss->ssl3.hs.tls12_handshake_hash); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); + return rv; + } + } rv = PK11_DigestBegin(ss->ssl3.hs.md5); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); @@ -3519,24 +3673,20 @@ ssl3_NewHandshakeHashes(sslSocket *ss) * that the master secret will wind up in ... */ SSL_TRC(30,("%d: SSL3[%d]: start handshake hashes", SSL_GETPID(), ss->fd)); -#ifndef NO_PKCS11_BYPASS - if (ss->opt.bypassPKCS11) { - PORT_Assert(!ss->ssl3.hs.messages.buf && !ss->ssl3.hs.messages.space); - ss->ssl3.hs.messages.buf = NULL; - ss->ssl3.hs.messages.space = 0; - } else -#endif - { - ss->ssl3.hs.md5 = md5 = PK11_CreateDigestContext(SEC_OID_MD5); - ss->ssl3.hs.sha = sha = PK11_CreateDigestContext(SEC_OID_SHA1); - if (md5 == NULL) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - goto loser; - } - if (sha == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - goto loser; - } + PORT_Assert(!ss->ssl3.hs.messages.buf && !ss->ssl3.hs.messages.space); + ss->ssl3.hs.messages.buf = NULL; + ss->ssl3.hs.messages.space = 0; + + ss->ssl3.hs.md5 = md5 = PK11_CreateDigestContext(SEC_OID_MD5); + ss->ssl3.hs.sha = sha = PK11_CreateDigestContext(SEC_OID_SHA1); + ss->ssl3.hs.tls12_handshake_hash = NULL; + if (md5 == NULL) { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); + goto loser; + } + if (sha == NULL) { + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); + goto loser; } if (SECSuccess == ssl3_RestartHandshakeHashes(ss)) { return SECSuccess; @@ -3574,6 +3724,17 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, PRINT_BUF(90, (NULL, "MD5 & SHA handshake hash input:", b, l)); + if ((ss->version == 0 || ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) && + !ss->opt.bypassPKCS11 && + ss->ssl3.hs.tls12_handshake_hash == NULL) { + /* For TLS 1.2 connections we need to buffer the handshake messages + * until we have established which PRF hash function to use. */ + rv = sslBuffer_Append(&ss->ssl3.hs.messages, b, l); + if (rv != SECSuccess) { + return rv; + } + } + #ifndef NO_PKCS11_BYPASS if (ss->opt.bypassPKCS11) { MD5_Update((MD5Context *)ss->ssl3.hs.md5_cx, b, l); @@ -3584,15 +3745,23 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, return rv; } #endif - rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - return rv; - } - rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - return rv; + if (ss->ssl3.hs.tls12_handshake_hash) { + rv = PK11_DigestOp(ss->ssl3.hs.tls12_handshake_hash, b, l); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); + return rv; + } + } else { + rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); + return rv; + } + rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); + return rv; + } } return rv; } @@ -3744,6 +3913,25 @@ ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length) return rv; /* error code set by AppendHandshake, if applicable. */ } +/* ssl3_AppendSignatureAndHashAlgorithm appends the serialisation of + * |sigAndHash| to the current handshake message. */ +SECStatus +ssl3_AppendSignatureAndHashAlgorithm( + sslSocket *ss, const SSL3SignatureAndHashAlgorithm* sigAndHash) +{ + unsigned char serialized[2]; + + serialized[0] = ssl3_OIDToTLSHashAlgorithm(sigAndHash->hashAlg); + if (serialized[0] == 0) { + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); + return SECFailure; + } + + serialized[1] = sigAndHash->sigAlg; + + return ssl3_AppendHandshake(ss, serialized, sizeof(serialized)); +} + /************************************************************************** * Consume Handshake functions. * @@ -3850,6 +4038,147 @@ ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes, return SECSuccess; } +/* tlsHashOIDMap contains the mapping between TLS hash identifiers and the + * SECOidTag used internally by NSS. */ +static const struct { + int tlsHash; + SECOidTag oid; +} tlsHashOIDMap[] = { + { tls_hash_md5, SEC_OID_MD5 }, + { tls_hash_sha1, SEC_OID_SHA1 }, + { tls_hash_sha224, SEC_OID_SHA224 }, + { tls_hash_sha256, SEC_OID_SHA256 }, + { tls_hash_sha384, SEC_OID_SHA384 }, + { tls_hash_sha512, SEC_OID_SHA512 } +}; + +/* ssl3_TLSHashAlgorithmToOID converts a TLS hash identifier into an OID value. + * If the hash is not recognised, SEC_OID_UNKNOWN is returned. + * + * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ +SECOidTag +ssl3_TLSHashAlgorithmToOID(int hashFunc) +{ + unsigned int i; + + for (i = 0; i < PR_ARRAY_SIZE(tlsHashOIDMap); i++) { + if (hashFunc == tlsHashOIDMap[i].tlsHash) { + return tlsHashOIDMap[i].oid; + } + } + return SEC_OID_UNKNOWN; +} + +/* ssl3_OIDToTLSHashAlgorithm converts an OID to a TLS hash algorithm + * identifier. If the hash is not recognised, zero is returned. + * + * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ +static int +ssl3_OIDToTLSHashAlgorithm(SECOidTag oid) +{ + unsigned int i; + + for (i = 0; i < PR_ARRAY_SIZE(tlsHashOIDMap); i++) { + if (oid == tlsHashOIDMap[i].oid) { + return tlsHashOIDMap[i].tlsHash; + } + } + return 0; +} + +/* ssl3_TLSSignatureAlgorithmForKeyType returns the TLS 1.2 signature algorithm + * identifier for a given KeyType. */ +static SECStatus +ssl3_TLSSignatureAlgorithmForKeyType(KeyType keyType, + TLSSignatureAlgorithm *out) +{ + switch (keyType) { + case rsaKey: + *out = tls_sig_rsa; + return SECSuccess; + case dsaKey: + *out = tls_sig_dsa; + return SECSuccess; + case ecKey: + *out = tls_sig_ecdsa; + return SECSuccess; + default: + PORT_SetError(SEC_ERROR_INVALID_KEY); + return SECFailure; + } +} + +/* ssl3_TLSSignatureAlgorithmForCertificate returns the TLS 1.2 signature + * algorithm identifier for the given certificate. */ +static SECStatus +ssl3_TLSSignatureAlgorithmForCertificate(CERTCertificate *cert, + TLSSignatureAlgorithm *out) +{ + SECKEYPublicKey *key; + KeyType keyType; + + key = CERT_ExtractPublicKey(cert); + if (key == NULL) { + ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); + return SECFailure; + } + + keyType = key->keyType; + SECKEY_DestroyPublicKey(key); + return ssl3_TLSSignatureAlgorithmForKeyType(keyType, out); +} + +/* ssl3_CheckSignatureAndHashAlgorithmConsistency checks that the signature + * algorithm identifier in |sigAndHash| is consistent with the public key in + * |cert|. If so, SECSuccess is returned. Otherwise, PORT_SetError is called + * and SECFailure is returned. */ +SECStatus +ssl3_CheckSignatureAndHashAlgorithmConsistency( + const SSL3SignatureAndHashAlgorithm *sigAndHash, CERTCertificate* cert) +{ + SECStatus rv; + TLSSignatureAlgorithm sigAlg; + + rv = ssl3_TLSSignatureAlgorithmForCertificate(cert, &sigAlg); + if (rv != SECSuccess) { + return rv; + } + if (sigAlg != sigAndHash->sigAlg) { + PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); + return SECFailure; + } + return SECSuccess; +} + +/* ssl3_ConsumeSignatureAndHashAlgorithm reads a SignatureAndHashAlgorithm + * structure from |b| and puts the resulting value into |out|. |b| and |length| + * are updated accordingly. + * + * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ +SECStatus +ssl3_ConsumeSignatureAndHashAlgorithm(sslSocket *ss, + SSL3Opaque **b, + PRUint32 *length, + SSL3SignatureAndHashAlgorithm *out) +{ + unsigned char bytes[2]; + SECStatus rv; + + rv = ssl3_ConsumeHandshake(ss, bytes, sizeof(bytes), b, length); + if (rv != SECSuccess) { + return rv; + } + + out->hashAlg = ssl3_TLSHashAlgorithmToOID(bytes[0]); + if (out->hashAlg == SEC_OID_UNKNOWN) { + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); + return SECFailure; + } + + out->sigAlg = bytes[1]; + return SECSuccess; +} + /************************************************************************** * end of Consume Handshake functions. **************************************************************************/ @@ -3876,6 +4205,7 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss, SSL3Opaque sha_inner[MAX_MAC_LENGTH]; PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); + hashes->hashAlg = SEC_OID_UNKNOWN; #ifndef NO_PKCS11_BYPASS if (ss->opt.bypassPKCS11) { @@ -3939,9 +4269,9 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss, MD5_Update(md5cx, mac_pad_2, mac_defs[mac_md5].pad_size); MD5_Update(md5cx, md5_inner, MD5_LENGTH); } - MD5_End(md5cx, hashes->md5, &outLength, MD5_LENGTH); + MD5_End(md5cx, hashes->u.s.md5, &outLength, MD5_LENGTH); - PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->md5, MD5_LENGTH)); + PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH)); if (!isTLS) { PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, @@ -3953,16 +4283,58 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss, SHA1_Update(shacx, mac_pad_2, mac_defs[mac_sha].pad_size); SHA1_Update(shacx, sha_inner, SHA1_LENGTH); } - SHA1_End(shacx, hashes->sha, &outLength, SHA1_LENGTH); + SHA1_End(shacx, hashes->u.s.sha, &outLength, SHA1_LENGTH); - PRINT_BUF(60, (NULL, "SHA outer: result", hashes->sha, SHA1_LENGTH)); + PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH)); + hashes->len = MD5_LENGTH + SHA1_LENGTH; rv = SECSuccess; #undef md5cx #undef shacx } else #endif - { + if (ss->ssl3.hs.tls12_handshake_hash) { + PK11Context *h; + unsigned int stateLen; + unsigned char stackBuf[1024]; + unsigned char *stateBuf = NULL; + + if (!spec->master_secret) { + PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE); + return SECFailure; + } + + h = ss->ssl3.hs.tls12_handshake_hash; + stateBuf = PK11_SaveContextAlloc(h, stackBuf, + sizeof(stackBuf), &stateLen); + if (stateBuf == NULL) { + ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); + goto tls12_loser; + } + rv |= PK11_DigestFinal(h, hashes->u.raw, &hashes->len, + sizeof(hashes->u.raw)); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); + rv = SECFailure; + goto tls12_loser; + } + /* If we ever support ciphersuites where the PRF hash isn't SHA-256 + * then this will need to be updated. */ + hashes->hashAlg = SEC_OID_SHA256; + rv = SECSuccess; + +tls12_loser: + if (stateBuf) { + if (PK11_RestoreContext(ss->ssl3.hs.tls12_handshake_hash, stateBuf, + stateLen) != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); + rv = SECFailure; + } + if (stateBuf != stackBuf) { + PORT_ZFree(stateBuf, stateLen); + } + } + } else { /* compute hases with PKCS11 */ PK11Context * md5; PK11Context * sha = NULL; @@ -4051,7 +4423,7 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss, rv |= PK11_DigestOp(md5, mac_pad_2, mac_defs[mac_md5].pad_size); rv |= PK11_DigestOp(md5, md5_inner, MD5_LENGTH); } - rv |= PK11_DigestFinal(md5, hashes->md5, &outLength, MD5_LENGTH); + rv |= PK11_DigestFinal(md5, hashes->u.s.md5, &outLength, MD5_LENGTH); PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); @@ -4059,7 +4431,7 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss, goto loser; } - PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->md5, MD5_LENGTH)); + PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH)); if (!isTLS) { PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, @@ -4071,7 +4443,7 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss, rv |= PK11_DigestOp(sha, mac_pad_2, mac_defs[mac_sha].pad_size); rv |= PK11_DigestOp(sha, sha_inner, SHA1_LENGTH); } - rv |= PK11_DigestFinal(sha, hashes->sha, &outLength, SHA1_LENGTH); + rv |= PK11_DigestFinal(sha, hashes->u.s.sha, &outLength, SHA1_LENGTH); PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); @@ -4079,8 +4451,9 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss, goto loser; } - PRINT_BUF(60, (NULL, "SHA outer: result", hashes->sha, SHA1_LENGTH)); + PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH)); + hashes->len = MD5_LENGTH + SHA1_LENGTH; rv = SECSuccess; loser: @@ -5343,8 +5716,12 @@ ssl3_SendCertificateVerify(sslSocket *ss) { SECStatus rv = SECFailure; PRBool isTLS; + PRBool isTLS12; SECItem buf = {siBuffer, NULL, 0}; SSL3Hashes hashes; + KeyType keyType; + unsigned int len; + SSL3SignatureAndHashAlgorithm sigAndHash; PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); @@ -5360,16 +5737,18 @@ ssl3_SendCertificateVerify(sslSocket *ss) } isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); if (ss->ssl3.platformClientKey) { #ifdef NSS_PLATFORM_CLIENT_AUTH + keyType = CERT_GetCertKeyType( + &ss->ssl3.clientCertificate->subjectPublicKeyInfo); rv = ssl3_PlatformSignHashes( - &hashes, ss->ssl3.platformClientKey, &buf, isTLS, - CERT_GetCertKeyType( - &ss->ssl3.clientCertificate->subjectPublicKeyInfo)); + &hashes, ss->ssl3.platformClientKey, &buf, isTLS, keyType); ssl_FreePlatformKey(ss->ssl3.platformClientKey); ss->ssl3.platformClientKey = (PlatformKey)NULL; #endif /* NSS_PLATFORM_CLIENT_AUTH */ } else { + keyType = ss->ssl3.clientPrivateKey->keyType; rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS); if (rv == SECSuccess) { PK11SlotInfo * slot; @@ -5393,10 +5772,30 @@ ssl3_SendCertificateVerify(sslSocket *ss) goto done; /* err code was set by ssl3_SignHashes */ } - rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, buf.len + 2); + len = buf.len + 2 + (isTLS12 ? 2 : 0); + + rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len); if (rv != SECSuccess) { goto done; /* error code set by AppendHandshake */ } + if (isTLS12) { + rv = ssl3_TLSSignatureAlgorithmForKeyType(keyType, + &sigAndHash.sigAlg); + if (rv != SECSuccess) { + goto done; + } + /* We always sign using the handshake hash function. It's possible that + * a server could support SHA-256 as the handshake hash but not as a + * signature hash. In that case we wouldn't be able to do client + * certificates with it. The alternative is to buffer all handshake + * messages. */ + sigAndHash.hashAlg = hashes.hashAlg; + + rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash); + if (rv != SECSuccess) { + goto done; /* err set by AppendHandshake. */ + } + } rv = ssl3_AppendHandshakeVariable(ss, buf.data, buf.len, 2); if (rv != SECSuccess) { goto done; /* error code set by AppendHandshake */ @@ -5504,6 +5903,13 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0); + rv = ssl3_InitTLS12HandshakeHash(ss); + if (rv != SECSuccess) { + desc = internal_error; + errCode = PORT_GetError(); + goto alert_loser; + } + rv = ssl3_ConsumeHandshake( ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length); if (rv != SECSuccess) { @@ -5834,12 +6240,15 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) { PRArenaPool * arena = NULL; SECKEYPublicKey *peerKey = NULL; - PRBool isTLS; + PRBool isTLS, isTLS12; SECStatus rv; int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; SSL3AlertDescription desc = illegal_parameter; SSL3Hashes hashes; SECItem signature = {siBuffer, NULL, 0}; + SSL3SignatureAndHashAlgorithm sigAndHash; + + sigAndHash.hashAlg = SEC_OID_UNKNOWN; SSL_TRC(3, ("%d: SSL3[%d]: handle server_key_exchange handshake", SSL_GETPID(), ss->fd)); @@ -5859,6 +6268,7 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); switch (ss->ssl3.hs.kea_def->exchKeyType) { @@ -5874,6 +6284,18 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) if (rv != SECSuccess) { goto loser; /* malformed. */ } + if (isTLS12) { + rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, + &sigAndHash); + if (rv != SECSuccess) { + goto loser; /* malformed or unsupported. */ + } + rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( + &sigAndHash, ss->sec.peerCert); + if (rv != SECSuccess) { + goto loser; + } + } rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ @@ -5891,7 +6313,7 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) /* * check to make sure the hash is signed by right guy */ - rv = ssl3_ComputeExportRSAKeyHash(modulus, exponent, + rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg, modulus, exponent, &ss->ssl3.hs.client_random, &ss->ssl3.hs.server_random, &hashes, ss->opt.bypassPKCS11); @@ -5964,6 +6386,18 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } if (dh_Ys.len > dh_p.len || !ssl3_BigIntGreaterThanOne(&dh_Ys)) goto alert_loser; + if (isTLS12) { + rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, + &sigAndHash); + if (rv != SECSuccess) { + goto loser; /* malformed or unsupported. */ + } + rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( + &sigAndHash, ss->sec.peerCert); + if (rv != SECSuccess) { + goto loser; + } + } rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ @@ -5985,7 +6419,7 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) /* * check to make sure the hash is signed by right guy */ - rv = ssl3_ComputeDHKeyHash(dh_p, dh_g, dh_Ys, + rv = ssl3_ComputeDHKeyHash(sigAndHash.hashAlg, dh_p, dh_g, dh_Ys, &ss->ssl3.hs.client_random, &ss->ssl3.hs.server_random, &hashes, ss->opt.bypassPKCS11); @@ -6862,6 +7296,13 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto alert_loser; } + rv = ssl3_InitTLS12HandshakeHash(ss); + if (rv != SECSuccess) { + desc = internal_error; + errCode = PORT_GetError(); + goto alert_loser; + } + /* grab the client random data. */ rv = ssl3_ConsumeHandshake( ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length); @@ -7604,6 +8045,13 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length) goto alert_loser; } + rv = ssl3_InitTLS12HandshakeHash(ss); + if (rv != SECSuccess) { + desc = internal_error; + errCode = PORT_GetError(); + goto alert_loser; + } + /* if we get a non-zero SID, just ignore it. */ if (length != SSL_HL_CLIENT_HELLO_HBYTES + suite_length + sid_length + rand_length) { @@ -7851,6 +8299,85 @@ ssl3_SendServerHello(sslSocket *ss) return SECSuccess; } +/* ssl3_PickSignatureHashAlgorithm selects a hash algorithm to use when signing + * elements of the handshake. (The negotiated cipher suite determines the + * signature algorithm.) Prior to TLS 1.2, the MD5/SHA1 combination is always + * used. With TLS 1.2, a client may advertise its support for signature and + * hash combinations. */ +static SECStatus +ssl3_PickSignatureHashAlgorithm(sslSocket *ss, + SSL3SignatureAndHashAlgorithm* out) +{ + TLSSignatureAlgorithm sigAlg; + unsigned int i, j; + /* hashPreference expresses our preferences for hash algorithms, most + * preferable first. */ + static const PRUint8 hashPreference[] = { + tls_hash_sha256, + tls_hash_sha384, + tls_hash_sha512, + tls_hash_sha1, + }; + + switch (ss->ssl3.hs.kea_def->kea) { + case kea_rsa: + case kea_rsa_export: + case kea_rsa_export_1024: + case kea_dh_rsa: + case kea_dh_rsa_export: + case kea_dhe_rsa: + case kea_dhe_rsa_export: + case kea_rsa_fips: + case kea_ecdh_rsa: + case kea_ecdhe_rsa: + sigAlg = tls_sig_rsa; + break; + case kea_dh_dss: + case kea_dh_dss_export: + case kea_dhe_dss: + case kea_dhe_dss_export: + sigAlg = tls_sig_dsa; + break; + case kea_ecdh_ecdsa: + case kea_ecdhe_ecdsa: + sigAlg = tls_sig_ecdsa; + break; + default: + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); + return SECFailure; + } + out->sigAlg = sigAlg; + + if (ss->version <= SSL_LIBRARY_VERSION_TLS_1_1) { + /* SEC_OID_UNKNOWN means the MD5/SHA1 combo hash used in TLS 1.1 and + * prior. */ + out->hashAlg = SEC_OID_UNKNOWN; + return SECSuccess; + } + + if (ss->ssl3.hs.numClientSigAndHash == 0) { + /* If the client didn't provide any signature_algorithms extension then + * we can assume that they support SHA-1: + * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ + out->hashAlg = SEC_OID_SHA1; + return SECSuccess; + } + + for (i = 0; i < PR_ARRAY_SIZE(hashPreference); i++) { + for (j = 0; j < ss->ssl3.hs.numClientSigAndHash; j++) { + const SSL3SignatureAndHashAlgorithm* sh = + &ss->ssl3.hs.clientSigAndHash[j]; + if (sh->sigAlg == sigAlg && sh->hashAlg == hashPreference[i]) { + out->hashAlg = sh->hashAlg; + return SECSuccess; + } + } + } + + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); + return SECFailure; +} + static SECStatus ssl3_SendServerKeyExchange(sslSocket *ss) @@ -7862,6 +8389,7 @@ ssl3_SendServerKeyExchange(sslSocket *ss) SECItem signed_hash = {siBuffer, NULL, 0}; SSL3Hashes hashes; SECKEYPublicKey * sdPub; /* public key for step-down */ + SSL3SignatureAndHashAlgorithm sigAndHash; SSL_TRC(3, ("%d: SSL3[%d]: send server_key_exchange handshake", SSL_GETPID(), ss->fd)); @@ -7869,6 +8397,10 @@ ssl3_SendServerKeyExchange(sslSocket *ss) PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + if (ssl3_PickSignatureHashAlgorithm(ss, &sigAndHash) != SECSuccess) { + return SECFailure; + } + switch (kea_def->exchKeyType) { case kt_rsa: /* Perform SSL Step-Down here. */ @@ -7878,7 +8410,8 @@ ssl3_SendServerKeyExchange(sslSocket *ss) PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); return SECFailure; } - rv = ssl3_ComputeExportRSAKeyHash(sdPub->u.rsa.modulus, + rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg, + sdPub->u.rsa.modulus, sdPub->u.rsa.publicExponent, &ss->ssl3.hs.client_random, &ss->ssl3.hs.server_random, @@ -7921,6 +8454,13 @@ ssl3_SendServerKeyExchange(sslSocket *ss) goto loser; /* err set by AppendHandshake. */ } + if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { + rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + } + rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, signed_hash.len, 2); if (rv != SECSuccess) { @@ -7931,7 +8471,7 @@ ssl3_SendServerKeyExchange(sslSocket *ss) #ifdef NSS_ENABLE_ECC case kt_ecdh: { - rv = ssl3_SendECDHServerKeyExchange(ss); + rv = ssl3_SendECDHServerKeyExchange(ss, &sigAndHash); return rv; } #endif /* NSS_ENABLE_ECC */ @@ -8045,26 +8585,51 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length, SECStatus rv; int errCode = SSL_ERROR_RX_MALFORMED_CERT_VERIFY; SSL3AlertDescription desc = handshake_failure; - PRBool isTLS; + PRBool isTLS, isTLS12; + SSL3SignatureAndHashAlgorithm sigAndHash; SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake", SSL_GETPID(), ss->fd)); PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); + isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + if (ss->ssl3.hs.ws != wait_cert_verify || ss->sec.peerCert == NULL) { desc = unexpected_message; errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY; goto alert_loser; } + if (isTLS12) { + rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, + &sigAndHash); + if (rv != SECSuccess) { + goto loser; /* malformed or unsupported. */ + } + rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( + &sigAndHash, ss->sec.peerCert); + if (rv != SECSuccess) { + errCode = PORT_GetError(); + desc = decrypt_error; + goto alert_loser; + } + + /* We only support CertificateVerify messages that use the handshake + * hash. */ + if (sigAndHash.hashAlg != hashes->hashAlg) { + errCode = SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM; + desc = decrypt_error; + goto alert_loser; + } + } + rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ } - isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); - /* XXX verify that the key & kea match */ rv = ssl3_VerifySignedHashes(hashes, ss->sec.peerCert, &signed_hash, isTLS, ss->pkcs11PinArg); @@ -9163,7 +9728,7 @@ done: static SECStatus ssl3_ComputeTLSFinished(ssl3CipherSpec *spec, PRBool isServer, - const SSL3Finished * hashes, + const SSL3Hashes * hashes, TLSFinished * tlsFinished) { const char * label; @@ -9173,8 +9738,8 @@ ssl3_ComputeTLSFinished(ssl3CipherSpec *spec, label = isServer ? "server finished" : "client finished"; len = 15; - rv = ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->md5, - sizeof *hashes, tlsFinished->verify_data, + rv = ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->u.raw, + hashes->len, tlsFinished->verify_data, sizeof tlsFinished->verify_data); return rv; @@ -9192,12 +9757,16 @@ ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec, const char *label, SECStatus rv = SECSuccess; if (spec->master_secret && !spec->bypassCiphers) { - SECItem param = {siBuffer, NULL, 0}; - PK11Context *prf_context = - PK11_CreateContextBySymKey(CKM_TLS_PRF_GENERAL, CKA_SIGN, - spec->master_secret, ¶m); + SECItem param = {siBuffer, NULL, 0}; + CK_MECHANISM_TYPE mech = CKM_TLS_PRF_GENERAL; + PK11Context *prf_context; unsigned int retLen; + if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { + mech = CKM_NSS_TLS_PRF_GENERAL_SHA256; + } + prf_context = PK11_CreateContextBySymKey(mech, CKA_SIGN, + spec->master_secret, ¶m); if (!prf_context) return SECFailure; @@ -9409,9 +9978,10 @@ ssl3_SendEncryptedExtensions(sslSocket *ss) pub_bytes = spki->data + sizeof(P256_SPKI_PREFIX); memcpy(signed_data, CHANNEL_ID_MAGIC, sizeof(CHANNEL_ID_MAGIC)); - memcpy(signed_data + sizeof(CHANNEL_ID_MAGIC), &hashes, sizeof(hashes)); + memcpy(signed_data + sizeof(CHANNEL_ID_MAGIC), hashes.u.raw, hashes.len); - rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, sizeof(signed_data)); + rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, + sizeof(CHANNEL_ID_MAGIC) + hashes.len); if (rv != SECSuccess) goto loser; @@ -9496,7 +10066,7 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags) PRBool isServer = ss->sec.isServer; SECStatus rv; SSL3Sender sender = isServer ? sender_server : sender_client; - SSL3Finished hashes; + SSL3Hashes hashes; TLSFinished tlsFinished; SSL_TRC(3, ("%d: SSL3[%d]: send finished handshake", SSL_GETPID(), ss->fd)); @@ -9530,14 +10100,15 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags) goto fail; /* err set by AppendHandshake. */ } else { if (isServer) - ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes; + ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes.u.s; else - ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes; - ss->ssl3.hs.finishedBytes = sizeof hashes; - rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes); + ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes.u.s; + PORT_Assert(hashes.len == sizeof hashes.u.s); + ss->ssl3.hs.finishedBytes = sizeof hashes.u.s; + rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes.u.s); if (rv != SECSuccess) goto fail; /* err set by AppendHandshake. */ - rv = ssl3_AppendHandshake(ss, &hashes, sizeof hashes); + rv = ssl3_AppendHandshake(ss, &hashes.u.s, sizeof hashes.u.s); if (rv != SECSuccess) goto fail; /* err set by AppendHandshake. */ } @@ -9686,18 +10257,19 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, return SECFailure; } } else { - if (length != sizeof(SSL3Hashes)) { + if (length != sizeof(SSL3Finished)) { (void)ssl3_IllegalParameter(ss); PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED); return SECFailure; } if (!isServer) - ss->ssl3.hs.finishedMsgs.sFinished[1] = *hashes; + ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes->u.s; else - ss->ssl3.hs.finishedMsgs.sFinished[0] = *hashes; - ss->ssl3.hs.finishedBytes = sizeof *hashes; - if (0 != NSS_SecureMemcmp(hashes, b, length)) { + ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes->u.s; + PORT_Assert(hashes->len == sizeof hashes->u.s); + ss->ssl3.hs.finishedBytes = sizeof hashes->u.s; + if (0 != NSS_SecureMemcmp(&hashes->u.s, b, length)) { (void)ssl3_HandshakeFailure(ss); PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); return SECFailure; @@ -11286,6 +11858,12 @@ ssl3_DestroySSL3Info(sslSocket *ss) if (ss->ssl3.hs.sha) { PK11_DestroyContext(ss->ssl3.hs.sha,PR_TRUE); } + if (ss->ssl3.hs.tls12_handshake_hash) { + PK11_DestroyContext(ss->ssl3.hs.tls12_handshake_hash,PR_TRUE); + } + if (ss->ssl3.hs.clientSigAndHash) { + PORT_Free(ss->ssl3.hs.clientSigAndHash); + } if (ss->ssl3.hs.messages.buf) { PORT_Free(ss->ssl3.hs.messages.buf); ss->ssl3.hs.messages.buf = NULL; diff --git a/net/third_party/nss/ssl/ssl3ecc.c b/net/third_party/nss/ssl/ssl3ecc.c index c8cee6d..3accbad2 100644 --- a/net/third_party/nss/ssl/ssl3ecc.c +++ b/net/third_party/nss/ssl/ssl3ecc.c @@ -31,6 +31,12 @@ #include <stdio.h> +/* This is a bodge to allow this code to be compiled against older NSS headers + * that don't contain the TLS 1.2 changes. */ +#ifndef CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 +#define CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 (CKM_NSS + 24) +#endif + #ifdef NSS_ENABLE_ECC /* @@ -217,9 +223,10 @@ params2ecName(SECKEYECParams * params) /* Caller must set hiLevel error code. */ static SECStatus -ssl3_ComputeECDHKeyHash(SECItem ec_params, SECItem server_ecpoint, - SSL3Random *client_rand, SSL3Random *server_rand, - SSL3Hashes *hashes, PRBool bypassPKCS11) +ssl3_ComputeECDHKeyHash(SECOidTag hashAlg, + SECItem ec_params, SECItem server_ecpoint, + SSL3Random *client_rand, SSL3Random *server_rand, + SSL3Hashes *hashes, PRBool bypassPKCS11) { PRUint8 * hashBuf; PRUint8 * pBuf; @@ -255,11 +262,14 @@ ssl3_ComputeECDHKeyHash(SECItem ec_params, SECItem server_ecpoint, pBuf += server_ecpoint.len; PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); - rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11); + rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, + bypassPKCS11); PRINT_BUF(95, (NULL, "ECDHkey hash: ", hashBuf, bufLen)); - PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", hashes->md5, MD5_LENGTH)); - PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); + PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", + hashes->u.s.md5, MD5_LENGTH)); + PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", + hashes->u.s.sha, SHA1_LENGTH)); if (hashBuf != buf) PORT_Free(hashBuf); @@ -273,7 +283,7 @@ ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) { PK11SymKey * pms = NULL; SECStatus rv = SECFailure; - PRBool isTLS; + PRBool isTLS, isTLS12; CK_MECHANISM_TYPE target; SECKEYPublicKey *pubKey = NULL; /* Ephemeral ECDH key */ SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */ @@ -282,6 +292,7 @@ ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); /* Generate ephemeral EC keypair */ if (svrPubKey->keyType != ecKey) { @@ -300,8 +311,13 @@ ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len)); - if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; - else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; + if (isTLS12) { + target = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256; + } else if (isTLS) { + target = CKM_TLS_MASTER_KEY_DERIVE_DH; + } else { + target = CKM_SSL3_MASTER_KEY_DERIVE_DH; + } /* Determine the PMS */ pms = PK11_PubDeriveWithKDF(privKey, svrPubKey, PR_FALSE, NULL, NULL, @@ -365,7 +381,7 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, SECStatus rv; SECKEYPublicKey clntPubKey; CK_MECHANISM_TYPE target; - PRBool isTLS; + PRBool isTLS, isTLS12; PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); @@ -384,9 +400,15 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, } isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; - else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; + if (isTLS12) { + target = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256; + } else if (isTLS) { + target = CKM_TLS_MASTER_KEY_DERIVE_DH; + } else { + target = CKM_SSL3_MASTER_KEY_DERIVE_DH; + } /* Determine the PMS */ pms = PK11_PubDeriveWithKDF(srvrPrivKey, &clntPubKey, PR_FALSE, NULL, NULL, @@ -582,7 +604,7 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) { PRArenaPool * arena = NULL; SECKEYPublicKey *peerKey = NULL; - PRBool isTLS; + PRBool isTLS, isTLS12; SECStatus rv; int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; SSL3AlertDescription desc = illegal_parameter; @@ -592,8 +614,12 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SECItem ec_params = {siBuffer, NULL, 0}; SECItem ec_point = {siBuffer, NULL, 0}; unsigned char paramBuf[3]; /* only for curve_type == named_curve */ + SSL3SignatureAndHashAlgorithm sigAndHash; + + sigAndHash.hashAlg = SEC_OID_UNKNOWN; isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); /* XXX This works only for named curves, revisit this when * we support generic curves. @@ -625,6 +651,19 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto alert_loser; } + if (isTLS12) { + rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, + &sigAndHash); + if (rv != SECSuccess) { + goto loser; /* malformed or unsupported. */ + } + rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( + &sigAndHash, ss->sec.peerCert); + if (rv != SECSuccess) { + goto loser; + } + } + rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ @@ -647,10 +686,10 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) /* * check to make sure the hash is signed by right guy */ - rv = ssl3_ComputeECDHKeyHash(ec_params, ec_point, - &ss->ssl3.hs.client_random, - &ss->ssl3.hs.server_random, - &hashes, ss->opt.bypassPKCS11); + rv = ssl3_ComputeECDHKeyHash(sigAndHash.hashAlg, ec_params, ec_point, + &ss->ssl3.hs.client_random, + &ss->ssl3.hs.server_random, + &hashes, ss->opt.bypassPKCS11); if (rv != SECSuccess) { errCode = @@ -714,12 +753,14 @@ no_memory: /* no-memory error has already been set. */ } SECStatus -ssl3_SendECDHServerKeyExchange(sslSocket *ss) +ssl3_SendECDHServerKeyExchange( + sslSocket *ss, + const SSL3SignatureAndHashAlgorithm *sigAndHash) { -const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; + const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; SECStatus rv = SECFailure; int length; - PRBool isTLS; + PRBool isTLS, isTLS12; SECItem signed_hash = {siBuffer, NULL, 0}; SSL3Hashes hashes; @@ -729,7 +770,6 @@ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; ECName curve; SSL3KEAType certIndex; - /* Generate ephemeral ECDH key pair and send the public key */ curve = ssl3_GetCurveNameForServerSocket(ss); if (curve == ec_noName) { @@ -758,16 +798,19 @@ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; goto loser; } - rv = ssl3_ComputeECDHKeyHash(ec_params, ecdhePub->u.ec.publicValue, - &ss->ssl3.hs.client_random, - &ss->ssl3.hs.server_random, - &hashes, ss->opt.bypassPKCS11); + rv = ssl3_ComputeECDHKeyHash(sigAndHash->hashAlg, + ec_params, + ecdhePub->u.ec.publicValue, + &ss->ssl3.hs.client_random, + &ss->ssl3.hs.server_random, + &hashes, ss->opt.bypassPKCS11); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); goto loser; } isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); /* XXX SSLKEAType isn't really a good choice for * indexing certificates but that's all we have @@ -791,7 +834,7 @@ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; length = ec_params.len + 1 + ecdhePub->u.ec.publicValue.len + - 2 + signed_hash.len; + (isTLS12 ? 2 : 0) + 2 + signed_hash.len; rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); if (rv != SECSuccess) { @@ -809,6 +852,13 @@ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; goto loser; /* err set by AppendHandshake. */ } + if (isTLS12) { + rv = ssl3_AppendSignatureAndHashAlgorithm(ss, sigAndHash); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + } + rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, signed_hash.len, 2); if (rv != SECSuccess) { diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c index bb7728d..5e6c4b78 100644 --- a/net/third_party/nss/ssl/ssl3ext.c +++ b/net/third_party/nss/ssl/ssl3ext.c @@ -74,6 +74,10 @@ static SECStatus ssl3_ClientHandleStatusRequestXtn(sslSocket *ss, SECItem *data); static PRInt32 ssl3_ClientSendStatusRequestXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes); +static PRInt32 ssl3_ClientSendSigAlgsXtn(sslSocket *ss, PRBool append, + PRUint32 maxBytes); +static SECStatus ssl3_ServerHandleSigAlgsXtn(sslSocket *ss, PRUint16 ex_type, + SECItem *data); /* * Write bytes. Using this function means the SECItem structure @@ -236,6 +240,7 @@ static const ssl3HelloExtensionHandler clientHelloHandlers[] = { { ssl_next_proto_nego_xtn, &ssl3_ServerHandleNextProtoNegoXtn }, { ssl_use_srtp_xtn, &ssl3_HandleUseSRTPXtn }, { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn }, + { ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn }, { -1, NULL } }; @@ -276,7 +281,8 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = { { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn }, { ssl_use_srtp_xtn, &ssl3_SendUseSRTPXtn }, { ssl_channel_id_xtn, &ssl3_ClientSendChannelIDXtn }, - { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn } + { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn }, + { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn } /* any extra entries will appear as { 0, NULL } */ }; @@ -2039,3 +2045,134 @@ ssl3_HandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) return ssl3_RegisterServerHelloExtensionSender(ss, ssl_use_srtp_xtn, ssl3_SendUseSRTPXtn); } + +/* ssl3_ServerHandleSigAlgsXtn handles the signature_algorithms extension + * from a client. + * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ +static SECStatus +ssl3_ServerHandleSigAlgsXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) +{ + SECStatus rv; + SECItem algorithms; + const unsigned char *b; + unsigned int numAlgorithms, i; + + /* Ignore this extension if we aren't doing TLS 1.2 or greater. */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) { + return SECSuccess; + } + + /* Keep track of negotiated extensions. */ + ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; + + rv = ssl3_ConsumeHandshakeVariable(ss, &algorithms, 2, &data->data, + &data->len); + if (rv != SECSuccess) { + return SECFailure; + } + /* Trailing data or odd-length parameters is invalid. */ + if (data->len != 0 || (algorithms.len & 1) != 0) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); + return SECFailure; + } + + numAlgorithms = algorithms.len/2; + + if (numAlgorithms == 0) { + return SECSuccess; + } + /* We don't care to process excessive numbers of algorithms. */ + if (numAlgorithms > 512) { + numAlgorithms = 512; + } + + ss->ssl3.hs.clientSigAndHash = + PORT_NewArray(SSL3SignatureAndHashAlgorithm, numAlgorithms); + if (!ss->ssl3.hs.clientSigAndHash) { + return SECFailure; + } + ss->ssl3.hs.numClientSigAndHash = 0; + + b = algorithms.data; + for (i = 0; i < numAlgorithms; i++) { + unsigned char tls_hash = *(b++); + unsigned char tls_sig = *(b++); + SECOidTag hash = ssl3_TLSHashAlgorithmToOID(tls_hash); + + if (hash == SEC_OID_UNKNOWN) { + /* We ignore formats that we don't understand. */ + continue; + } + /* tls_sig support will be checked later in + * ssl3_PickSignatureHashAlgorithm. */ + ss->ssl3.hs.clientSigAndHash[i].hashAlg = hash; + ss->ssl3.hs.clientSigAndHash[i].sigAlg = tls_sig; + ss->ssl3.hs.numClientSigAndHash++; + } + + if (!ss->ssl3.hs.numClientSigAndHash) { + /* We didn't understand any of the client's requested signature + * formats. We'll use the defaults. */ + PORT_Free(ss->ssl3.hs.clientSigAndHash); + ss->ssl3.hs.clientSigAndHash = NULL; + } + + return SECSuccess; +} + +/* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS + * 1.2 ClientHellos. */ +static PRInt32 +ssl3_ClientSendSigAlgsXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes) +{ + static const unsigned char signatureAlgorithms[] = { + /* This block is the contents of our signature_algorithms extension, in + * wire format. See + * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ + tls_hash_sha256, tls_sig_rsa, + tls_hash_sha384, tls_sig_rsa, + tls_hash_sha1, tls_sig_rsa, +#ifdef NSS_ENABLE_ECC + tls_hash_sha256, tls_sig_ecdsa, + tls_hash_sha384, tls_sig_ecdsa, + tls_hash_sha1, tls_sig_ecdsa, +#endif + tls_hash_sha256, tls_sig_dsa, + tls_hash_sha1, tls_sig_dsa, + }; + PRInt32 extension_length; + + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) { + return 0; + } + + extension_length = + 2 /* extension type */ + + 2 /* extension length */ + + 2 /* supported_signature_algorithms length */ + + sizeof(signatureAlgorithms); + + if (append && maxBytes >= extension_length) { + SECStatus rv; + rv = ssl3_AppendHandshakeNumber(ss, ssl_signature_algorithms_xtn, 2); + if (rv != SECSuccess) + goto loser; + rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); + if (rv != SECSuccess) + goto loser; + rv = ssl3_AppendHandshakeVariable(ss, signatureAlgorithms, + sizeof(signatureAlgorithms), 2); + if (rv != SECSuccess) + goto loser; + ss->xtnData.advertised[ss->xtnData.numAdvertised++] = + ssl_signature_algorithms_xtn; + } else if (maxBytes < extension_length) { + PORT_Assert(0); + return 0; + } + + return extension_length; + +loser: + return -1; +} diff --git a/net/third_party/nss/ssl/ssl3prot.h b/net/third_party/nss/ssl/ssl3prot.h index 50fd6fa..835a675 100644 --- a/net/third_party/nss/ssl/ssl3prot.h +++ b/net/third_party/nss/ssl/ssl3prot.h @@ -212,11 +212,51 @@ typedef struct { } u; } SSL3ServerParams; +/* This enum reflects HashAlgorithm enum from + * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 + * + * When updating, be sure to also update ssl3_TLSHashAlgorithmToOID. */ +enum { + tls_hash_md5 = 1, + tls_hash_sha1 = 2, + tls_hash_sha224 = 3, + tls_hash_sha256 = 4, + tls_hash_sha384 = 5, + tls_hash_sha512 = 6 +}; + +/* This enum reflects SignatureAlgorithm enum from + * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ +typedef enum { + tls_sig_rsa = 1, + tls_sig_dsa = 2, + tls_sig_ecdsa = 3 +} TLSSignatureAlgorithm; + +typedef struct { + SECOidTag hashAlg; + TLSSignatureAlgorithm sigAlg; +} SSL3SignatureAndHashAlgorithm; + +/* SSL3HashesIndividually contains a combination MD5/SHA1 hash, as used in TLS + * prior to 1.2. */ typedef struct { uint8 md5[16]; uint8 sha[20]; +} SSL3HashesIndividually; + +/* SSL3Hashes contains an SSL hash value. The digest is contained in |u.raw| + * which, if |hashAlg==SEC_OID_UNKNOWN| is also a SSL3HashesIndividually + * struct. */ +typedef struct { + unsigned int len; + SECOidTag hashAlg; + union { + PRUint8 raw[64]; + SSL3HashesIndividually s; + } u; } SSL3Hashes; - + typedef struct { union { SSL3Opaque anonymous; @@ -274,7 +314,7 @@ typedef enum { sender_server = 0x53525652 } SSL3Sender; -typedef SSL3Hashes SSL3Finished; +typedef SSL3HashesIndividually SSL3Finished; typedef struct { SSL3Opaque verify_data[12]; diff --git a/net/third_party/nss/ssl/sslerr.h b/net/third_party/nss/ssl/sslerr.h index 1c34965..4f8627c 100644 --- a/net/third_party/nss/ssl/sslerr.h +++ b/net/third_party/nss/ssl/sslerr.h @@ -194,6 +194,10 @@ SSL_ERROR_BAD_CHANNEL_ID_DATA = (SSL_ERROR_BASE + 126), SSL_ERROR_INVALID_CHANNEL_ID_KEY = (SSL_ERROR_BASE + 127), SSL_ERROR_GET_CHANNEL_ID_FAILED = (SSL_ERROR_BASE + 128), +SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM = (SSL_ERROR_BASE + 129), +SSL_ERROR_DIGEST_FAILURE = (SSL_ERROR_BASE + 130), +SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 131), + 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 e120498..5a42fa6 100644 --- a/net/third_party/nss/ssl/sslimpl.h +++ b/net/third_party/nss/ssl/sslimpl.h @@ -799,6 +799,7 @@ typedef struct SSL3HandshakeStateStr { PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS]; PK11Context * md5; /* handshake running hashes */ PK11Context * sha; + PK11Context * tls12_handshake_hash; const ssl3KEADef * kea_def; ssl3CipherSuite cipher_suite; const ssl3CipherSuiteDef *suite_def; @@ -820,7 +821,7 @@ const ssl3CipherSuiteDef *suite_def; PRUint16 finishedBytes; /* size of single finished below */ union { TLSFinished tFinished[2]; /* client, then server */ - SSL3Hashes sFinished[2]; + SSL3Finished sFinished[2]; SSL3Opaque data[72]; } finishedMsgs; #ifdef NSS_ENABLE_ECC @@ -835,6 +836,12 @@ const ssl3CipherSuiteDef *suite_def; /* Shared state between ssl3_HandleFinished and ssl3_FinishHandshake */ PRBool cacheSID; + /* clientSigAndHash contains the contents of the signature_algorithms + * extension (if any) from the client. This is only valid for TLS 1.2 + * or later. */ + SSL3SignatureAndHashAlgorithm *clientSigAndHash; + unsigned int numClientSigAndHash; + /* This group of values is used for DTLS */ PRUint16 sendMessageSeq; /* The sending message sequence * number */ @@ -1473,7 +1480,7 @@ extern PRInt32 ssl3_SendRecord(sslSocket *ss, DTLSEpoch epoch, * runtime to determine which versions are supported by the version of libssl * in use. */ -#define SSL_LIBRARY_VERSION_MAX_SUPPORTED SSL_LIBRARY_VERSION_TLS_1_1 +#define SSL_LIBRARY_VERSION_MAX_SUPPORTED SSL_LIBRARY_VERSION_TLS_1_2 /* Rename this macro SSL_ALL_VERSIONS_DISABLED when SSL 2.0 is removed. */ #define SSL3_ALL_VERSIONS_DISABLED(vrange) \ @@ -1639,10 +1646,12 @@ extern SECStatus ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length, SECKEYPublicKey *srvrPubKey, SECKEYPrivateKey *srvrPrivKey); -extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss); +extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss, + const SSL3SignatureAndHashAlgorithm *sigAndHash); #endif -extern SECStatus ssl3_ComputeCommonKeyHash(PRUint8 * hashBuf, +extern SECStatus ssl3_ComputeCommonKeyHash(SECOidTag hashAlg, + PRUint8 * hashBuf, unsigned int bufLen, SSL3Hashes *hashes, PRBool bypassPKCS11); extern void ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName); @@ -1655,12 +1664,21 @@ extern SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, PRInt32 lenSize); extern SECStatus ssl3_AppendHandshakeVariable( sslSocket *ss, const SSL3Opaque *src, PRInt32 bytes, PRInt32 lenSize); +extern SECStatus ssl3_AppendSignatureAndHashAlgorithm(sslSocket *ss, + const SSL3SignatureAndHashAlgorithm* sigAndHash); extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, SSL3Opaque **b, PRUint32 *length); extern PRInt32 ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, SSL3Opaque **b, PRUint32 *length); extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes, SSL3Opaque **b, PRUint32 *length); +extern SECOidTag ssl3_TLSHashAlgorithmToOID(int hashFunc); +extern SECStatus ssl3_CheckSignatureAndHashAlgorithmConsistency( + const SSL3SignatureAndHashAlgorithm *sigAndHash, + CERTCertificate* cert); +extern SECStatus ssl3_ConsumeSignatureAndHashAlgorithm(sslSocket *ss, + SSL3Opaque **b, PRUint32 *length, + SSL3SignatureAndHashAlgorithm *out); extern SECStatus ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf, PRBool isTLS); extern SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash, diff --git a/net/third_party/nss/ssl/sslplatf.c b/net/third_party/nss/ssl/sslplatf.c index bbe96db..83740ca 100644 --- a/net/third_party/nss/ssl/sslplatf.c +++ b/net/third_party/nss/ssl/sslplatf.c @@ -212,9 +212,8 @@ ssl3_CngPlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, DWORD dwFlags = 0; VOID *pPaddingInfo = NULL; - /* Always encode using PKCS#1 block type, with no OID/encoded DigestInfo */ + /* Always encode using PKCS#1 block type. */ BCRYPT_PKCS1_PADDING_INFO rsaPaddingInfo; - rsaPaddingInfo.pszAlgId = NULL; if (key->dwKeySpec != CERT_NCRYPT_KEY_SPEC) { PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); @@ -227,8 +226,29 @@ ssl3_CngPlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, switch (keyType) { case rsaKey: - hashItem.data = hash->md5; - hashItem.len = sizeof(SSL3Hashes); + switch (hash->hashAlg) { + case SEC_OID_UNKNOWN: + /* No OID/encoded DigestInfo. */ + rsaPaddingInfo.pszAlgId = NULL; + break; + case SEC_OID_SHA1: + rsaPaddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM; + break; + case SEC_OID_SHA256: + rsaPaddingInfo.pszAlgId = BCRYPT_SHA256_ALGORITHM; + break; + case SEC_OID_SHA384: + rsaPaddingInfo.pszAlgId = BCRYPT_SHA384_ALGORITHM; + break; + case SEC_OID_SHA512: + rsaPaddingInfo.pszAlgId = BCRYPT_SHA512_ALGORITHM; + break; + default: + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); + return SECFailure; + } + hashItem.data = hash->u.raw; + hashItem.len = hash->len; dwFlags = BCRYPT_PAD_PKCS1; pPaddingInfo = &rsaPaddingInfo; break; @@ -239,8 +259,13 @@ ssl3_CngPlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, } else { doDerEncode = isTLS; } - hashItem.data = hash->sha; - hashItem.len = sizeof(hash->sha); + if (hash->hashAlg == SEC_OID_UNKNOWN) { + hashItem.data = hash->u.s.sha; + hashItem.len = sizeof(hash->u.s.sha); + } else { + hashItem.data = hash->u.raw; + hashItem.len = hash->len; + } break; default: PORT_SetError(SEC_ERROR_INVALID_KEY); @@ -315,11 +340,34 @@ ssl3_CAPIPlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, buf->data = NULL; + switch (hash->hashAlg) { + case SEC_OID_UNKNOWN: + hashAlg = 0; + break; + case SEC_OID_SHA1: + hashAlg = CALG_SHA1; + break; + case SEC_OID_SHA256: + hashAlg = CALG_SHA_256; + break; + case SEC_OID_SHA384: + hashAlg = CALG_SHA_384; + break; + case SEC_OID_SHA512: + hashAlg = CALG_SHA_512; + break; + default: + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); + return SECFailure; + } + switch (keyType) { case rsaKey: - hashAlg = CALG_SSL3_SHAMD5; - hashItem.data = hash->md5; - hashItem.len = sizeof(SSL3Hashes); + if (hashAlg == 0) { + hashAlg = CALG_SSL3_SHAMD5; + } + hashItem.data = hash->u.raw; + hashItem.len = hash->len; break; case dsaKey: case ecKey: @@ -328,9 +376,14 @@ ssl3_CAPIPlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, } else { doDerEncode = isTLS; } - hashAlg = CALG_SHA1; - hashItem.data = hash->sha; - hashItem.len = sizeof(hash->sha); + if (hashAlg == 0) { + hashAlg = CALG_SHA1; + hashItem.data = hash->u.s.sha; + hashItem.len = sizeof(hash->u.s.sha); + } else { + hashItem.data = hash->u.raw; + hashItem.len = hash->len; + } break; default: PORT_SetError(SEC_ERROR_INVALID_KEY); @@ -468,11 +521,36 @@ ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, goto done; /* error code was set. */ sigAlg = cssmKey->KeyHeader.AlgorithmId; + if (keyType == rsaKey) { + PORT_Assert(sigAlg == CSSM_ALGID_RSA); + switch (hash->hashAlg) { + case SEC_OID_UNKNOWN: + break; + case SEC_OID_SHA1: + sigAlg = CSSM_ALGID_SHA1WithRSA; + break; + case SEC_OID_SHA224: + sigAlg = CSSM_ALGID_SHA224WithRSA; + break; + case SEC_OID_SHA256: + sigAlg = CSSM_ALGID_SHA256WithRSA; + break; + case SEC_OID_SHA384: + sigAlg = CSSM_ALGID_SHA384WithRSA; + break; + case SEC_OID_SHA512: + sigAlg = CSSM_ALGID_SHA512WithRSA; + break; + default: + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); + goto done; + } + } + switch (keyType) { case rsaKey: - PORT_Assert(sigAlg == CSSM_ALGID_RSA); - hashData.Data = hash->md5; - hashData.Length = sizeof(SSL3Hashes); + hashData.Data = hash->u.raw; + hashData.Length = hash->len; break; case dsaKey: case ecKey: @@ -483,8 +561,13 @@ ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, PORT_Assert(sigAlg == CSSM_ALGID_DSA); doDerEncode = isTLS; } - hashData.Data = hash->sha; - hashData.Length = sizeof(hash->sha); + if (hash->hashAlg == SEC_OID_UNKNOWN) { + hashData.Data = hash->u.s.sha; + hashData.Length = sizeof(hash->u.s.sha); + } else { + hashData.Data = hash->u.raw; + hashData.Length = hash->len; + } break; default: PORT_SetError(SEC_ERROR_INVALID_KEY); diff --git a/net/third_party/nss/ssl/sslproto.h b/net/third_party/nss/ssl/sslproto.h index 4acf6ab..228919b 100644 --- a/net/third_party/nss/ssl/sslproto.h +++ b/net/third_party/nss/ssl/sslproto.h @@ -16,6 +16,7 @@ #define SSL_LIBRARY_VERSION_3_0 0x0300 #define SSL_LIBRARY_VERSION_TLS_1_0 0x0301 #define SSL_LIBRARY_VERSION_TLS_1_1 0x0302 +#define SSL_LIBRARY_VERSION_TLS_1_2 0x0303 /* Note: this is the internal format, not the wire format */ #define SSL_LIBRARY_VERSION_DTLS_1_0 0x0302 diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c index c64b4fa..eaffbef 100644 --- a/net/third_party/nss/ssl/sslsock.c +++ b/net/third_party/nss/ssl/sslsock.c @@ -18,8 +18,15 @@ #ifndef NO_PKCS11_BYPASS #include "blapi.h" #endif +#include "pk11pub.h" #include "nss.h" +/* This is a bodge to allow this code to be compiled against older NSS headers + * that don't contain the TLS 1.2 changes. */ +#ifndef CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 +#define CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 (CKM_NSS + 24) +#endif + #define SET_ERROR_CODE /* reminder */ struct cipherPolicyStr { @@ -782,6 +789,17 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) rv = SECFailure; } else { if (PR_FALSE != on) { + /* TLS 1.2 isn't supported in bypass mode. */ + if (ss->vrange.min >= SSL_LIBRARY_VERSION_TLS_1_2) { + /* If the user requested a minimum version of TLS 1.2 then + * we don't silently downgrade. */ + PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE); + rv = SECFailure; + break; + } + if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_2) { + ss->vrange.max = SSL_LIBRARY_VERSION_TLS_1_1; + } if (PR_SUCCESS == SSL_BypassSetup() ) { #ifdef NO_PKCS11_BYPASS ss->opt.bypassPKCS11 = PR_FALSE; @@ -1895,6 +1913,24 @@ SSL_VersionRangeGet(PRFileDesc *fd, SSLVersionRange *vrange) return SECSuccess; } +static PRCallOnceType checkTLS12TokenOnce; +static PRBool tls12TokenExists; + +static PRStatus +ssl_CheckTLS12Token(void) +{ + tls12TokenExists = + PK11_TokenExists(CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256); + return PR_SUCCESS; +} + +static PRBool +ssl_TLS12TokenExists(void) +{ + (void) PR_CallOnce(&checkTLS12TokenOnce, ssl_CheckTLS12Token); + return tls12TokenExists; +} + SECStatus SSL_VersionRangeSet(PRFileDesc *fd, const SSLVersionRange *vrange) { @@ -1915,6 +1951,24 @@ SSL_VersionRangeSet(PRFileDesc *fd, const SSLVersionRange *vrange) ssl_GetSSL3HandshakeLock(ss); ss->vrange = *vrange; + /* If we don't have a sufficiently up-to-date softoken then we cannot do + * TLS 1.2. */ + if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_2 && + !ssl_TLS12TokenExists()) { + /* If the user requested a minimum version of 1.2, then we don't + * silently downgrade. */ + if (ss->vrange.min >= SSL_LIBRARY_VERSION_TLS_1_2) { + ssl_ReleaseSSL3HandshakeLock(ss); + ssl_Release1stHandshakeLock(ss); + PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE); + return SECFailure; + } + ss->vrange.max = SSL_LIBRARY_VERSION_TLS_1_1; + } + /* PKCS#11 bypass is not supported with TLS 1.2. */ + if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_2) { + ss->opt.bypassPKCS11 = PR_FALSE; + } ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); diff --git a/net/third_party/nss/ssl/sslt.h b/net/third_party/nss/ssl/sslt.h index 8254df8..e5067e6 100644 --- a/net/third_party/nss/ssl/sslt.h +++ b/net/third_party/nss/ssl/sslt.h @@ -193,6 +193,7 @@ typedef enum { ssl_elliptic_curves_xtn = 10, ssl_ec_point_formats_xtn = 11, #endif + ssl_signature_algorithms_xtn = 13, ssl_use_srtp_xtn = 14, ssl_session_ticket_xtn = 35, ssl_next_proto_nego_xtn = 13172, @@ -200,6 +201,6 @@ typedef enum { ssl_renegotiation_info_xtn = 0xff01 /* experimental number */ } SSLExtensionType; -#define SSL_MAX_EXTENSIONS 9 +#define SSL_MAX_EXTENSIONS 10 #endif /* __sslt_h_ */ |