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