Index: net/third_party/nss/patches/tls12backuphash.patch |
=================================================================== |
--- net/third_party/nss/patches/tls12backuphash.patch (revision 0) |
+++ net/third_party/nss/patches/tls12backuphash.patch (revision 0) |
@@ -0,0 +1,163 @@ |
+Index: net/third_party/nss/ssl/ssl3con.c |
+=================================================================== |
+--- net/third_party/nss/ssl/ssl3con.c (revision 219342) |
++++ net/third_party/nss/ssl/ssl3con.c (working copy) |
+@@ -3933,6 +3933,22 @@ |
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); |
+ return SECFailure; |
+ } |
++ |
++#ifdef _WIN32 |
++ /* A backup SHA-1 hash for a potential client auth signature. */ |
++ if (!ss->sec.isServer) { |
++ ss->ssl3.hs.md5 = PK11_CreateDigestContext(SEC_OID_SHA1); |
++ if (ss->ssl3.hs.md5 == NULL) { |
++ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); |
++ return SECFailure; |
++ } |
++ |
++ if (PK11_DigestBegin(ss->ssl3.hs.md5) != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); |
++ return SECFailure; |
++ } |
++ } |
++#endif |
+ } else { |
+ /* Both ss->ssl3.hs.md5 and ss->ssl3.hs.sha should be NULL or |
+ * created successfully. */ |
+@@ -4043,6 +4059,13 @@ |
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); |
+ return rv; |
+ } |
++ if (ss->ssl3.hs.md5) { |
++ rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l); |
++ if (rv != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); |
++ return rv; |
++ } |
++ } |
+ } else { |
+ rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l); |
+ if (rv != SECSuccess) { |
+@@ -4791,6 +4814,30 @@ |
+ return rv; |
+ } |
+ |
++static SECStatus |
++ssl3_ComputeBackupHandshakeHashes(sslSocket * ss, |
++ SSL3Hashes * hashes) /* output goes here. */ |
++{ |
++ SECStatus rv = SECSuccess; |
++ |
++ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); |
++ PORT_Assert( ss->ssl3.hs.hashType == handshake_hash_single ); |
++ |
++ rv = PK11_DigestFinal(ss->ssl3.hs.md5, hashes->u.raw, &hashes->len, |
++ sizeof(hashes->u.raw)); |
++ if (rv != SECSuccess) { |
++ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); |
++ rv = SECFailure; |
++ goto loser; |
++ } |
++ hashes->hashAlg = SEC_OID_SHA1; |
++ |
++loser: |
++ PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE); |
++ ss->ssl3.hs.md5 = NULL; |
++ return rv; |
++} |
++ |
+ /* |
+ * SSL 2 based implementations pass in the initial outbound buffer |
+ * so that the handshake hash can contain the included information. |
+@@ -6044,7 +6091,17 @@ |
+ SSL_GETPID(), ss->fd)); |
+ |
+ ssl_GetSpecReadLock(ss); |
+- rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0); |
++ /* In TLS 1.2, ssl3_ComputeHandshakeHashes always uses the handshake hash |
++ * function (SHA-256). If the server or the client does not support SHA-256 |
++ * as a signature hash, we can either maintain a backup SHA-1 handshake |
++ * hash or buffer all handshake messages. |
++ */ |
++ if (ss->ssl3.hs.hashType == handshake_hash_single && ss->ssl3.hs.md5) { |
++ rv = ssl3_ComputeBackupHandshakeHashes(ss, &hashes); |
++ PORT_Assert(ss->ssl3.hs.md5 == NULL); |
++ } else { |
++ rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0); |
++ } |
+ ssl_ReleaseSpecReadLock(ss); |
+ if (rv != SECSuccess) { |
+ goto done; /* err code was set by ssl3_ComputeHandshakeHashes */ |
+@@ -6098,11 +6155,6 @@ |
+ 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); |
+@@ -6994,6 +7046,31 @@ |
+ } |
+ goto send_no_certificate; |
+ } |
++ |
++ if (isTLS12 && ss->ssl3.hs.md5) { |
++ PRBool need_backup_hash = PR_FALSE; |
++#ifdef _WIN32 |
++ /* If the key is in CAPI, assume conservatively that the CAPI |
++ * service provider may be unable to sign SHA-256 hashes. |
++ * Use SHA-1 if the server supports it. */ |
++ if (ss->ssl3.platformClientKey->dwKeySpec != |
++ CERT_NCRYPT_KEY_SPEC) { |
++ for (i = 0; i < algorithms.len; i += 2) { |
++ /* CAPI only supports RSA and DSA signatures. */ |
++ if (algorithms.data[i] == tls_hash_sha1 && |
++ (algorithms.data[i+1] == tls_sig_rsa || |
++ algorithms.data[i+1] == tls_sig_dsa)) { |
++ need_backup_hash = PR_TRUE; |
++ break; |
++ } |
++ } |
++ } |
++#endif /* _WIN32 */ |
++ if (!need_backup_hash) { |
++ PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE); |
++ ss->ssl3.hs.md5 = NULL; |
++ } |
++ } |
+ break; /* not an error */ |
+ } |
+ #endif /* NSS_PLATFORM_CLIENT_AUTH */ |
+@@ -7227,6 +7304,13 @@ |
+ (ss->ssl3.platformClientKey || |
+ ss->ssl3.clientPrivateKey != NULL); |
+ |
++ if (!sendClientCert && |
++ ss->ssl3.hs.hashType == handshake_hash_single && ss->ssl3.hs.md5) { |
++ /* Don't need the backup handshake hash. */ |
++ PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE); |
++ ss->ssl3.hs.md5 = NULL; |
++ } |
++ |
+ /* We must wait for the server's certificate to be authenticated before |
+ * sending the client certificate in order to disclosing the client |
+ * certificate to an attacker that does not have a valid cert for the |
+Index: net/third_party/nss/ssl/sslimpl.h |
+=================================================================== |
+--- net/third_party/nss/ssl/sslimpl.h (revision 219342) |
++++ net/third_party/nss/ssl/sslimpl.h (working copy) |
+@@ -838,6 +838,9 @@ |
+ * SSL 3.0 - TLS 1.1 use both |md5| and |sha|. |md5| is used for MD5 and |
+ * |sha| for SHA-1. |
+ * TLS 1.2 and later use only |sha|, for SHA-256. */ |
++ /* NOTE: On Windows, TLS 1.2 and later use |md5| as a backup handshake hash |
++ * for generating client auth signatures. Confusingly, the backup hash |
++ * function is SHA-1. */ |
+ PK11Context * md5; |
+ PK11Context * sha; |
+ |