Bug 1304407 - Handle no matching sigAlgs for client certificate r=mt NSS_3_25_BRANCH
authorTim Taubert <ttaubert@mozilla.com>
Tue, 04 Oct 2016 21:44:49 +0200
branchNSS_3_25_BRANCH
changeset 12668 c579a83e6d9f3f13e1156d529d1209ab3b941bae
parent 12667 d0715ba4da5d7aeca79911106155bb3bd72fd34a
child 12695 224846c1b152e9fa141e5e26c19e6d061414edfa
push id1623
push userttaubert@mozilla.com
push dateTue, 04 Oct 2016 19:54:31 +0000
reviewersmt
bugs1304407
Bug 1304407 - Handle no matching sigAlgs for client certificate r=mt
external_tests/ssl_gtest/ssl_loopback_unittest.cc
lib/ssl/ssl3con.c
--- a/external_tests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/external_tests/ssl_gtest/ssl_loopback_unittest.cc
@@ -471,16 +471,30 @@ TEST_P(TlsConnectPre12, SignatureAlgorit
 
 TEST_P(TlsConnectTls12, RequestClientAuthWithSha384) {
   server_->SetSignatureAlgorithms(SignatureRsaSha384,
                                   PR_ARRAY_SIZE(SignatureRsaSha384));
   server_->RequestClientAuth(false);
   Connect();
 }
 
+TEST_P(TlsConnectTls12, ClientAuthNoMatchingSigAlgs) {
+  Reset(TlsAgent::kServerEcdsa);
+  server_->RequestClientAuth(false);
+  client_->SetupClientAuth();
+
+  server_->EnableCiphersByAuthType(ssl_auth_ecdh_ecdsa);
+  server_->SetSignatureAlgorithms(SignatureEcdsaSha256,
+                                  PR_ARRAY_SIZE(SignatureEcdsaSha256));
+
+  Connect();
+  CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa);
+  EXPECT_TRUE(!SSL_PeerCertificate(server_->ssl_fd()));
+}
+
 TEST_P(TlsConnectGeneric, ConnectAlpn) {
   EnableAlpn();
   Connect();
   client_->CheckAlpn(SSL_NEXT_PROTO_SELECTED, "a");
   server_->CheckAlpn(SSL_NEXT_PROTO_NEGOTIATED, "a");
 }
 
 TEST_P(TlsConnectDatagram, ConnectSrtp) {
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -7895,17 +7895,17 @@ ssl3_ExtractClientKeyInfo(sslSocket *ss,
     }
 
 done:
     if (pubk)
         SECKEY_DestroyPublicKey(pubk);
     return rv;
 }
 
-static void
+static SECStatus
 ssl3_DecideTls12CertVerifyHash(sslSocket *ss, const SECItem *algorithms);
 
 typedef struct dnameNode {
     struct dnameNode *next;
     SECItem name;
 } dnameNode;
 
 /*
@@ -8126,17 +8126,20 @@ ssl3_CompleteHandleCertificateRequest(ss
                 CERT_DestroyCertificate(ss->ssl3.clientCertificate);
                 ss->ssl3.clientCertificate = NULL;
                 SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
                 ss->ssl3.clientPrivateKey = NULL;
                 goto send_no_certificate;
             }
             if (ss->ssl3.hs.hashType == handshake_hash_record ||
                 ss->ssl3.hs.hashType == handshake_hash_single) {
-                ssl3_DecideTls12CertVerifyHash(ss, algorithms);
+                rv = ssl3_DecideTls12CertVerifyHash(ss, algorithms);
+                if (rv != SECSuccess) {
+                    goto send_no_certificate;
+                }
             }
             break; /* not an error */
 
         case SECFailure:
         default:
         send_no_certificate:
             if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) {
                 ss->ssl3.sendEmptyCert = PR_TRUE;
@@ -10200,31 +10203,31 @@ ssl3_PickSignatureHashAlgorithm(sslSocke
             }
         }
     }
 
     PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
     return SECFailure;
 }
 
-static void
+static SECStatus
 ssl3_DecideTls12CertVerifyHash(sslSocket *ss, const SECItem *algorithms)
 {
     SECStatus rv;
     SSLSignType sigAlg;
     PRBool preferSha1 = PR_FALSE;
     PRBool supportsSha1 = PR_FALSE;
     PRBool supportsHandshakeHash = PR_FALSE;
     unsigned int i;
     SSLHashType otherHashAlg = ssl_hash_none;
 
     /* Determine the key's signature algorithm and whether it prefers SHA-1. */
     rv = ssl3_ExtractClientKeyInfo(ss, &sigAlg, &preferSha1);
     if (rv != SECSuccess) {
-        return;
+        return SECFailure;
     }
 
     /* Determine the server's hash support for that signature algorithm. */
     for (i = 0; i < algorithms->len; i += 2) {
         if (algorithms->data[i + 1] == sigAlg) {
             SSLHashType hashAlg = algorithms->data[i];
             SECOidTag hashOID;
             PRUint32 policy;
@@ -10252,16 +10255,23 @@ ssl3_DecideTls12CertVerifyHash(sslSocket
 
     if (supportsSha1 && preferSha1) {
         ss->ssl3.hs.tls12CertVerifyHash = ssl_hash_sha1;
     } else if (supportsHandshakeHash) {
         ss->ssl3.hs.tls12CertVerifyHash = ssl3_GetSuitePrfHash(ss); /* Use suite PRF hash. */
     } else {
         ss->ssl3.hs.tls12CertVerifyHash = otherHashAlg;
     }
+
+    /* We didn't find a sigAlg matching the client cert's key type. */
+    if (ss->ssl3.hs.tls12CertVerifyHash == ssl_hash_none) {
+        return SECFailure;
+    }
+
+    return SECSuccess;
 }
 
 static SECStatus
 ssl3_SendServerKeyExchange(sslSocket *ss)
 {
     const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def;
     SECStatus rv = SECFailure;
     int length;