summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-30 05:52:51 +0000
committerwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-30 05:52:51 +0000
commit7799de1ae747dcbd2e54f650539850fb6c139b1a (patch)
tree68e30cfd82a1b9ee944ecbb922994589caac1a77 /net
parente67140ee9ee65723732edb6a145b38030e142807 (diff)
downloadchromium_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.cc15
-rw-r--r--net/http/http_network_transaction_spdy3_unittest.cc15
-rw-r--r--net/ssl/ssl_config_service.cc6
-rw-r--r--net/third_party/nss/README.chromium7
-rwxr-xr-xnet/third_party/nss/patches/applypatches.sh4
-rw-r--r--net/third_party/nss/patches/tls12.patch1942
-rw-r--r--net/third_party/nss/patches/tls12chromium.patch317
-rw-r--r--net/third_party/nss/ssl/SSLerrs.h9
-rw-r--r--net/third_party/nss/ssl/ssl3con.c852
-rw-r--r--net/third_party/nss/ssl/ssl3ecc.c102
-rw-r--r--net/third_party/nss/ssl/ssl3ext.c139
-rw-r--r--net/third_party/nss/ssl/ssl3prot.h44
-rw-r--r--net/third_party/nss/ssl/sslerr.h4
-rw-r--r--net/third_party/nss/ssl/sslimpl.h26
-rw-r--r--net/third_party/nss/ssl/sslplatf.c117
-rw-r--r--net/third_party/nss/ssl/sslproto.h1
-rw-r--r--net/third_party/nss/ssl/sslsock.c54
-rw-r--r--net/third_party/nss/ssl/sslt.h3
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, &param);
++ 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, &param);
+ 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, &param);
+ 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, &param);
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_ */