Index: net/third_party/nss/ssl/ssl3con.c |
=================================================================== |
--- net/third_party/nss/ssl/ssl3con.c (revision 221205) |
+++ net/third_party/nss/ssl/ssl3con.c (working copy) |
@@ -3674,6 +3674,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. */ |
@@ -3784,6 +3800,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) { |
@@ -4532,6 +4555,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. |
@@ -5781,7 +5828,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 */ |
@@ -5835,11 +5892,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); |
@@ -6731,6 +6783,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 */ |
@@ -6964,6 +7041,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 |