Blob Blame History Raw
diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -7061,49 +7061,68 @@ ssl3_SendClientKeyExchange(sslSocket *ss
 
 loser:
     if (serverKey)
         SECKEY_DestroyPublicKey(serverKey);
     return rv; /* err code already set. */
 }
 
 static SECStatus
-ssl_PickSignatureScheme(sslSocket *ss, SECKEYPublicKey *key,
+ssl_PickSignatureScheme(sslSocket *ss,
+                        SECKEYPublicKey *pubKey,
+                        SECKEYPrivateKey *privKey,
                         const SignatureScheme *peerSchemes,
                         unsigned int peerSchemeCount,
                         PRBool requireSha1)
 {
     unsigned int i, j;
     const namedGroupDef *group = NULL;
     KeyType keyType;
+    PK11SlotInfo *slot;
+    PRBool slotDoesPss;
     PRBool isTLS13 = ss->version == SSL_LIBRARY_VERSION_TLS_1_3;
 
-    if (!key) {
+    if (!pubKey || !privKey) {
         PORT_Assert(0);
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
-    keyType = SECKEY_GetPublicKeyType(key);
+    slot = PK11_GetSlotFromPrivateKey(privKey);
+    if (!slot) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    slotDoesPss = PK11_DoesMechanism(slot, auth_alg_defs[ssl_auth_rsa_pss]);
+    PK11_FreeSlot(slot);
+
+    keyType = SECKEY_GetPublicKeyType(pubKey);
+
     if (keyType == ecKey) {
-        group = ssl_ECPubKey2NamedGroup(key);
+        group = ssl_ECPubKey2NamedGroup(pubKey);
     }
 
     /* Here we look for the first local preference that the client has
      * indicated support for in their signature_algorithms extension. */
     for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
         SSLHashType hashType;
         SECOidTag hashOID;
         SignatureScheme preferred = ss->ssl3.signatureSchemes[i];
         PRUint32 policy;
 
         if (!ssl_SignatureSchemeValidForKey(isTLS13, keyType, group,
                                             preferred)) {
             continue;
         }
 
+        /* Skip RSA-PSS schemes when the certificate's private key slot does
+         * not support this signature mechanism. */
+        if (ssl_IsRsaPssSignatureScheme(preferred) && !slotDoesPss) {
+            continue;
+        }
+
         hashType = ssl_SignatureSchemeToHashType(preferred);
         hashOID = ssl3_HashTypeToOID(hashType);
         if (requireSha1 && hashOID != SEC_OID_SHA1) {
             continue;
         }
         if ((NSS_GetAlgorithmPolicy(hashOID, &policy) == SECSuccess) &&
             !(policy & NSS_USE_ALG_IN_SSL_KX)) {
             /* we ignore hashes we don't support */
@@ -7148,51 +7167,54 @@ ssl3_PickServerSignatureScheme(sslSocket
                 PORT_Assert(0);
                 PORT_SetError(SEC_ERROR_INVALID_KEY);
                 return SECFailure;
         }
         return SECSuccess;
     }
 
     /* Sets error code, if needed. */
-    return ssl_PickSignatureScheme(ss, keyPair->pubKey,
+    return ssl_PickSignatureScheme(ss, keyPair->pubKey, keyPair->privKey,
                                    ss->ssl3.hs.clientSigSchemes,
                                    ss->ssl3.hs.numClientSigScheme,
-                                   PR_FALSE);
+                                   PR_FALSE /* requireSha1 */);
 }
 
 static SECStatus
 ssl_PickClientSignatureScheme(sslSocket *ss, const SignatureScheme *schemes,
                               unsigned int numSchemes)
 {
-    SECKEYPublicKey *key;
+    SECKEYPrivateKey *privKey = ss->ssl3.clientPrivateKey;
+    SECKEYPublicKey *pubKey;
     SECStatus rv;
 
-    key = CERT_ExtractPublicKey(ss->ssl3.clientCertificate);
-    PORT_Assert(key);
+    pubKey = CERT_ExtractPublicKey(ss->ssl3.clientCertificate);
+    PORT_Assert(pubKey);
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 &&
-        (SECKEY_GetPublicKeyType(key) == rsaKey ||
-         SECKEY_GetPublicKeyType(key) == dsaKey) &&
-        SECKEY_PublicKeyStrengthInBits(key) <= 1024) {
+        (SECKEY_GetPublicKeyType(pubKey) == rsaKey ||
+         SECKEY_GetPublicKeyType(pubKey) == dsaKey) &&
+        SECKEY_PublicKeyStrengthInBits(pubKey) <= 1024) {
         /* If the key is a 1024-bit RSA or DSA key, assume conservatively that
          * it may be unable to sign SHA-256 hashes. This is the case for older
          * Estonian ID cards that have 1024-bit RSA keys. In FIPS 186-2 and
          * older, DSA key size is at most 1024 bits and the hash function must
          * be SHA-1.
          */
-        rv = ssl_PickSignatureScheme(ss, key, schemes, numSchemes, PR_TRUE);
+        rv = ssl_PickSignatureScheme(ss, pubKey, privKey, schemes, numSchemes,
+                                     PR_TRUE /* requireSha1 */);
         if (rv == SECSuccess) {
-            SECKEY_DestroyPublicKey(key);
+            SECKEY_DestroyPublicKey(pubKey);
             return SECSuccess;
         }
         /* If this fails, that's because the peer doesn't advertise SHA-1,
          * so fall back to the full negotiation. */
     }
-    rv = ssl_PickSignatureScheme(ss, key, schemes, numSchemes, PR_FALSE);
-    SECKEY_DestroyPublicKey(key);
+    rv = ssl_PickSignatureScheme(ss, pubKey, privKey, schemes, numSchemes,
+                                 PR_FALSE /* requireSha1 */);
+    SECKEY_DestroyPublicKey(pubKey);
     return rv;
 }
 
 /* Called from ssl3_HandleServerHelloDone(). */
 static SECStatus
 ssl3_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey)
 {
     SECStatus rv = SECFailure;
@@ -10593,16 +10615,23 @@ ssl3_EncodeSigAlgs(sslSocket *ss, PRUint
         return SECFailure;
     }
 
     for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
         PRUint32 policy = 0;
         SSLHashType hashType = ssl_SignatureSchemeToHashType(
             ss->ssl3.signatureSchemes[i]);
         SECOidTag hashOID = ssl3_HashTypeToOID(hashType);
+
+        /* Skip RSA-PSS schemes if there are no tokens to verify them. */
+        if (ssl_IsRsaPssSignatureScheme(ss->ssl3.signatureSchemes[i]) &&
+            !PK11_TokenExists(auth_alg_defs[ssl_auth_rsa_pss])) {
+            continue;
+        }
+
         if ((NSS_GetAlgorithmPolicy(hashOID, &policy) != SECSuccess) ||
             (policy & NSS_USE_ALG_IN_SSL_KX)) {
             p = ssl_EncodeUintX((PRUint32)ss->ssl3.signatureSchemes[i], 2, p);
         }
     }
 
     if (p == buf) {
         PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);