blob: 85e5308db6b48453f300e57eee3ccce350a5163f [file] [log] [blame]
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;
}