Index: net/third_party/nss/patches/tls12.patch |
=================================================================== |
--- net/third_party/nss/patches/tls12.patch (revision 0) |
+++ net/third_party/nss/patches/tls12.patch (revision 0) |
@@ -0,0 +1,1942 @@ |
+Index: net/third_party/nss/ssl/sslt.h |
+=================================================================== |
+--- net/third_party/nss/ssl/sslt.h (revision 202696) |
++++ net/third_party/nss/ssl/sslt.h (working copy) |
+@@ -193,6 +193,7 @@ |
+ ssl_elliptic_curves_xtn = 10, |
+ ssl_ec_point_formats_xtn = 11, |
+ #endif |
++ ssl_signature_algorithms_xtn = 13, |
+ ssl_use_srtp_xtn = 14, |
+ ssl_session_ticket_xtn = 35, |
+ ssl_next_proto_nego_xtn = 13172, |
+@@ -200,6 +201,6 @@ |
+ ssl_renegotiation_info_xtn = 0xff01 /* experimental number */ |
+ } SSLExtensionType; |
+ |
+-#define SSL_MAX_EXTENSIONS 9 |
++#define SSL_MAX_EXTENSIONS 10 |
+ |
+ #endif /* __sslt_h_ */ |
+Index: net/third_party/nss/ssl/sslproto.h |
+=================================================================== |
+--- net/third_party/nss/ssl/sslproto.h (revision 202696) |
++++ net/third_party/nss/ssl/sslproto.h (working copy) |
+@@ -16,6 +16,7 @@ |
+ #define SSL_LIBRARY_VERSION_3_0 0x0300 |
+ #define SSL_LIBRARY_VERSION_TLS_1_0 0x0301 |
+ #define SSL_LIBRARY_VERSION_TLS_1_1 0x0302 |
++#define SSL_LIBRARY_VERSION_TLS_1_2 0x0303 |
+ /* Note: this is the internal format, not the wire format */ |
+ #define SSL_LIBRARY_VERSION_DTLS_1_0 0x0302 |
+ |
+Index: net/third_party/nss/ssl/SSLerrs.h |
+=================================================================== |
+--- net/third_party/nss/ssl/SSLerrs.h (revision 202696) |
++++ net/third_party/nss/ssl/SSLerrs.h (working copy) |
+@@ -412,3 +412,12 @@ |
+ |
+ ER3(SSL_ERROR_GET_CHANNEL_ID_FAILED, (SSL_ERROR_BASE + 128), |
+ "The application could not get a TLS Channel ID.") |
++ |
++ER3(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM, (SSL_ERROR_BASE + 129), |
++"Unsupported hash algorithm used by TLS peer.") |
++ |
++ER3(SSL_ERROR_DIGEST_FAILURE, (SSL_ERROR_BASE + 130), |
++"Digest function failed.") |
++ |
++ER3(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, (SSL_ERROR_BASE + 131), |
++"Incorrect signature algorithm specified in a digitally-signed element.") |
+Index: net/third_party/nss/ssl/sslerr.h |
+=================================================================== |
+--- net/third_party/nss/ssl/sslerr.h (revision 202696) |
++++ net/third_party/nss/ssl/sslerr.h (working copy) |
+@@ -194,6 +194,10 @@ |
+ SSL_ERROR_INVALID_CHANNEL_ID_KEY = (SSL_ERROR_BASE + 127), |
+ SSL_ERROR_GET_CHANNEL_ID_FAILED = (SSL_ERROR_BASE + 128), |
+ |
++SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM = (SSL_ERROR_BASE + 129), |
++SSL_ERROR_DIGEST_FAILURE = (SSL_ERROR_BASE + 130), |
++SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 131), |
++ |
+ SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ |
+ } SSLErrorCodes; |
+ #endif /* NO_SECURITY_ERROR_ENUM */ |
+Index: net/third_party/nss/ssl/sslimpl.h |
+=================================================================== |
+--- net/third_party/nss/ssl/sslimpl.h (revision 202696) |
++++ net/third_party/nss/ssl/sslimpl.h (working copy) |
+@@ -799,6 +799,7 @@ |
+ PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS]; |
+ PK11Context * md5; /* handshake running hashes */ |
+ PK11Context * sha; |
++ PK11Context * tls12_handshake_hash; |
+ const ssl3KEADef * kea_def; |
+ ssl3CipherSuite cipher_suite; |
+ const ssl3CipherSuiteDef *suite_def; |
+@@ -820,7 +821,7 @@ |
+ PRUint16 finishedBytes; /* size of single finished below */ |
+ union { |
+ TLSFinished tFinished[2]; /* client, then server */ |
+- SSL3Hashes sFinished[2]; |
++ SSL3Finished sFinished[2]; |
+ SSL3Opaque data[72]; |
+ } finishedMsgs; |
+ #ifdef NSS_ENABLE_ECC |
+@@ -835,6 +836,12 @@ |
+ /* Shared state between ssl3_HandleFinished and ssl3_FinishHandshake */ |
+ PRBool cacheSID; |
+ |
++ /* clientSigAndHash contains the contents of the signature_algorithms |
++ * extension (if any) from the client. This is only valid for TLS 1.2 |
++ * or later. */ |
++ SSL3SignatureAndHashAlgorithm *clientSigAndHash; |
++ unsigned int numClientSigAndHash; |
++ |
+ /* This group of values is used for DTLS */ |
+ PRUint16 sendMessageSeq; /* The sending message sequence |
+ * number */ |
+@@ -1473,7 +1480,7 @@ |
+ * runtime to determine which versions are supported by the version of libssl |
+ * in use. |
+ */ |
+-#define SSL_LIBRARY_VERSION_MAX_SUPPORTED SSL_LIBRARY_VERSION_TLS_1_1 |
++#define SSL_LIBRARY_VERSION_MAX_SUPPORTED SSL_LIBRARY_VERSION_TLS_1_2 |
+ |
+ /* Rename this macro SSL_ALL_VERSIONS_DISABLED when SSL 2.0 is removed. */ |
+ #define SSL3_ALL_VERSIONS_DISABLED(vrange) \ |
+@@ -1639,10 +1646,12 @@ |
+ SSL3Opaque *b, PRUint32 length, |
+ SECKEYPublicKey *srvrPubKey, |
+ SECKEYPrivateKey *srvrPrivKey); |
+-extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss); |
++extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss, |
++ const SSL3SignatureAndHashAlgorithm *sigAndHash); |
+ #endif |
+ |
+-extern SECStatus ssl3_ComputeCommonKeyHash(PRUint8 * hashBuf, |
++extern SECStatus ssl3_ComputeCommonKeyHash(SECOidTag hashAlg, |
++ PRUint8 * hashBuf, |
+ unsigned int bufLen, SSL3Hashes *hashes, |
+ PRBool bypassPKCS11); |
+ extern void ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName); |
+@@ -1655,12 +1664,21 @@ |
+ PRInt32 lenSize); |
+ extern SECStatus ssl3_AppendHandshakeVariable( sslSocket *ss, |
+ const SSL3Opaque *src, PRInt32 bytes, PRInt32 lenSize); |
++extern SECStatus ssl3_AppendSignatureAndHashAlgorithm(sslSocket *ss, |
++ const SSL3SignatureAndHashAlgorithm* sigAndHash); |
+ extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, |
+ SSL3Opaque **b, PRUint32 *length); |
+ extern PRInt32 ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, |
+ SSL3Opaque **b, PRUint32 *length); |
+ extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, |
+ PRInt32 bytes, SSL3Opaque **b, PRUint32 *length); |
++extern SECOidTag ssl3_TLSHashAlgorithmToOID(int hashFunc); |
++extern SECStatus ssl3_CheckSignatureAndHashAlgorithmConsistency( |
++ const SSL3SignatureAndHashAlgorithm *sigAndHash, |
++ CERTCertificate* cert); |
++extern SECStatus ssl3_ConsumeSignatureAndHashAlgorithm(sslSocket *ss, |
++ SSL3Opaque **b, PRUint32 *length, |
++ SSL3SignatureAndHashAlgorithm *out); |
+ extern SECStatus ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, |
+ SECItem *buf, PRBool isTLS); |
+ extern SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash, |
+Index: net/third_party/nss/ssl/ssl3prot.h |
+=================================================================== |
+--- net/third_party/nss/ssl/ssl3prot.h (revision 202696) |
++++ net/third_party/nss/ssl/ssl3prot.h (working copy) |
+@@ -212,11 +212,51 @@ |
+ } u; |
+ } SSL3ServerParams; |
+ |
++/* This enum reflects HashAlgorithm enum from |
++ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 |
++ * |
++ * When updating, be sure to also update ssl3_TLSHashAlgorithmToOID. */ |
++enum { |
++ tls_hash_md5 = 1, |
++ tls_hash_sha1 = 2, |
++ tls_hash_sha224 = 3, |
++ tls_hash_sha256 = 4, |
++ tls_hash_sha384 = 5, |
++ tls_hash_sha512 = 6 |
++}; |
++ |
++/* This enum reflects SignatureAlgorithm enum from |
++ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ |
++typedef enum { |
++ tls_sig_rsa = 1, |
++ tls_sig_dsa = 2, |
++ tls_sig_ecdsa = 3 |
++} TLSSignatureAlgorithm; |
++ |
+ typedef struct { |
++ SECOidTag hashAlg; |
++ TLSSignatureAlgorithm sigAlg; |
++} SSL3SignatureAndHashAlgorithm; |
++ |
++/* SSL3HashesIndividually contains a combination MD5/SHA1 hash, as used in TLS |
++ * prior to 1.2. */ |
++typedef struct { |
+ uint8 md5[16]; |
+ uint8 sha[20]; |
++} SSL3HashesIndividually; |
++ |
++/* SSL3Hashes contains an SSL hash value. The digest is contained in |u.raw| |
++ * which, if |hashAlg==SEC_OID_UNKNOWN| is also a SSL3HashesIndividually |
++ * struct. */ |
++typedef struct { |
++ unsigned int len; |
++ SECOidTag hashAlg; |
++ union { |
++ PRUint8 raw[64]; |
++ SSL3HashesIndividually s; |
++ } u; |
+ } SSL3Hashes; |
+- |
++ |
+ typedef struct { |
+ union { |
+ SSL3Opaque anonymous; |
+@@ -274,7 +314,7 @@ |
+ sender_server = 0x53525652 |
+ } SSL3Sender; |
+ |
+-typedef SSL3Hashes SSL3Finished; |
++typedef SSL3HashesIndividually SSL3Finished; |
+ |
+ typedef struct { |
+ SSL3Opaque verify_data[12]; |
+Index: net/third_party/nss/ssl/ssl3ecc.c |
+=================================================================== |
+--- net/third_party/nss/ssl/ssl3ecc.c (revision 202696) |
++++ net/third_party/nss/ssl/ssl3ecc.c (working copy) |
+@@ -217,9 +223,10 @@ |
+ |
+ /* Caller must set hiLevel error code. */ |
+ static SECStatus |
+-ssl3_ComputeECDHKeyHash(SECItem ec_params, SECItem server_ecpoint, |
+- SSL3Random *client_rand, SSL3Random *server_rand, |
+- SSL3Hashes *hashes, PRBool bypassPKCS11) |
++ssl3_ComputeECDHKeyHash(SECOidTag hashAlg, |
++ SECItem ec_params, SECItem server_ecpoint, |
++ SSL3Random *client_rand, SSL3Random *server_rand, |
++ SSL3Hashes *hashes, PRBool bypassPKCS11) |
+ { |
+ PRUint8 * hashBuf; |
+ PRUint8 * pBuf; |
+@@ -255,11 +262,14 @@ |
+ pBuf += server_ecpoint.len; |
+ PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); |
+ |
+- rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11); |
++ rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, |
++ bypassPKCS11); |
+ |
+ PRINT_BUF(95, (NULL, "ECDHkey hash: ", hashBuf, bufLen)); |
+- PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", hashes->md5, MD5_LENGTH)); |
+- PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); |
++ PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", |
++ hashes->u.s.md5, MD5_LENGTH)); |
++ PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", |
++ hashes->u.s.sha, SHA1_LENGTH)); |
+ |
+ if (hashBuf != buf) |
+ PORT_Free(hashBuf); |
+@@ -273,7 +283,7 @@ |
+ { |
+ PK11SymKey * pms = NULL; |
+ SECStatus rv = SECFailure; |
+- PRBool isTLS; |
++ PRBool isTLS, isTLS12; |
+ CK_MECHANISM_TYPE target; |
+ SECKEYPublicKey *pubKey = NULL; /* Ephemeral ECDH key */ |
+ SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */ |
+@@ -282,6 +292,7 @@ |
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); |
+ |
+ isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); |
++ isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); |
+ |
+ /* Generate ephemeral EC keypair */ |
+ if (svrPubKey->keyType != ecKey) { |
+@@ -300,8 +311,13 @@ |
+ pubKey->u.ec.publicValue.data, |
+ pubKey->u.ec.publicValue.len)); |
+ |
+- if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; |
+- else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; |
++ if (isTLS12) { |
++ target = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256; |
++ } else if (isTLS) { |
++ target = CKM_TLS_MASTER_KEY_DERIVE_DH; |
++ } else { |
++ target = CKM_SSL3_MASTER_KEY_DERIVE_DH; |
++ } |
+ |
+ /* Determine the PMS */ |
+ pms = PK11_PubDeriveWithKDF(privKey, svrPubKey, PR_FALSE, NULL, NULL, |
+@@ -365,7 +381,7 @@ |
+ SECStatus rv; |
+ SECKEYPublicKey clntPubKey; |
+ CK_MECHANISM_TYPE target; |
+- PRBool isTLS; |
++ PRBool isTLS, isTLS12; |
+ |
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); |
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); |
+@@ -384,9 +400,15 @@ |
+ } |
+ |
+ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); |
++ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); |
+ |
+- if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; |
+- else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; |
++ if (isTLS12) { |
++ target = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256; |
++ } else if (isTLS) { |
++ target = CKM_TLS_MASTER_KEY_DERIVE_DH; |
++ } else { |
++ target = CKM_SSL3_MASTER_KEY_DERIVE_DH; |
++ } |
+ |
+ /* Determine the PMS */ |
+ pms = PK11_PubDeriveWithKDF(srvrPrivKey, &clntPubKey, PR_FALSE, NULL, NULL, |
+@@ -582,7 +604,7 @@ |
+ { |
+ PRArenaPool * arena = NULL; |
+ SECKEYPublicKey *peerKey = NULL; |
+- PRBool isTLS; |
++ PRBool isTLS, isTLS12; |
+ SECStatus rv; |
+ int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; |
+ SSL3AlertDescription desc = illegal_parameter; |
+@@ -592,8 +614,12 @@ |
+ SECItem ec_params = {siBuffer, NULL, 0}; |
+ SECItem ec_point = {siBuffer, NULL, 0}; |
+ unsigned char paramBuf[3]; /* only for curve_type == named_curve */ |
++ SSL3SignatureAndHashAlgorithm sigAndHash; |
+ |
++ sigAndHash.hashAlg = SEC_OID_UNKNOWN; |
++ |
+ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); |
++ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); |
+ |
+ /* XXX This works only for named curves, revisit this when |
+ * we support generic curves. |
+@@ -625,6 +651,19 @@ |
+ goto alert_loser; |
+ } |
+ |
++ if (isTLS12) { |
++ rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, |
++ &sigAndHash); |
++ if (rv != SECSuccess) { |
++ goto loser; /* malformed or unsupported. */ |
++ } |
++ rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( |
++ &sigAndHash, ss->sec.peerCert); |
++ if (rv != SECSuccess) { |
++ goto loser; |
++ } |
++ } |
++ |
+ rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); |
+ if (rv != SECSuccess) { |
+ goto loser; /* malformed. */ |
+@@ -647,10 +686,10 @@ |
+ /* |
+ * check to make sure the hash is signed by right guy |
+ */ |
+- rv = ssl3_ComputeECDHKeyHash(ec_params, ec_point, |
+- &ss->ssl3.hs.client_random, |
+- &ss->ssl3.hs.server_random, |
+- &hashes, ss->opt.bypassPKCS11); |
++ rv = ssl3_ComputeECDHKeyHash(sigAndHash.hashAlg, ec_params, ec_point, |
++ &ss->ssl3.hs.client_random, |
++ &ss->ssl3.hs.server_random, |
++ &hashes, ss->opt.bypassPKCS11); |
+ |
+ if (rv != SECSuccess) { |
+ errCode = |
+@@ -714,12 +753,14 @@ |
+ } |
+ |
+ SECStatus |
+-ssl3_SendECDHServerKeyExchange(sslSocket *ss) |
++ssl3_SendECDHServerKeyExchange( |
++ sslSocket *ss, |
++ const SSL3SignatureAndHashAlgorithm *sigAndHash) |
+ { |
+-const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; |
++ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; |
+ SECStatus rv = SECFailure; |
+ int length; |
+- PRBool isTLS; |
++ PRBool isTLS, isTLS12; |
+ SECItem signed_hash = {siBuffer, NULL, 0}; |
+ SSL3Hashes hashes; |
+ |
+@@ -729,7 +770,6 @@ |
+ ECName curve; |
+ SSL3KEAType certIndex; |
+ |
+- |
+ /* Generate ephemeral ECDH key pair and send the public key */ |
+ curve = ssl3_GetCurveNameForServerSocket(ss); |
+ if (curve == ec_noName) { |
+@@ -758,16 +798,19 @@ |
+ goto loser; |
+ } |
+ |
+- rv = ssl3_ComputeECDHKeyHash(ec_params, ecdhePub->u.ec.publicValue, |
+- &ss->ssl3.hs.client_random, |
+- &ss->ssl3.hs.server_random, |
+- &hashes, ss->opt.bypassPKCS11); |
++ rv = ssl3_ComputeECDHKeyHash(sigAndHash->hashAlg, |
++ ec_params, |
++ ecdhePub->u.ec.publicValue, |
++ &ss->ssl3.hs.client_random, |
++ &ss->ssl3.hs.server_random, |
++ &hashes, ss->opt.bypassPKCS11); |
+ if (rv != SECSuccess) { |
+ ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); |
+ goto loser; |
+ } |
+ |
+ isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); |
++ isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); |
+ |
+ /* XXX SSLKEAType isn't really a good choice for |
+ * indexing certificates but that's all we have |
+@@ -791,7 +834,7 @@ |
+ |
+ length = ec_params.len + |
+ 1 + ecdhePub->u.ec.publicValue.len + |
+- 2 + signed_hash.len; |
++ (isTLS12 ? 2 : 0) + 2 + signed_hash.len; |
+ |
+ rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); |
+ if (rv != SECSuccess) { |
+@@ -809,6 +852,13 @@ |
+ goto loser; /* err set by AppendHandshake. */ |
+ } |
+ |
++ if (isTLS12) { |
++ rv = ssl3_AppendSignatureAndHashAlgorithm(ss, sigAndHash); |
++ if (rv != SECSuccess) { |
++ goto loser; /* err set by AppendHandshake. */ |
++ } |
++ } |
++ |
+ rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, |
+ signed_hash.len, 2); |
+ if (rv != SECSuccess) { |
+Index: net/third_party/nss/ssl/ssl3ext.c |
+=================================================================== |
+--- net/third_party/nss/ssl/ssl3ext.c (revision 202696) |
++++ net/third_party/nss/ssl/ssl3ext.c (working copy) |
+@@ -74,6 +74,10 @@ |
+ SECItem *data); |
+ static PRInt32 ssl3_ClientSendStatusRequestXtn(sslSocket * ss, PRBool append, |
+ PRUint32 maxBytes); |
++static PRInt32 ssl3_ClientSendSigAlgsXtn(sslSocket *ss, PRBool append, |
++ PRUint32 maxBytes); |
++static SECStatus ssl3_ServerHandleSigAlgsXtn(sslSocket *ss, PRUint16 ex_type, |
++ SECItem *data); |
+ |
+ /* |
+ * Write bytes. Using this function means the SECItem structure |
+@@ -236,6 +240,7 @@ |
+ { ssl_next_proto_nego_xtn, &ssl3_ServerHandleNextProtoNegoXtn }, |
+ { ssl_use_srtp_xtn, &ssl3_HandleUseSRTPXtn }, |
+ { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn }, |
++ { ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn }, |
+ { -1, NULL } |
+ }; |
+ |
+@@ -276,7 +281,8 @@ |
+ { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn }, |
+ { ssl_use_srtp_xtn, &ssl3_SendUseSRTPXtn }, |
+ { ssl_channel_id_xtn, &ssl3_ClientSendChannelIDXtn }, |
+- { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn } |
++ { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn }, |
++ { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn } |
+ /* any extra entries will appear as { 0, NULL } */ |
+ }; |
+ |
+@@ -2039,3 +2045,134 @@ |
+ return ssl3_RegisterServerHelloExtensionSender(ss, ssl_use_srtp_xtn, |
+ ssl3_SendUseSRTPXtn); |
+ } |
++ |
++/* ssl3_ServerHandleSigAlgsXtn handles the signature_algorithms extension |
++ * from a client. |
++ * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ |
++static SECStatus |
++ssl3_ServerHandleSigAlgsXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data) |
++{ |
++ SECStatus rv; |
++ SECItem algorithms; |
++ const unsigned char *b; |
++ unsigned int numAlgorithms, i; |
++ |
++ /* Ignore this extension if we aren't doing TLS 1.2 or greater. */ |
++ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) { |
++ return SECSuccess; |
++ } |
++ |
++ /* Keep track of negotiated extensions. */ |
++ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; |
++ |
++ rv = ssl3_ConsumeHandshakeVariable(ss, &algorithms, 2, &data->data, |
++ &data->len); |
++ if (rv != SECSuccess) { |
++ return SECFailure; |
++ } |
++ /* Trailing data or odd-length parameters is invalid. */ |
++ if (data->len != 0 || (algorithms.len & 1) != 0) { |
++ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); |
++ return SECFailure; |
++ } |
++ |
++ numAlgorithms = algorithms.len/2; |
++ |
++ if (numAlgorithms == 0) { |
++ return SECSuccess; |
++ } |
++ /* We don't care to process excessive numbers of algorithms. */ |
++ if (numAlgorithms > 512) { |
++ numAlgorithms = 512; |
++ } |
++ |
++ ss->ssl3.hs.clientSigAndHash = |
++ PORT_NewArray(SSL3SignatureAndHashAlgorithm, numAlgorithms); |
++ if (!ss->ssl3.hs.clientSigAndHash) { |
++ return SECFailure; |
++ } |
++ ss->ssl3.hs.numClientSigAndHash = 0; |
++ |
++ b = algorithms.data; |
++ for (i = 0; i < numAlgorithms; i++) { |
++ unsigned char tls_hash = *(b++); |
++ unsigned char tls_sig = *(b++); |
++ SECOidTag hash = ssl3_TLSHashAlgorithmToOID(tls_hash); |
++ |
++ if (hash == SEC_OID_UNKNOWN) { |
++ /* We ignore formats that we don't understand. */ |
++ continue; |
++ } |
++ /* tls_sig support will be checked later in |
++ * ssl3_PickSignatureHashAlgorithm. */ |
++ ss->ssl3.hs.clientSigAndHash[i].hashAlg = hash; |
++ ss->ssl3.hs.clientSigAndHash[i].sigAlg = tls_sig; |
++ ss->ssl3.hs.numClientSigAndHash++; |
++ } |
++ |
++ if (!ss->ssl3.hs.numClientSigAndHash) { |
++ /* We didn't understand any of the client's requested signature |
++ * formats. We'll use the defaults. */ |
++ PORT_Free(ss->ssl3.hs.clientSigAndHash); |
++ ss->ssl3.hs.clientSigAndHash = NULL; |
++ } |
++ |
++ return SECSuccess; |
++} |
++ |
++/* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS |
++ * 1.2 ClientHellos. */ |
++static PRInt32 |
++ssl3_ClientSendSigAlgsXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes) |
++{ |
++ static const unsigned char signatureAlgorithms[] = { |
++ /* This block is the contents of our signature_algorithms extension, in |
++ * wire format. See |
++ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ |
++ tls_hash_sha256, tls_sig_rsa, |
++ tls_hash_sha384, tls_sig_rsa, |
++ tls_hash_sha1, tls_sig_rsa, |
++#ifdef NSS_ENABLE_ECC |
++ tls_hash_sha256, tls_sig_ecdsa, |
++ tls_hash_sha384, tls_sig_ecdsa, |
++ tls_hash_sha1, tls_sig_ecdsa, |
++#endif |
++ tls_hash_sha256, tls_sig_dsa, |
++ tls_hash_sha1, tls_sig_dsa, |
++ }; |
++ PRInt32 extension_length; |
++ |
++ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) { |
++ return 0; |
++ } |
++ |
++ extension_length = |
++ 2 /* extension type */ + |
++ 2 /* extension length */ + |
++ 2 /* supported_signature_algorithms length */ + |
++ sizeof(signatureAlgorithms); |
++ |
++ if (append && maxBytes >= extension_length) { |
++ SECStatus rv; |
++ rv = ssl3_AppendHandshakeNumber(ss, ssl_signature_algorithms_xtn, 2); |
++ if (rv != SECSuccess) |
++ goto loser; |
++ rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); |
++ if (rv != SECSuccess) |
++ goto loser; |
++ rv = ssl3_AppendHandshakeVariable(ss, signatureAlgorithms, |
++ sizeof(signatureAlgorithms), 2); |
++ if (rv != SECSuccess) |
++ goto loser; |
++ ss->xtnData.advertised[ss->xtnData.numAdvertised++] = |
++ ssl_signature_algorithms_xtn; |
++ } else if (maxBytes < extension_length) { |
++ PORT_Assert(0); |
++ return 0; |
++ } |
++ |
++ return extension_length; |
++ |
++loser: |
++ return -1; |
++} |
+Index: net/third_party/nss/ssl/sslsock.c |
+=================================================================== |
+--- net/third_party/nss/ssl/sslsock.c (revision 202696) |
++++ net/third_party/nss/ssl/sslsock.c (working copy) |
+@@ -782,6 +789,17 @@ |
+ rv = SECFailure; |
+ } else { |
+ if (PR_FALSE != on) { |
++ /* TLS 1.2 isn't supported in bypass mode. */ |
++ if (ss->vrange.min >= SSL_LIBRARY_VERSION_TLS_1_2) { |
++ /* If the user requested a minimum version of TLS 1.2 then |
++ * we don't silently downgrade. */ |
++ PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE); |
++ rv = SECFailure; |
++ break; |
++ } |
++ if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_2) { |
++ ss->vrange.max = SSL_LIBRARY_VERSION_TLS_1_1; |
++ } |
+ if (PR_SUCCESS == SSL_BypassSetup() ) { |
+ #ifdef NO_PKCS11_BYPASS |
+ ss->opt.bypassPKCS11 = PR_FALSE; |
+Index: net/third_party/nss/ssl/ssl3con.c |
+=================================================================== |
+--- net/third_party/nss/ssl/ssl3con.c (revision 202696) |
++++ net/third_party/nss/ssl/ssl3con.c (working copy) |
+@@ -15,6 +15,7 @@ |
+ #include "keyhi.h" |
+ #include "secder.h" |
+ #include "secitem.h" |
++#include "sechash.h" |
+ |
+ #include "sslimpl.h" |
+ #include "sslproto.h" |
+@@ -64,6 +74,7 @@ |
+ const unsigned char *b, |
+ unsigned int l); |
+ static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags); |
++static int ssl3_OIDToTLSHashAlgorithm(SECOidTag oid); |
+ |
+ static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen, |
+ int maxOutputLen, const unsigned char *input, |
+@@ -811,32 +822,36 @@ |
+ SECItem hashItem; |
+ |
+ buf->data = NULL; |
+- signatureLen = PK11_SignatureLen(key); |
+- if (signatureLen <= 0) { |
+- PORT_SetError(SEC_ERROR_INVALID_KEY); |
+- goto done; |
+- } |
+ |
+- buf->len = (unsigned)signatureLen; |
+- buf->data = (unsigned char *)PORT_Alloc(signatureLen); |
+- if (!buf->data) |
+- goto done; /* error code was set. */ |
+- |
+ switch (key->keyType) { |
+ case rsaKey: |
+- hashItem.data = hash->md5; |
+- hashItem.len = sizeof(SSL3Hashes); |
++ hashItem.data = hash->u.raw; |
++ hashItem.len = hash->len; |
+ break; |
+ case dsaKey: |
+ doDerEncode = isTLS; |
+- hashItem.data = hash->sha; |
+- hashItem.len = sizeof(hash->sha); |
++ /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash. |
++ * In that case, we use just the SHA1 part. */ |
++ if (hash->hashAlg == SEC_OID_UNKNOWN) { |
++ hashItem.data = hash->u.s.sha; |
++ hashItem.len = sizeof(hash->u.s.sha); |
++ } else { |
++ hashItem.data = hash->u.raw; |
++ hashItem.len = hash->len; |
++ } |
+ break; |
+ #ifdef NSS_ENABLE_ECC |
+ case ecKey: |
+ doDerEncode = PR_TRUE; |
+- hashItem.data = hash->sha; |
+- hashItem.len = sizeof(hash->sha); |
++ /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash. |
++ * In that case, we use just the SHA1 part. */ |
++ if (hash->hashAlg == SEC_OID_UNKNOWN) { |
++ hashItem.data = hash->u.s.sha; |
++ hashItem.len = sizeof(hash->u.s.sha); |
++ } else { |
++ hashItem.data = hash->u.raw; |
++ hashItem.len = hash->len; |
++ } |
+ break; |
+ #endif /* NSS_ENABLE_ECC */ |
+ default: |
+@@ -845,7 +860,22 @@ |
+ } |
+ PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len)); |
+ |
+- rv = PK11_Sign(key, buf, &hashItem); |
++ if (hash->hashAlg == SEC_OID_UNKNOWN) { |
++ signatureLen = PK11_SignatureLen(key); |
++ if (signatureLen <= 0) { |
++ PORT_SetError(SEC_ERROR_INVALID_KEY); |
++ goto done; |
++ } |
++ |
++ buf->len = (unsigned)signatureLen; |
++ buf->data = (unsigned char *)PORT_Alloc(signatureLen); |
++ if (!buf->data) |
++ goto done; /* error code was set. */ |
++ |
++ rv = PK11_Sign(key, buf, &hashItem); |
++ } else { |
++ rv = SGN_Digest(key, hash->hashAlg, buf, &hashItem); |
++ } |
+ if (rv != SECSuccess) { |
+ ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); |
+ } else if (doDerEncode) { |
+@@ -879,9 +909,8 @@ |
+ SECItem * signature = NULL; |
+ SECStatus rv; |
+ SECItem hashItem; |
+-#ifdef NSS_ENABLE_ECC |
+- unsigned int len; |
+-#endif /* NSS_ENABLE_ECC */ |
++ SECOidTag encAlg; |
++ SECOidTag hashAlg; |
+ |
+ |
+ PRINT_BUF(60, (NULL, "check signed hashes", |
+@@ -893,14 +922,24 @@ |
+ return SECFailure; |
+ } |
+ |
++ hashAlg = hash->hashAlg; |
+ switch (key->keyType) { |
+ case rsaKey: |
+- hashItem.data = hash->md5; |
+- hashItem.len = sizeof(SSL3Hashes); |
++ encAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; |
++ hashItem.data = hash->u.raw; |
++ hashItem.len = hash->len; |
+ break; |
+ case dsaKey: |
+- hashItem.data = hash->sha; |
+- hashItem.len = sizeof(hash->sha); |
++ encAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; |
++ /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash. |
++ * In that case, we use just the SHA1 part. */ |
++ if (hash->hashAlg == SEC_OID_UNKNOWN) { |
++ hashItem.data = hash->u.s.sha; |
++ hashItem.len = sizeof(hash->u.s.sha); |
++ } else { |
++ hashItem.data = hash->u.raw; |
++ hashItem.len = hash->len; |
++ } |
+ /* Allow DER encoded DSA signatures in SSL 3.0 */ |
+ if (isTLS || buf->len != SECKEY_SignatureLen(key)) { |
+ signature = DSAU_DecodeDerSig(buf); |
+@@ -914,25 +953,21 @@ |
+ |
+ #ifdef NSS_ENABLE_ECC |
+ case ecKey: |
+- hashItem.data = hash->sha; |
+- hashItem.len = sizeof(hash->sha); |
+- /* |
+- * ECDSA signatures always encode the integers r and s |
+- * using ASN (unlike DSA where ASN encoding is used |
+- * with TLS but not with SSL3) |
++ encAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; |
++ /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash. |
++ * In that case, we use just the SHA1 part. |
++ * ECDSA signatures always encode the integers r and s using ASN.1 |
++ * (unlike DSA where ASN.1 encoding is used with TLS but not with |
++ * SSL3). So we can use VFY_VerifyDigestDirect for ECDSA. |
+ */ |
+- len = SECKEY_SignatureLen(key); |
+- if (len == 0) { |
+- SECKEY_DestroyPublicKey(key); |
+- PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
+- return SECFailure; |
++ if (hash->hashAlg == SEC_OID_UNKNOWN) { |
++ hashAlg = SEC_OID_SHA1; |
++ hashItem.data = hash->u.s.sha; |
++ hashItem.len = sizeof(hash->u.s.sha); |
++ } else { |
++ hashItem.data = hash->u.raw; |
++ hashItem.len = hash->len; |
+ } |
+- signature = DSAU_DecodeDerSigToLen(buf, len); |
+- if (!signature) { |
+- PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); |
+- return SECFailure; |
+- } |
+- buf = signature; |
+ break; |
+ #endif /* NSS_ENABLE_ECC */ |
+ |
+@@ -945,7 +980,17 @@ |
+ PRINT_BUF(60, (NULL, "hash(es) to be verified", |
+ hashItem.data, hashItem.len)); |
+ |
+- rv = PK11_Verify(key, buf, &hashItem, pwArg); |
++ if (hashAlg == SEC_OID_UNKNOWN || key->keyType == dsaKey) { |
++ /* VFY_VerifyDigestDirect requires DSA signatures to be DER-encoded. |
++ * DSA signatures are DER-encoded in TLS but not in SSL3 and the code |
++ * above always removes the DER encoding of DSA signatures when |
++ * present. Thus DSA signatures are always verified with PK11_Verify. |
++ */ |
++ rv = PK11_Verify(key, buf, &hashItem, pwArg); |
++ } else { |
++ rv = VFY_VerifyDigestDirect(&hashItem, key, buf, encAlg, hashAlg, |
++ pwArg); |
++ } |
+ SECKEY_DestroyPublicKey(key); |
+ if (signature) { |
+ SECITEM_FreeItem(signature, PR_TRUE); |
+@@ -961,33 +1006,69 @@ |
+ /* Called from ssl3_ComputeExportRSAKeyHash |
+ * ssl3_ComputeDHKeyHash |
+ * which are called from ssl3_HandleServerKeyExchange. |
++ * |
++ * hashAlg: either the OID for a hash algorithm or SEC_OID_UNKNOWN to specify |
++ * the pre-1.2, MD5/SHA1 combination hash. |
+ */ |
+ SECStatus |
+-ssl3_ComputeCommonKeyHash(PRUint8 * hashBuf, unsigned int bufLen, |
+- SSL3Hashes *hashes, PRBool bypassPKCS11) |
++ssl3_ComputeCommonKeyHash(SECOidTag hashAlg, |
++ PRUint8 * hashBuf, unsigned int bufLen, |
++ SSL3Hashes *hashes, PRBool bypassPKCS11) |
+ { |
+ SECStatus rv = SECSuccess; |
+ |
+ #ifndef NO_PKCS11_BYPASS |
+ if (bypassPKCS11) { |
+- MD5_HashBuf (hashes->md5, hashBuf, bufLen); |
+- SHA1_HashBuf(hashes->sha, hashBuf, bufLen); |
++ if (hashAlg == SEC_OID_UNKNOWN) { |
++ MD5_HashBuf (hashes->u.s.md5, hashBuf, bufLen); |
++ SHA1_HashBuf(hashes->u.s.sha, hashBuf, bufLen); |
++ hashes->len = MD5_LENGTH + SHA1_LENGTH; |
++ } else if (hashAlg == SEC_OID_SHA1) { |
++ SHA1_HashBuf(hashes->u.raw, hashBuf, bufLen); |
++ hashes->len = SHA1_LENGTH; |
++ } else if (hashAlg == SEC_OID_SHA256) { |
++ SHA256_HashBuf(hashes->u.raw, hashBuf, bufLen); |
++ hashes->len = SHA256_LENGTH; |
++ } else if (hashAlg == SEC_OID_SHA384) { |
++ SHA384_HashBuf(hashes->u.raw, hashBuf, bufLen); |
++ hashes->len = SHA384_LENGTH; |
++ } else { |
++ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); |
++ return SECFailure; |
++ } |
+ } else |
+ #endif |
+ { |
+- rv = PK11_HashBuf(SEC_OID_MD5, hashes->md5, hashBuf, bufLen); |
+- if (rv != SECSuccess) { |
+- ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); |
+- rv = SECFailure; |
+- goto done; |
+- } |
++ if (hashAlg == SEC_OID_UNKNOWN) { |
++ rv = PK11_HashBuf(SEC_OID_MD5, hashes->u.s.md5, hashBuf, bufLen); |
++ if (rv != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); |
++ rv = SECFailure; |
++ goto done; |
++ } |
+ |
+- rv = PK11_HashBuf(SEC_OID_SHA1, hashes->sha, hashBuf, bufLen); |
+- if (rv != SECSuccess) { |
+- ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); |
+- rv = SECFailure; |
++ rv = PK11_HashBuf(SEC_OID_SHA1, hashes->u.s.sha, hashBuf, bufLen); |
++ if (rv != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); |
++ rv = SECFailure; |
++ } |
++ hashes->len = MD5_LENGTH + SHA1_LENGTH; |
++ } else { |
++ hashes->len = HASH_ResultLenByOidTag(hashAlg); |
++ if (hashes->len > sizeof(hashes->u.raw)) { |
++ ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); |
++ rv = SECFailure; |
++ goto done; |
++ } |
++ rv = PK11_HashBuf(hashAlg, hashes->u.raw, hashBuf, bufLen); |
++ if (rv != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); |
++ rv = SECFailure; |
++ } |
+ } |
+ } |
++ hashes->hashAlg = hashAlg; |
++ |
+ done: |
+ return rv; |
+ } |
+@@ -997,7 +1078,8 @@ |
+ ** ssl3_HandleServerKeyExchange. |
+ */ |
+ static SECStatus |
+-ssl3_ComputeExportRSAKeyHash(SECItem modulus, SECItem publicExponent, |
++ssl3_ComputeExportRSAKeyHash(SECOidTag hashAlg, |
++ SECItem modulus, SECItem publicExponent, |
+ SSL3Random *client_rand, SSL3Random *server_rand, |
+ SSL3Hashes *hashes, PRBool bypassPKCS11) |
+ { |
+@@ -1033,11 +1115,19 @@ |
+ pBuf += publicExponent.len; |
+ PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); |
+ |
+- rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11); |
++ rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, |
++ bypassPKCS11); |
+ |
+ PRINT_BUF(95, (NULL, "RSAkey hash: ", hashBuf, bufLen)); |
+- PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result", hashes->md5, MD5_LENGTH)); |
+- PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); |
++ if (hashAlg == SEC_OID_UNKNOWN) { |
++ PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result", |
++ hashes->u.s.md5, MD5_LENGTH)); |
++ PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result", |
++ hashes->u.s.sha, SHA1_LENGTH)); |
++ } else { |
++ PRINT_BUF(95, (NULL, "RSAkey hash: result", |
++ hashes->u.raw, hashes->len)); |
++ } |
+ |
+ if (hashBuf != buf && hashBuf != NULL) |
+ PORT_Free(hashBuf); |
+@@ -1047,9 +1137,10 @@ |
+ /* Caller must set hiLevel error code. */ |
+ /* Called from ssl3_HandleServerKeyExchange. */ |
+ static SECStatus |
+-ssl3_ComputeDHKeyHash(SECItem dh_p, SECItem dh_g, SECItem dh_Ys, |
+- SSL3Random *client_rand, SSL3Random *server_rand, |
+- SSL3Hashes *hashes, PRBool bypassPKCS11) |
++ssl3_ComputeDHKeyHash(SECOidTag hashAlg, |
++ SECItem dh_p, SECItem dh_g, SECItem dh_Ys, |
++ SSL3Random *client_rand, SSL3Random *server_rand, |
++ SSL3Hashes *hashes, PRBool bypassPKCS11) |
+ { |
+ PRUint8 * hashBuf; |
+ PRUint8 * pBuf; |
+@@ -1088,11 +1179,19 @@ |
+ pBuf += dh_Ys.len; |
+ PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); |
+ |
+- rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11); |
++ rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, |
++ bypassPKCS11); |
+ |
+ PRINT_BUF(95, (NULL, "DHkey hash: ", hashBuf, bufLen)); |
+- PRINT_BUF(95, (NULL, "DHkey hash: MD5 result", hashes->md5, MD5_LENGTH)); |
+- PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); |
++ if (hashAlg == SEC_OID_UNKNOWN) { |
++ PRINT_BUF(95, (NULL, "DHkey hash: MD5 result", |
++ hashes->u.s.md5, MD5_LENGTH)); |
++ PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result", |
++ hashes->u.s.sha, SHA1_LENGTH)); |
++ } else { |
++ PRINT_BUF(95, (NULL, "DHkey hash: result", |
++ hashes->u.raw, hashes->len)); |
++ } |
+ |
+ if (hashBuf != buf && hashBuf != NULL) |
+ PORT_Free(hashBuf); |
+@@ -3190,6 +3289,8 @@ |
+ unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random; |
+ PRBool isTLS = (PRBool)(kea_def->tls_keygen || |
+ (pwSpec->version > SSL_LIBRARY_VERSION_3_0)); |
++ PRBool isTLS12= |
++ (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); |
+ /* |
+ * Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH |
+ * which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size |
+@@ -3208,7 +3309,12 @@ |
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); |
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); |
+ PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); |
+- if (isTLS) { |
++ if (isTLS12) { |
++ if(isDH) master_derive = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256; |
++ else master_derive = CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256; |
++ key_derive = CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256; |
++ keyFlags = CKF_SIGN | CKF_VERIFY; |
++ } else if (isTLS) { |
+ if(isDH) master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH; |
+ else master_derive = CKM_TLS_MASTER_KEY_DERIVE; |
+ key_derive = CKM_TLS_KEY_AND_MAC_DERIVE; |
+@@ -3366,6 +3472,8 @@ |
+ unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random; |
+ PRBool isTLS = (PRBool)(kea_def->tls_keygen || |
+ (pwSpec->version > SSL_LIBRARY_VERSION_3_0)); |
++ PRBool isTLS12= |
++ (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); |
+ /* following variables used in PKCS11 path */ |
+ const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def; |
+ PK11SlotInfo * slot = NULL; |
+@@ -3423,7 +3531,9 @@ |
+ params.data = (unsigned char *)&key_material_params; |
+ params.len = sizeof(key_material_params); |
+ |
+- if (isTLS) { |
++ if (isTLS12) { |
++ key_derive = CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256; |
++ } else if (isTLS) { |
+ key_derive = CKM_TLS_KEY_AND_MAC_DERIVE; |
+ } else { |
+ key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE; |
+@@ -3480,19 +3590,63 @@ |
+ return SECFailure; |
+ } |
+ |
++/* ssl3_InitTLS12HandshakeHash creates a handshake hash context for TLS 1.2, |
++ * if needed, and hashes in any buffered messages in ss->ssl3.hs.messages. */ |
++static SECStatus |
++ssl3_InitTLS12HandshakeHash(sslSocket *ss) |
++{ |
++ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2 && |
++ ss->ssl3.hs.tls12_handshake_hash == NULL) { |
++ /* If we ever support ciphersuites where the PRF hash isn't SHA-256 |
++ * then this will need to be updated. */ |
++ ss->ssl3.hs.tls12_handshake_hash = |
++ PK11_CreateDigestContext(SEC_OID_SHA256); |
++ if (!ss->ssl3.hs.tls12_handshake_hash || |
++ PK11_DigestBegin(ss->ssl3.hs.tls12_handshake_hash) != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); |
++ return SECFailure; |
++ } |
++ } |
++ |
++ if (ss->ssl3.hs.tls12_handshake_hash && ss->ssl3.hs.messages.len > 0) { |
++ if (PK11_DigestOp(ss->ssl3.hs.tls12_handshake_hash, |
++ ss->ssl3.hs.messages.buf, |
++ ss->ssl3.hs.messages.len) != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); |
++ return SECFailure; |
++ } |
++ } |
++ |
++ if (ss->ssl3.hs.messages.buf && !ss->opt.bypassPKCS11) { |
++ PORT_Free(ss->ssl3.hs.messages.buf); |
++ ss->ssl3.hs.messages.buf = NULL; |
++ ss->ssl3.hs.messages.len = 0; |
++ ss->ssl3.hs.messages.space = 0; |
++ } |
++ |
++ return SECSuccess; |
++} |
++ |
+ static SECStatus |
+ ssl3_RestartHandshakeHashes(sslSocket *ss) |
+ { |
+ SECStatus rv = SECSuccess; |
+ |
++ ss->ssl3.hs.messages.len = 0; |
+ #ifndef NO_PKCS11_BYPASS |
+ if (ss->opt.bypassPKCS11) { |
+- ss->ssl3.hs.messages.len = 0; |
+ MD5_Begin((MD5Context *)ss->ssl3.hs.md5_cx); |
+ SHA1_Begin((SHA1Context *)ss->ssl3.hs.sha_cx); |
+ } else |
+ #endif |
+ { |
++ if (ss->ssl3.hs.tls12_handshake_hash) { |
++ rv = PK11_DigestBegin(ss->ssl3.hs.tls12_handshake_hash); |
++ if (rv != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); |
++ return rv; |
++ } |
++ } |
+ rv = PK11_DigestBegin(ss->ssl3.hs.md5); |
+ if (rv != SECSuccess) { |
+ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); |
+@@ -3519,25 +3673,21 @@ |
+ * that the master secret will wind up in ... |
+ */ |
+ SSL_TRC(30,("%d: SSL3[%d]: start handshake hashes", SSL_GETPID(), ss->fd)); |
+-#ifndef NO_PKCS11_BYPASS |
+- if (ss->opt.bypassPKCS11) { |
+- PORT_Assert(!ss->ssl3.hs.messages.buf && !ss->ssl3.hs.messages.space); |
+- ss->ssl3.hs.messages.buf = NULL; |
+- ss->ssl3.hs.messages.space = 0; |
+- } else |
+-#endif |
+- { |
+- ss->ssl3.hs.md5 = md5 = PK11_CreateDigestContext(SEC_OID_MD5); |
+- ss->ssl3.hs.sha = sha = PK11_CreateDigestContext(SEC_OID_SHA1); |
+- if (md5 == NULL) { |
+- ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); |
+- goto loser; |
+- } |
+- if (sha == NULL) { |
+- ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); |
+- goto loser; |
+- } |
++ PORT_Assert(!ss->ssl3.hs.messages.buf && !ss->ssl3.hs.messages.space); |
++ ss->ssl3.hs.messages.buf = NULL; |
++ ss->ssl3.hs.messages.space = 0; |
++ |
++ ss->ssl3.hs.md5 = md5 = PK11_CreateDigestContext(SEC_OID_MD5); |
++ ss->ssl3.hs.sha = sha = PK11_CreateDigestContext(SEC_OID_SHA1); |
++ ss->ssl3.hs.tls12_handshake_hash = NULL; |
++ if (md5 == NULL) { |
++ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); |
++ goto loser; |
+ } |
++ if (sha == NULL) { |
++ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); |
++ goto loser; |
++ } |
+ if (SECSuccess == ssl3_RestartHandshakeHashes(ss)) { |
+ return SECSuccess; |
+ } |
+@@ -3574,6 +3724,17 @@ |
+ |
+ PRINT_BUF(90, (NULL, "MD5 & SHA handshake hash input:", b, l)); |
+ |
++ if ((ss->version == 0 || ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) && |
++ !ss->opt.bypassPKCS11 && |
++ ss->ssl3.hs.tls12_handshake_hash == NULL) { |
++ /* For TLS 1.2 connections we need to buffer the handshake messages |
++ * until we have established which PRF hash function to use. */ |
++ rv = sslBuffer_Append(&ss->ssl3.hs.messages, b, l); |
++ if (rv != SECSuccess) { |
++ return rv; |
++ } |
++ } |
++ |
+ #ifndef NO_PKCS11_BYPASS |
+ if (ss->opt.bypassPKCS11) { |
+ MD5_Update((MD5Context *)ss->ssl3.hs.md5_cx, b, l); |
+@@ -3584,16 +3745,24 @@ |
+ return rv; |
+ } |
+ #endif |
+- rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l); |
+- if (rv != SECSuccess) { |
+- ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); |
+- return rv; |
++ if (ss->ssl3.hs.tls12_handshake_hash) { |
++ rv = PK11_DigestOp(ss->ssl3.hs.tls12_handshake_hash, b, l); |
++ if (rv != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); |
++ return rv; |
++ } |
++ } else { |
++ rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l); |
++ if (rv != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); |
++ return rv; |
++ } |
++ rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l); |
++ if (rv != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); |
++ return rv; |
++ } |
+ } |
+- rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l); |
+- if (rv != SECSuccess) { |
+- ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); |
+- return rv; |
+- } |
+ return rv; |
+ } |
+ |
+@@ -3744,6 +3913,25 @@ |
+ return rv; /* error code set by AppendHandshake, if applicable. */ |
+ } |
+ |
++/* ssl3_AppendSignatureAndHashAlgorithm appends the serialisation of |
++ * |sigAndHash| to the current handshake message. */ |
++SECStatus |
++ssl3_AppendSignatureAndHashAlgorithm( |
++ sslSocket *ss, const SSL3SignatureAndHashAlgorithm* sigAndHash) |
++{ |
++ unsigned char serialized[2]; |
++ |
++ serialized[0] = ssl3_OIDToTLSHashAlgorithm(sigAndHash->hashAlg); |
++ if (serialized[0] == 0) { |
++ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); |
++ return SECFailure; |
++ } |
++ |
++ serialized[1] = sigAndHash->sigAlg; |
++ |
++ return ssl3_AppendHandshake(ss, serialized, sizeof(serialized)); |
++} |
++ |
+ /************************************************************************** |
+ * Consume Handshake functions. |
+ * |
+@@ -3850,6 +4038,147 @@ |
+ return SECSuccess; |
+ } |
+ |
++/* tlsHashOIDMap contains the mapping between TLS hash identifiers and the |
++ * SECOidTag used internally by NSS. */ |
++static const struct { |
++ int tlsHash; |
++ SECOidTag oid; |
++} tlsHashOIDMap[] = { |
++ { tls_hash_md5, SEC_OID_MD5 }, |
++ { tls_hash_sha1, SEC_OID_SHA1 }, |
++ { tls_hash_sha224, SEC_OID_SHA224 }, |
++ { tls_hash_sha256, SEC_OID_SHA256 }, |
++ { tls_hash_sha384, SEC_OID_SHA384 }, |
++ { tls_hash_sha512, SEC_OID_SHA512 } |
++}; |
++ |
++/* ssl3_TLSHashAlgorithmToOID converts a TLS hash identifier into an OID value. |
++ * If the hash is not recognised, SEC_OID_UNKNOWN is returned. |
++ * |
++ * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ |
++SECOidTag |
++ssl3_TLSHashAlgorithmToOID(int hashFunc) |
++{ |
++ unsigned int i; |
++ |
++ for (i = 0; i < PR_ARRAY_SIZE(tlsHashOIDMap); i++) { |
++ if (hashFunc == tlsHashOIDMap[i].tlsHash) { |
++ return tlsHashOIDMap[i].oid; |
++ } |
++ } |
++ return SEC_OID_UNKNOWN; |
++} |
++ |
++/* ssl3_OIDToTLSHashAlgorithm converts an OID to a TLS hash algorithm |
++ * identifier. If the hash is not recognised, zero is returned. |
++ * |
++ * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ |
++static int |
++ssl3_OIDToTLSHashAlgorithm(SECOidTag oid) |
++{ |
++ unsigned int i; |
++ |
++ for (i = 0; i < PR_ARRAY_SIZE(tlsHashOIDMap); i++) { |
++ if (oid == tlsHashOIDMap[i].oid) { |
++ return tlsHashOIDMap[i].tlsHash; |
++ } |
++ } |
++ return 0; |
++} |
++ |
++/* ssl3_TLSSignatureAlgorithmForKeyType returns the TLS 1.2 signature algorithm |
++ * identifier for a given KeyType. */ |
++static SECStatus |
++ssl3_TLSSignatureAlgorithmForKeyType(KeyType keyType, |
++ TLSSignatureAlgorithm *out) |
++{ |
++ switch (keyType) { |
++ case rsaKey: |
++ *out = tls_sig_rsa; |
++ return SECSuccess; |
++ case dsaKey: |
++ *out = tls_sig_dsa; |
++ return SECSuccess; |
++ case ecKey: |
++ *out = tls_sig_ecdsa; |
++ return SECSuccess; |
++ default: |
++ PORT_SetError(SEC_ERROR_INVALID_KEY); |
++ return SECFailure; |
++ } |
++} |
++ |
++/* ssl3_TLSSignatureAlgorithmForCertificate returns the TLS 1.2 signature |
++ * algorithm identifier for the given certificate. */ |
++static SECStatus |
++ssl3_TLSSignatureAlgorithmForCertificate(CERTCertificate *cert, |
++ TLSSignatureAlgorithm *out) |
++{ |
++ SECKEYPublicKey *key; |
++ KeyType keyType; |
++ |
++ key = CERT_ExtractPublicKey(cert); |
++ if (key == NULL) { |
++ ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); |
++ return SECFailure; |
++ } |
++ |
++ keyType = key->keyType; |
++ SECKEY_DestroyPublicKey(key); |
++ return ssl3_TLSSignatureAlgorithmForKeyType(keyType, out); |
++} |
++ |
++/* ssl3_CheckSignatureAndHashAlgorithmConsistency checks that the signature |
++ * algorithm identifier in |sigAndHash| is consistent with the public key in |
++ * |cert|. If so, SECSuccess is returned. Otherwise, PORT_SetError is called |
++ * and SECFailure is returned. */ |
++SECStatus |
++ssl3_CheckSignatureAndHashAlgorithmConsistency( |
++ const SSL3SignatureAndHashAlgorithm *sigAndHash, CERTCertificate* cert) |
++{ |
++ SECStatus rv; |
++ TLSSignatureAlgorithm sigAlg; |
++ |
++ rv = ssl3_TLSSignatureAlgorithmForCertificate(cert, &sigAlg); |
++ if (rv != SECSuccess) { |
++ return rv; |
++ } |
++ if (sigAlg != sigAndHash->sigAlg) { |
++ PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); |
++ return SECFailure; |
++ } |
++ return SECSuccess; |
++} |
++ |
++/* ssl3_ConsumeSignatureAndHashAlgorithm reads a SignatureAndHashAlgorithm |
++ * structure from |b| and puts the resulting value into |out|. |b| and |length| |
++ * are updated accordingly. |
++ * |
++ * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ |
++SECStatus |
++ssl3_ConsumeSignatureAndHashAlgorithm(sslSocket *ss, |
++ SSL3Opaque **b, |
++ PRUint32 *length, |
++ SSL3SignatureAndHashAlgorithm *out) |
++{ |
++ unsigned char bytes[2]; |
++ SECStatus rv; |
++ |
++ rv = ssl3_ConsumeHandshake(ss, bytes, sizeof(bytes), b, length); |
++ if (rv != SECSuccess) { |
++ return rv; |
++ } |
++ |
++ out->hashAlg = ssl3_TLSHashAlgorithmToOID(bytes[0]); |
++ if (out->hashAlg == SEC_OID_UNKNOWN) { |
++ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); |
++ return SECFailure; |
++ } |
++ |
++ out->sigAlg = bytes[1]; |
++ return SECSuccess; |
++} |
++ |
+ /************************************************************************** |
+ * end of Consume Handshake functions. |
+ **************************************************************************/ |
+@@ -3876,6 +4205,7 @@ |
+ SSL3Opaque sha_inner[MAX_MAC_LENGTH]; |
+ |
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); |
++ hashes->hashAlg = SEC_OID_UNKNOWN; |
+ |
+ #ifndef NO_PKCS11_BYPASS |
+ if (ss->opt.bypassPKCS11) { |
+@@ -3939,9 +4269,9 @@ |
+ MD5_Update(md5cx, mac_pad_2, mac_defs[mac_md5].pad_size); |
+ MD5_Update(md5cx, md5_inner, MD5_LENGTH); |
+ } |
+- MD5_End(md5cx, hashes->md5, &outLength, MD5_LENGTH); |
++ MD5_End(md5cx, hashes->u.s.md5, &outLength, MD5_LENGTH); |
+ |
+- PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->md5, MD5_LENGTH)); |
++ PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH)); |
+ |
+ if (!isTLS) { |
+ PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, |
+@@ -3953,16 +4283,58 @@ |
+ SHA1_Update(shacx, mac_pad_2, mac_defs[mac_sha].pad_size); |
+ SHA1_Update(shacx, sha_inner, SHA1_LENGTH); |
+ } |
+- SHA1_End(shacx, hashes->sha, &outLength, SHA1_LENGTH); |
++ SHA1_End(shacx, hashes->u.s.sha, &outLength, SHA1_LENGTH); |
+ |
+- PRINT_BUF(60, (NULL, "SHA outer: result", hashes->sha, SHA1_LENGTH)); |
++ PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH)); |
+ |
++ hashes->len = MD5_LENGTH + SHA1_LENGTH; |
+ rv = SECSuccess; |
+ #undef md5cx |
+ #undef shacx |
+ } else |
+ #endif |
+- { |
++ if (ss->ssl3.hs.tls12_handshake_hash) { |
++ PK11Context *h; |
++ unsigned int stateLen; |
++ unsigned char stackBuf[1024]; |
++ unsigned char *stateBuf = NULL; |
++ |
++ if (!spec->master_secret) { |
++ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE); |
++ return SECFailure; |
++ } |
++ |
++ h = ss->ssl3.hs.tls12_handshake_hash; |
++ stateBuf = PK11_SaveContextAlloc(h, stackBuf, |
++ sizeof(stackBuf), &stateLen); |
++ if (stateBuf == NULL) { |
++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); |
++ goto tls12_loser; |
++ } |
++ rv |= PK11_DigestFinal(h, hashes->u.raw, &hashes->len, |
++ sizeof(hashes->u.raw)); |
++ if (rv != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); |
++ rv = SECFailure; |
++ goto tls12_loser; |
++ } |
++ /* If we ever support ciphersuites where the PRF hash isn't SHA-256 |
++ * then this will need to be updated. */ |
++ hashes->hashAlg = SEC_OID_SHA256; |
++ rv = SECSuccess; |
++ |
++tls12_loser: |
++ if (stateBuf) { |
++ if (PK11_RestoreContext(ss->ssl3.hs.tls12_handshake_hash, stateBuf, |
++ stateLen) != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); |
++ rv = SECFailure; |
++ } |
++ if (stateBuf != stackBuf) { |
++ PORT_ZFree(stateBuf, stateLen); |
++ } |
++ } |
++ } else { |
+ /* compute hases with PKCS11 */ |
+ PK11Context * md5; |
+ PK11Context * sha = NULL; |
+@@ -4051,7 +4423,7 @@ |
+ rv |= PK11_DigestOp(md5, mac_pad_2, mac_defs[mac_md5].pad_size); |
+ rv |= PK11_DigestOp(md5, md5_inner, MD5_LENGTH); |
+ } |
+- rv |= PK11_DigestFinal(md5, hashes->md5, &outLength, MD5_LENGTH); |
++ rv |= PK11_DigestFinal(md5, hashes->u.s.md5, &outLength, MD5_LENGTH); |
+ PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH); |
+ if (rv != SECSuccess) { |
+ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); |
+@@ -4059,7 +4431,7 @@ |
+ goto loser; |
+ } |
+ |
+- PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->md5, MD5_LENGTH)); |
++ PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH)); |
+ |
+ if (!isTLS) { |
+ PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, |
+@@ -4071,7 +4443,7 @@ |
+ rv |= PK11_DigestOp(sha, mac_pad_2, mac_defs[mac_sha].pad_size); |
+ rv |= PK11_DigestOp(sha, sha_inner, SHA1_LENGTH); |
+ } |
+- rv |= PK11_DigestFinal(sha, hashes->sha, &outLength, SHA1_LENGTH); |
++ rv |= PK11_DigestFinal(sha, hashes->u.s.sha, &outLength, SHA1_LENGTH); |
+ PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH); |
+ if (rv != SECSuccess) { |
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); |
+@@ -4079,8 +4451,9 @@ |
+ goto loser; |
+ } |
+ |
+- PRINT_BUF(60, (NULL, "SHA outer: result", hashes->sha, SHA1_LENGTH)); |
++ PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH)); |
+ |
++ hashes->len = MD5_LENGTH + SHA1_LENGTH; |
+ rv = SECSuccess; |
+ |
+ loser: |
+@@ -5343,8 +5716,12 @@ |
+ { |
+ SECStatus rv = SECFailure; |
+ PRBool isTLS; |
++ PRBool isTLS12; |
+ SECItem buf = {siBuffer, NULL, 0}; |
+ SSL3Hashes hashes; |
++ KeyType keyType; |
++ unsigned int len; |
++ SSL3SignatureAndHashAlgorithm sigAndHash; |
+ |
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); |
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); |
+@@ -5393,10 +5772,30 @@ |
+ goto done; /* err code was set by ssl3_SignHashes */ |
+ } |
+ |
+- rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, buf.len + 2); |
++ len = buf.len + 2 + (isTLS12 ? 2 : 0); |
++ |
++ rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len); |
+ if (rv != SECSuccess) { |
+ goto done; /* error code set by AppendHandshake */ |
+ } |
++ if (isTLS12) { |
++ rv = ssl3_TLSSignatureAlgorithmForKeyType(keyType, |
++ &sigAndHash.sigAlg); |
++ if (rv != SECSuccess) { |
++ goto done; |
++ } |
++ /* We always sign using the handshake hash function. It's possible that |
++ * a server could support SHA-256 as the handshake hash but not as a |
++ * signature hash. In that case we wouldn't be able to do client |
++ * certificates with it. The alternative is to buffer all handshake |
++ * messages. */ |
++ sigAndHash.hashAlg = hashes.hashAlg; |
++ |
++ rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash); |
++ if (rv != SECSuccess) { |
++ goto done; /* err set by AppendHandshake. */ |
++ } |
++ } |
+ rv = ssl3_AppendHandshakeVariable(ss, buf.data, buf.len, 2); |
+ if (rv != SECSuccess) { |
+ goto done; /* error code set by AppendHandshake */ |
+@@ -5504,6 +5903,13 @@ |
+ } |
+ isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0); |
+ |
++ rv = ssl3_InitTLS12HandshakeHash(ss); |
++ if (rv != SECSuccess) { |
++ desc = internal_error; |
++ errCode = PORT_GetError(); |
++ goto alert_loser; |
++ } |
++ |
+ rv = ssl3_ConsumeHandshake( |
+ ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length); |
+ if (rv != SECSuccess) { |
+@@ -5834,13 +6240,16 @@ |
+ { |
+ PRArenaPool * arena = NULL; |
+ SECKEYPublicKey *peerKey = NULL; |
+- PRBool isTLS; |
++ PRBool isTLS, isTLS12; |
+ SECStatus rv; |
+ int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; |
+ SSL3AlertDescription desc = illegal_parameter; |
+ SSL3Hashes hashes; |
+ SECItem signature = {siBuffer, NULL, 0}; |
++ SSL3SignatureAndHashAlgorithm sigAndHash; |
+ |
++ sigAndHash.hashAlg = SEC_OID_UNKNOWN; |
++ |
+ SSL_TRC(3, ("%d: SSL3[%d]: handle server_key_exchange handshake", |
+ SSL_GETPID(), ss->fd)); |
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); |
+@@ -5859,6 +6268,7 @@ |
+ } |
+ |
+ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); |
++ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); |
+ |
+ switch (ss->ssl3.hs.kea_def->exchKeyType) { |
+ |
+@@ -5874,6 +6284,18 @@ |
+ if (rv != SECSuccess) { |
+ goto loser; /* malformed. */ |
+ } |
++ if (isTLS12) { |
++ rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, |
++ &sigAndHash); |
++ if (rv != SECSuccess) { |
++ goto loser; /* malformed or unsupported. */ |
++ } |
++ rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( |
++ &sigAndHash, ss->sec.peerCert); |
++ if (rv != SECSuccess) { |
++ goto loser; |
++ } |
++ } |
+ rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); |
+ if (rv != SECSuccess) { |
+ goto loser; /* malformed. */ |
+@@ -5891,7 +6313,7 @@ |
+ /* |
+ * check to make sure the hash is signed by right guy |
+ */ |
+- rv = ssl3_ComputeExportRSAKeyHash(modulus, exponent, |
++ rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg, modulus, exponent, |
+ &ss->ssl3.hs.client_random, |
+ &ss->ssl3.hs.server_random, |
+ &hashes, ss->opt.bypassPKCS11); |
+@@ -5964,6 +6386,18 @@ |
+ } |
+ if (dh_Ys.len > dh_p.len || !ssl3_BigIntGreaterThanOne(&dh_Ys)) |
+ goto alert_loser; |
++ if (isTLS12) { |
++ rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, |
++ &sigAndHash); |
++ if (rv != SECSuccess) { |
++ goto loser; /* malformed or unsupported. */ |
++ } |
++ rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( |
++ &sigAndHash, ss->sec.peerCert); |
++ if (rv != SECSuccess) { |
++ goto loser; |
++ } |
++ } |
+ rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); |
+ if (rv != SECSuccess) { |
+ goto loser; /* malformed. */ |
+@@ -5985,7 +6419,7 @@ |
+ /* |
+ * check to make sure the hash is signed by right guy |
+ */ |
+- rv = ssl3_ComputeDHKeyHash(dh_p, dh_g, dh_Ys, |
++ rv = ssl3_ComputeDHKeyHash(sigAndHash.hashAlg, dh_p, dh_g, dh_Ys, |
+ &ss->ssl3.hs.client_random, |
+ &ss->ssl3.hs.server_random, |
+ &hashes, ss->opt.bypassPKCS11); |
+@@ -6862,6 +7296,13 @@ |
+ goto alert_loser; |
+ } |
+ |
++ rv = ssl3_InitTLS12HandshakeHash(ss); |
++ if (rv != SECSuccess) { |
++ desc = internal_error; |
++ errCode = PORT_GetError(); |
++ goto alert_loser; |
++ } |
++ |
+ /* grab the client random data. */ |
+ rv = ssl3_ConsumeHandshake( |
+ ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length); |
+@@ -7604,6 +8045,13 @@ |
+ goto alert_loser; |
+ } |
+ |
++ rv = ssl3_InitTLS12HandshakeHash(ss); |
++ if (rv != SECSuccess) { |
++ desc = internal_error; |
++ errCode = PORT_GetError(); |
++ goto alert_loser; |
++ } |
++ |
+ /* if we get a non-zero SID, just ignore it. */ |
+ if (length != |
+ SSL_HL_CLIENT_HELLO_HBYTES + suite_length + sid_length + rand_length) { |
+@@ -7851,7 +8299,86 @@ |
+ return SECSuccess; |
+ } |
+ |
++/* ssl3_PickSignatureHashAlgorithm selects a hash algorithm to use when signing |
++ * elements of the handshake. (The negotiated cipher suite determines the |
++ * signature algorithm.) Prior to TLS 1.2, the MD5/SHA1 combination is always |
++ * used. With TLS 1.2, a client may advertise its support for signature and |
++ * hash combinations. */ |
++static SECStatus |
++ssl3_PickSignatureHashAlgorithm(sslSocket *ss, |
++ SSL3SignatureAndHashAlgorithm* out) |
++{ |
++ TLSSignatureAlgorithm sigAlg; |
++ unsigned int i, j; |
++ /* hashPreference expresses our preferences for hash algorithms, most |
++ * preferable first. */ |
++ static const PRUint8 hashPreference[] = { |
++ tls_hash_sha256, |
++ tls_hash_sha384, |
++ tls_hash_sha512, |
++ tls_hash_sha1, |
++ }; |
+ |
++ switch (ss->ssl3.hs.kea_def->kea) { |
++ case kea_rsa: |
++ case kea_rsa_export: |
++ case kea_rsa_export_1024: |
++ case kea_dh_rsa: |
++ case kea_dh_rsa_export: |
++ case kea_dhe_rsa: |
++ case kea_dhe_rsa_export: |
++ case kea_rsa_fips: |
++ case kea_ecdh_rsa: |
++ case kea_ecdhe_rsa: |
++ sigAlg = tls_sig_rsa; |
++ break; |
++ case kea_dh_dss: |
++ case kea_dh_dss_export: |
++ case kea_dhe_dss: |
++ case kea_dhe_dss_export: |
++ sigAlg = tls_sig_dsa; |
++ break; |
++ case kea_ecdh_ecdsa: |
++ case kea_ecdhe_ecdsa: |
++ sigAlg = tls_sig_ecdsa; |
++ break; |
++ default: |
++ PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); |
++ return SECFailure; |
++ } |
++ out->sigAlg = sigAlg; |
++ |
++ if (ss->version <= SSL_LIBRARY_VERSION_TLS_1_1) { |
++ /* SEC_OID_UNKNOWN means the MD5/SHA1 combo hash used in TLS 1.1 and |
++ * prior. */ |
++ out->hashAlg = SEC_OID_UNKNOWN; |
++ return SECSuccess; |
++ } |
++ |
++ if (ss->ssl3.hs.numClientSigAndHash == 0) { |
++ /* If the client didn't provide any signature_algorithms extension then |
++ * we can assume that they support SHA-1: |
++ * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ |
++ out->hashAlg = SEC_OID_SHA1; |
++ return SECSuccess; |
++ } |
++ |
++ for (i = 0; i < PR_ARRAY_SIZE(hashPreference); i++) { |
++ for (j = 0; j < ss->ssl3.hs.numClientSigAndHash; j++) { |
++ const SSL3SignatureAndHashAlgorithm* sh = |
++ &ss->ssl3.hs.clientSigAndHash[j]; |
++ if (sh->sigAlg == sigAlg && sh->hashAlg == hashPreference[i]) { |
++ out->hashAlg = sh->hashAlg; |
++ return SECSuccess; |
++ } |
++ } |
++ } |
++ |
++ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); |
++ return SECFailure; |
++} |
++ |
++ |
+ static SECStatus |
+ ssl3_SendServerKeyExchange(sslSocket *ss) |
+ { |
+@@ -7862,6 +8389,7 @@ |
+ SECItem signed_hash = {siBuffer, NULL, 0}; |
+ SSL3Hashes hashes; |
+ SECKEYPublicKey * sdPub; /* public key for step-down */ |
++ SSL3SignatureAndHashAlgorithm sigAndHash; |
+ |
+ SSL_TRC(3, ("%d: SSL3[%d]: send server_key_exchange handshake", |
+ SSL_GETPID(), ss->fd)); |
+@@ -7869,6 +8397,10 @@ |
+ PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); |
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); |
+ |
++ if (ssl3_PickSignatureHashAlgorithm(ss, &sigAndHash) != SECSuccess) { |
++ return SECFailure; |
++ } |
++ |
+ switch (kea_def->exchKeyType) { |
+ case kt_rsa: |
+ /* Perform SSL Step-Down here. */ |
+@@ -7878,7 +8410,8 @@ |
+ PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); |
+ return SECFailure; |
+ } |
+- rv = ssl3_ComputeExportRSAKeyHash(sdPub->u.rsa.modulus, |
++ rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg, |
++ sdPub->u.rsa.modulus, |
+ sdPub->u.rsa.publicExponent, |
+ &ss->ssl3.hs.client_random, |
+ &ss->ssl3.hs.server_random, |
+@@ -7921,6 +8454,13 @@ |
+ goto loser; /* err set by AppendHandshake. */ |
+ } |
+ |
++ if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { |
++ rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash); |
++ if (rv != SECSuccess) { |
++ goto loser; /* err set by AppendHandshake. */ |
++ } |
++ } |
++ |
+ rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, |
+ signed_hash.len, 2); |
+ if (rv != SECSuccess) { |
+@@ -7931,7 +8471,7 @@ |
+ |
+ #ifdef NSS_ENABLE_ECC |
+ case kt_ecdh: { |
+- rv = ssl3_SendECDHServerKeyExchange(ss); |
++ rv = ssl3_SendECDHServerKeyExchange(ss, &sigAndHash); |
+ return rv; |
+ } |
+ #endif /* NSS_ENABLE_ECC */ |
+@@ -8045,26 +8585,51 @@ |
+ SECStatus rv; |
+ int errCode = SSL_ERROR_RX_MALFORMED_CERT_VERIFY; |
+ SSL3AlertDescription desc = handshake_failure; |
+- PRBool isTLS; |
++ PRBool isTLS, isTLS12; |
++ SSL3SignatureAndHashAlgorithm sigAndHash; |
+ |
+ SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake", |
+ SSL_GETPID(), ss->fd)); |
+ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); |
+ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); |
+ |
++ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); |
++ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); |
++ |
+ if (ss->ssl3.hs.ws != wait_cert_verify || ss->sec.peerCert == NULL) { |
+ desc = unexpected_message; |
+ errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY; |
+ goto alert_loser; |
+ } |
+ |
++ if (isTLS12) { |
++ rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, |
++ &sigAndHash); |
++ if (rv != SECSuccess) { |
++ goto loser; /* malformed or unsupported. */ |
++ } |
++ rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( |
++ &sigAndHash, ss->sec.peerCert); |
++ if (rv != SECSuccess) { |
++ errCode = PORT_GetError(); |
++ desc = decrypt_error; |
++ goto alert_loser; |
++ } |
++ |
++ /* We only support CertificateVerify messages that use the handshake |
++ * hash. */ |
++ if (sigAndHash.hashAlg != hashes->hashAlg) { |
++ errCode = SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM; |
++ desc = decrypt_error; |
++ goto alert_loser; |
++ } |
++ } |
++ |
+ rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length); |
+ if (rv != SECSuccess) { |
+ goto loser; /* malformed. */ |
+ } |
+ |
+- isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); |
+- |
+ /* XXX verify that the key & kea match */ |
+ rv = ssl3_VerifySignedHashes(hashes, ss->sec.peerCert, &signed_hash, |
+ isTLS, ss->pkcs11PinArg); |
+@@ -9163,7 +9728,7 @@ |
+ static SECStatus |
+ ssl3_ComputeTLSFinished(ssl3CipherSpec *spec, |
+ PRBool isServer, |
+- const SSL3Finished * hashes, |
++ const SSL3Hashes * hashes, |
+ TLSFinished * tlsFinished) |
+ { |
+ const char * label; |
+@@ -9173,8 +9738,8 @@ |
+ label = isServer ? "server finished" : "client finished"; |
+ len = 15; |
+ |
+- rv = ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->md5, |
+- sizeof *hashes, tlsFinished->verify_data, |
++ rv = ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->u.raw, |
++ hashes->len, tlsFinished->verify_data, |
+ sizeof tlsFinished->verify_data); |
+ |
+ return rv; |
+@@ -9192,12 +9757,16 @@ |
+ SECStatus rv = SECSuccess; |
+ |
+ if (spec->master_secret && !spec->bypassCiphers) { |
+- SECItem param = {siBuffer, NULL, 0}; |
+- PK11Context *prf_context = |
+- PK11_CreateContextBySymKey(CKM_TLS_PRF_GENERAL, CKA_SIGN, |
+- spec->master_secret, ¶m); |
++ SECItem param = {siBuffer, NULL, 0}; |
++ CK_MECHANISM_TYPE mech = CKM_TLS_PRF_GENERAL; |
++ PK11Context *prf_context; |
+ unsigned int retLen; |
+ |
++ if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { |
++ mech = CKM_NSS_TLS_PRF_GENERAL_SHA256; |
++ } |
++ prf_context = PK11_CreateContextBySymKey(mech, CKA_SIGN, |
++ spec->master_secret, ¶m); |
+ if (!prf_context) |
+ return SECFailure; |
+ |
+@@ -9496,7 +10066,7 @@ |
+ PRBool isServer = ss->sec.isServer; |
+ SECStatus rv; |
+ SSL3Sender sender = isServer ? sender_server : sender_client; |
+- SSL3Finished hashes; |
++ SSL3Hashes hashes; |
+ TLSFinished tlsFinished; |
+ |
+ SSL_TRC(3, ("%d: SSL3[%d]: send finished handshake", SSL_GETPID(), ss->fd)); |
+@@ -9530,14 +10100,15 @@ |
+ goto fail; /* err set by AppendHandshake. */ |
+ } else { |
+ if (isServer) |
+- ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes; |
++ ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes.u.s; |
+ else |
+- ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes; |
+- ss->ssl3.hs.finishedBytes = sizeof hashes; |
+- rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes); |
++ ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes.u.s; |
++ PORT_Assert(hashes.len == sizeof hashes.u.s); |
++ ss->ssl3.hs.finishedBytes = sizeof hashes.u.s; |
++ rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes.u.s); |
+ if (rv != SECSuccess) |
+ goto fail; /* err set by AppendHandshake. */ |
+- rv = ssl3_AppendHandshake(ss, &hashes, sizeof hashes); |
++ rv = ssl3_AppendHandshake(ss, &hashes.u.s, sizeof hashes.u.s); |
+ if (rv != SECSuccess) |
+ goto fail; /* err set by AppendHandshake. */ |
+ } |
+@@ -9686,18 +10257,19 @@ |
+ return SECFailure; |
+ } |
+ } else { |
+- if (length != sizeof(SSL3Hashes)) { |
++ if (length != sizeof(SSL3Finished)) { |
+ (void)ssl3_IllegalParameter(ss); |
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED); |
+ return SECFailure; |
+ } |
+ |
+ if (!isServer) |
+- ss->ssl3.hs.finishedMsgs.sFinished[1] = *hashes; |
++ ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes->u.s; |
+ else |
+- ss->ssl3.hs.finishedMsgs.sFinished[0] = *hashes; |
+- ss->ssl3.hs.finishedBytes = sizeof *hashes; |
+- if (0 != NSS_SecureMemcmp(hashes, b, length)) { |
++ ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes->u.s; |
++ PORT_Assert(hashes->len == sizeof hashes->u.s); |
++ ss->ssl3.hs.finishedBytes = sizeof hashes->u.s; |
++ if (0 != NSS_SecureMemcmp(&hashes->u.s, b, length)) { |
+ (void)ssl3_HandshakeFailure(ss); |
+ PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); |
+ return SECFailure; |
+@@ -11286,6 +11858,12 @@ |
+ if (ss->ssl3.hs.sha) { |
+ PK11_DestroyContext(ss->ssl3.hs.sha,PR_TRUE); |
+ } |
++ if (ss->ssl3.hs.tls12_handshake_hash) { |
++ PK11_DestroyContext(ss->ssl3.hs.tls12_handshake_hash,PR_TRUE); |
++ } |
++ if (ss->ssl3.hs.clientSigAndHash) { |
++ PORT_Free(ss->ssl3.hs.clientSigAndHash); |
++ } |
+ if (ss->ssl3.hs.messages.buf) { |
+ PORT_Free(ss->ssl3.hs.messages.buf); |
+ ss->ssl3.hs.messages.buf = NULL; |