| diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c |
| index 06992e0..cf7ef32 100644 |
| --- a/net/third_party/nss/ssl/ssl3con.c |
| +++ b/net/third_party/nss/ssl/ssl3con.c |
| @@ -6973,14 +6973,27 @@ no_memory: /* no-memory error has already been set. */ |
| |
| |
| /* |
| - * Returns true if the client authentication key is an RSA or DSA key that |
| - * may be able to sign only SHA-1 hashes. |
| + * Returns the TLS signature algorithm for the client authentication key and |
| + * whether it is an RSA or DSA key that may be able to sign only SHA-1 hashes. |
| */ |
| -static PRBool |
| -ssl3_ClientKeyPrefersSHA1(sslSocket *ss) |
| +static SECStatus |
| +ssl3_ExtractClientKeyInfo(sslSocket *ss, |
| + TLSSignatureAlgorithm *sigAlg, |
| + PRBool *preferSha1) |
| { |
| + SECStatus rv = SECSuccess; |
| SECKEYPublicKey *pubk; |
| - PRBool prefer_sha1 = PR_FALSE; |
| + |
| + pubk = CERT_ExtractPublicKey(ss->ssl3.clientCertificate); |
| + if (pubk == NULL) { |
| + rv = SECFailure; |
| + goto done; |
| + } |
| + |
| + rv = ssl3_TLSSignatureAlgorithmForKeyType(pubk->keyType, sigAlg); |
| + if (rv != SECSuccess) { |
| + goto done; |
| + } |
| |
| #if defined(NSS_PLATFORM_CLIENT_AUTH) && defined(_WIN32) |
| /* If the key is in CAPI, assume conservatively that the CAPI service |
| @@ -6989,7 +7002,8 @@ ssl3_ClientKeyPrefersSHA1(sslSocket *ss) |
| if (ss->ssl3.platformClientKey->dwKeySpec != CERT_NCRYPT_KEY_SPEC) { |
| /* CAPI only supports RSA and DSA signatures, so we don't need to |
| * check the key type. */ |
| - return PR_TRUE; |
| + *preferSha1 = PR_TRUE; |
| + goto done; |
| } |
| #endif /* NSS_PLATFORM_CLIENT_AUTH && _WIN32 */ |
| |
| @@ -6999,38 +7013,61 @@ ssl3_ClientKeyPrefersSHA1(sslSocket *ss) |
| * older, DSA key size is at most 1024 bits and the hash function must |
| * be SHA-1. |
| */ |
| - pubk = CERT_ExtractPublicKey(ss->ssl3.clientCertificate); |
| - if (pubk == NULL) { |
| - return PR_FALSE; |
| - } |
| if (pubk->keyType == rsaKey || pubk->keyType == dsaKey) { |
| - prefer_sha1 = SECKEY_PublicKeyStrength(pubk) <= 128; |
| + *preferSha1 = SECKEY_PublicKeyStrength(pubk) <= 128; |
| + } else { |
| + *preferSha1 = PR_FALSE; |
| } |
| - SECKEY_DestroyPublicKey(pubk); |
| - return prefer_sha1; |
| + |
| + done: |
| + if (pubk) |
| + SECKEY_DestroyPublicKey(pubk); |
| + return rv; |
| } |
| |
| -/* Destroys the backup handshake hash context if we don't need it. */ |
| +/* Destroys the backup handshake hash context if we don't need it. Note that |
| + * this function selects the hash algorithm for client authentication |
| + * signatures; ssl3_SendCertificateVerify uses the presence of the backup hash |
| + * to determine whether to use SHA-1 or SHA-256. */ |
| static void |
| ssl3_DestroyBackupHandshakeHashIfNotNeeded(sslSocket *ss, |
| const SECItem *algorithms) |
| { |
| - PRBool need_backup_hash = PR_FALSE; |
| + SECStatus rv; |
| + TLSSignatureAlgorithm sigAlg; |
| + PRBool preferSha1; |
| + PRBool supportsSha1 = PR_FALSE; |
| + PRBool supportsSha256 = PR_FALSE; |
| + PRBool needBackupHash = PR_FALSE; |
| unsigned int i; |
| |
| PORT_Assert(ss->ssl3.hs.md5); |
| - if (ssl3_ClientKeyPrefersSHA1(ss)) { |
| - /* Use SHA-1 if the server supports it. */ |
| - for (i = 0; i < algorithms->len; i += 2) { |
| - 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; |
| + |
| + /* Determine the key's signature algorithm and whether it prefers SHA-1. */ |
| + rv = ssl3_ExtractClientKeyInfo(ss, &sigAlg, &preferSha1); |
| + if (rv != SECSuccess) { |
| + goto done; |
| + } |
| + |
| + /* Determine the server's hash support for that signature algorithm. */ |
| + for (i = 0; i < algorithms->len; i += 2) { |
| + if (algorithms->data[i+1] == sigAlg) { |
| + if (algorithms->data[i] == tls_hash_sha1) { |
| + supportsSha1 = PR_TRUE; |
| + } else if (algorithms->data[i] == tls_hash_sha256) { |
| + supportsSha256 = PR_TRUE; |
| } |
| } |
| } |
| - if (!need_backup_hash) { |
| + |
| + /* If either the server does not support SHA-256 or the client key prefers |
| + * SHA-1, leave the backup hash. */ |
| + if (supportsSha1 && (preferSha1 || !supportsSha256)) { |
| + needBackupHash = PR_TRUE; |
| + } |
| + |
| +done: |
| + if (!needBackupHash) { |
| PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE); |
| ss->ssl3.hs.md5 = NULL; |
| } |