5f43a7
# HG changeset patch
5f43a7
# User Daiki Ueno <dueno@redhat.com>
5f43a7
# Date 1594360877 -7200
5f43a7
#      Fri Jul 10 08:01:17 2020 +0200
5f43a7
# Node ID df1d2695e115ed9e6f7e8df6ad4d7be2c9bc77d8
5f43a7
# Parent  de661583d46713c9b4873a904dda3a8ba4a61976
5f43a7
Bug 1646324, advertise rsa_pkcs1_* schemes in CH and CR for certs, r=mt
5f43a7
5f43a7
Summary:
5f43a7
In TLS 1.3, unless "signature_algorithms_cert" is advertised, the
5f43a7
"signature_algorithms" extension is used as an indication of supported
5f43a7
algorithms for signatures on certificates.  While rsa_pkcs1_*
5f43a7
signatures schemes cannot be used for signing handshake messages, they
5f43a7
should be advertised if the peer wants to to support certificates
5f43a7
signed with RSA PKCS#1.
5f43a7
5f43a7
This adds a flag to ssl3_EncodeSigAlgs() and ssl3_FilterSigAlgs() to
5f43a7
preserve rsa_pkcs1_* schemes in the output.
5f43a7
5f43a7
Reviewers: mt
5f43a7
5f43a7
Reviewed By: mt
5f43a7
5f43a7
Bug #: 1646324
5f43a7
5f43a7
Differential Revision: https://phabricator.services.mozilla.com/D80881
5f43a7
5f43a7
diff -r de661583d467 -r df1d2695e115 gtests/ssl_gtest/ssl_auth_unittest.cc
5f43a7
--- a/gtests/ssl_gtest/ssl_auth_unittest.cc	Thu Jul 09 22:45:27 2020 +0000
5f43a7
+++ b/gtests/ssl_gtest/ssl_auth_unittest.cc	Fri Jul 10 08:01:17 2020 +0200
5f43a7
@@ -1591,6 +1591,47 @@
5f43a7
             capture->extension());
5f43a7
 }
5f43a7
 
5f43a7
+TEST_P(TlsConnectTls13, Tls13RsaPkcs1IsAdvertisedClient) {
5f43a7
+  EnsureTlsSetup();
5f43a7
+  static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pkcs1_sha256,
5f43a7
+                                                ssl_sig_rsa_pss_rsae_sha256};
5f43a7
+  client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
5f43a7
+  auto capture =
5f43a7
+      MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
5f43a7
+  Connect();
5f43a7
+  // We should only have the one signature algorithm advertised.
5f43a7
+  static const uint8_t kExpectedExt[] = {0,
5f43a7
+                                         4,
5f43a7
+                                         ssl_sig_rsa_pss_rsae_sha256 >> 8,
5f43a7
+                                         ssl_sig_rsa_pss_rsae_sha256 & 0xff,
5f43a7
+                                         ssl_sig_rsa_pkcs1_sha256 >> 8,
5f43a7
+                                         ssl_sig_rsa_pkcs1_sha256 & 0xff};
5f43a7
+  ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
5f43a7
+            capture->extension());
5f43a7
+}
5f43a7
+
5f43a7
+TEST_P(TlsConnectTls13, Tls13RsaPkcs1IsAdvertisedServer) {
5f43a7
+  EnsureTlsSetup();
5f43a7
+  static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pkcs1_sha256,
5f43a7
+                                                ssl_sig_rsa_pss_rsae_sha256};
5f43a7
+  server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
5f43a7
+  auto capture = MakeTlsFilter<TlsExtensionCapture>(
5f43a7
+      server_, ssl_signature_algorithms_xtn, true);
5f43a7
+  capture->SetHandshakeTypes({kTlsHandshakeCertificateRequest});
5f43a7
+  capture->EnableDecryption();
5f43a7
+  server_->RequestClientAuth(false);  // So we get a CertificateRequest.
5f43a7
+  Connect();
5f43a7
+  // We should only have the one signature algorithm advertised.
5f43a7
+  static const uint8_t kExpectedExt[] = {0,
5f43a7
+                                         4,
5f43a7
+                                         ssl_sig_rsa_pss_rsae_sha256 >> 8,
5f43a7
+                                         ssl_sig_rsa_pss_rsae_sha256 & 0xff,
5f43a7
+                                         ssl_sig_rsa_pkcs1_sha256 >> 8,
5f43a7
+                                         ssl_sig_rsa_pkcs1_sha256 & 0xff};
5f43a7
+  ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
5f43a7
+            capture->extension());
5f43a7
+}
5f43a7
+
5f43a7
 // variant, version, certificate, auth type, signature scheme
5f43a7
 typedef std::tuple
5f43a7
                    SSLSignatureScheme>
5f43a7
diff -r de661583d467 -r df1d2695e115 lib/ssl/ssl3con.c
5f43a7
--- a/lib/ssl/ssl3con.c	Thu Jul 09 22:45:27 2020 +0000
5f43a7
+++ b/lib/ssl/ssl3con.c	Fri Jul 10 08:01:17 2020 +0200
5f43a7
@@ -784,15 +784,19 @@
5f43a7
  * Both by policy and by having a token that supports it. */
5f43a7
 static PRBool
5f43a7
 ssl_SignatureSchemeAccepted(PRUint16 minVersion,
5f43a7
-                            SSLSignatureScheme scheme)
5f43a7
+                            SSLSignatureScheme scheme,
5f43a7
+                            PRBool forCert)
5f43a7
 {
5f43a7
     /* Disable RSA-PSS schemes if there are no tokens to verify them. */
5f43a7
     if (ssl_IsRsaPssSignatureScheme(scheme)) {
5f43a7
         if (!PK11_TokenExists(auth_alg_defs[ssl_auth_rsa_pss])) {
5f43a7
             return PR_FALSE;
5f43a7
         }
5f43a7
-    } else if (ssl_IsRsaPkcs1SignatureScheme(scheme)) {
5f43a7
-        /* Disable PKCS#1 signatures if we are limited to TLS 1.3. */
5f43a7
+    } else if (!forCert && ssl_IsRsaPkcs1SignatureScheme(scheme)) {
5f43a7
+        /* Disable PKCS#1 signatures if we are limited to TLS 1.3.
5f43a7
+         * We still need to advertise PKCS#1 signatures in CH and CR
5f43a7
+         * for certificate signatures.
5f43a7
+         */
5f43a7
         if (minVersion >= SSL_LIBRARY_VERSION_TLS_1_3) {
5f43a7
             return PR_FALSE;
5f43a7
         }
5f43a7
@@ -851,7 +855,8 @@
5f43a7
     /* Ensure that there is a signature scheme that can be accepted.*/
5f43a7
     for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
5f43a7
         if (ssl_SignatureSchemeAccepted(ss->vrange.min,
5f43a7
-                                        ss->ssl3.signatureSchemes[i])) {
5f43a7
+                                        ss->ssl3.signatureSchemes[i],
5f43a7
+                                        PR_FALSE /* forCert */)) {
5f43a7
             return SECSuccess;
5f43a7
         }
5f43a7
     }
5f43a7
@@ -880,7 +885,7 @@
5f43a7
         PRBool acceptable = authType == schemeAuthType ||
5f43a7
                             (schemeAuthType == ssl_auth_rsa_pss &&
5f43a7
                              authType == ssl_auth_rsa_sign);
5f43a7
-        if (acceptable && ssl_SignatureSchemeAccepted(ss->version, scheme)) {
5f43a7
+        if (acceptable && ssl_SignatureSchemeAccepted(ss->version, scheme, PR_FALSE /* forCert */)) {
5f43a7
             return PR_TRUE;
5f43a7
         }
5f43a7
     }
5f43a7
@@ -9803,12 +9808,13 @@
5f43a7
 }
5f43a7
 
5f43a7
 SECStatus
5f43a7
-ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, sslBuffer *buf)
5f43a7
+ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool forCert,
5f43a7
+                   sslBuffer *buf)
5f43a7
 {
5f43a7
     SSLSignatureScheme filtered[MAX_SIGNATURE_SCHEMES] = { 0 };
5f43a7
     unsigned int filteredCount = 0;
5f43a7
 
5f43a7
-    SECStatus rv = ssl3_FilterSigAlgs(ss, minVersion, PR_FALSE,
5f43a7
+    SECStatus rv = ssl3_FilterSigAlgs(ss, minVersion, PR_FALSE, forCert,
5f43a7
                                       PR_ARRAY_SIZE(filtered),
5f43a7
                                       filtered, &filteredCount);
5f43a7
     if (rv != SECSuccess) {
5f43a7
@@ -9843,8 +9849,21 @@
5f43a7
     return sslBuffer_InsertLength(buf, lengthOffset, 2);
5f43a7
 }
5f43a7
 
5f43a7
+/*
5f43a7
+ * In TLS 1.3 we are permitted to advertise support for PKCS#1
5f43a7
+ * schemes. This doesn't affect the signatures in TLS itself, just
5f43a7
+ * those on certificates. Not advertising PKCS#1 signatures creates a
5f43a7
+ * serious compatibility risk as it excludes many certificate chains
5f43a7
+ * that include PKCS#1. Hence, forCert is used to enable advertising
5f43a7
+ * PKCS#1 support. Note that we include these in signature_algorithms
5f43a7
+ * because we don't yet support signature_algorithms_cert. TLS 1.3
5f43a7
+ * requires that PKCS#1 schemes are placed last in the list if they
5f43a7
+ * are present. This sorting can be removed once we support
5f43a7
+ * signature_algorithms_cert.
5f43a7
+ */
5f43a7
 SECStatus
5f43a7
 ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool disableRsae,
5f43a7
+                   PRBool forCert,
5f43a7
                    unsigned int maxSchemes, SSLSignatureScheme *filteredSchemes,
5f43a7
                    unsigned int *numFilteredSchemes)
5f43a7
 {
5f43a7
@@ -9856,15 +9875,32 @@
5f43a7
     }
5f43a7
 
5f43a7
     *numFilteredSchemes = 0;
5f43a7
+    PRBool allowUnsortedPkcs1 = forCert && minVersion < SSL_LIBRARY_VERSION_TLS_1_3;
5f43a7
     for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
5f43a7
         if (disableRsae && ssl_IsRsaeSignatureScheme(ss->ssl3.signatureSchemes[i])) {
5f43a7
             continue;
5f43a7
         }
5f43a7
         if (ssl_SignatureSchemeAccepted(minVersion,
5f43a7
-                                        ss->ssl3.signatureSchemes[i])) {
5f43a7
+                                        ss->ssl3.signatureSchemes[i],
5f43a7
+                                        allowUnsortedPkcs1)) {
5f43a7
             filteredSchemes[(*numFilteredSchemes)++] = ss->ssl3.signatureSchemes[i];
5f43a7
         }
5f43a7
     }
5f43a7
+    if (forCert && !allowUnsortedPkcs1) {
5f43a7
+        for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
5f43a7
+            if (disableRsae && ssl_IsRsaeSignatureScheme(ss->ssl3.signatureSchemes[i])) {
5f43a7
+                continue;
5f43a7
+            }
5f43a7
+            if (!ssl_SignatureSchemeAccepted(minVersion,
5f43a7
+                                             ss->ssl3.signatureSchemes[i],
5f43a7
+                                             PR_FALSE) &&
5f43a7
+                ssl_SignatureSchemeAccepted(minVersion,
5f43a7
+                                            ss->ssl3.signatureSchemes[i],
5f43a7
+                                            PR_TRUE)) {
5f43a7
+                filteredSchemes[(*numFilteredSchemes)++] = ss->ssl3.signatureSchemes[i];
5f43a7
+            }
5f43a7
+        }
5f43a7
+    }
5f43a7
     return SECSuccess;
5f43a7
 }
5f43a7
 
5f43a7
@@ -9901,7 +9937,7 @@
5f43a7
 
5f43a7
     length = 1 + certTypesLength + 2 + calen;
5f43a7
     if (isTLS12) {
5f43a7
-        rv = ssl3_EncodeSigAlgs(ss, ss->version, &sigAlgsBuf);
5f43a7
+        rv = ssl3_EncodeSigAlgs(ss, ss->version, PR_TRUE /* forCert */, &sigAlgsBuf);
5f43a7
         if (rv != SECSuccess) {
5f43a7
             return rv;
5f43a7
         }
5f43a7
diff -r de661583d467 -r df1d2695e115 lib/ssl/ssl3exthandle.c
5f43a7
--- a/lib/ssl/ssl3exthandle.c	Thu Jul 09 22:45:27 2020 +0000
5f43a7
+++ b/lib/ssl/ssl3exthandle.c	Fri Jul 10 08:01:17 2020 +0200
5f43a7
@@ -1652,7 +1652,7 @@
5f43a7
         minVersion = ss->vrange.min; /* ClientHello */
5f43a7
     }
5f43a7
 
5f43a7
-    SECStatus rv = ssl3_EncodeSigAlgs(ss, minVersion, buf);
5f43a7
+    SECStatus rv = ssl3_EncodeSigAlgs(ss, minVersion, PR_TRUE /* forCert */, buf);
5f43a7
     if (rv != SECSuccess) {
5f43a7
         return SECFailure;
5f43a7
     }
5f43a7
diff -r de661583d467 -r df1d2695e115 lib/ssl/sslimpl.h
5f43a7
--- a/lib/ssl/sslimpl.h	Thu Jul 09 22:45:27 2020 +0000
5f43a7
+++ b/lib/ssl/sslimpl.h	Fri Jul 10 08:01:17 2020 +0200
5f43a7
@@ -1688,12 +1688,12 @@
5f43a7
 SECStatus ssl3_AuthCertificate(sslSocket *ss);
5f43a7
 SECStatus ssl_ReadCertificateStatus(sslSocket *ss, PRUint8 *b,
5f43a7
                                     PRUint32 length);
5f43a7
-SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion,
5f43a7
+SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool forCert,
5f43a7
                              sslBuffer *buf);
5f43a7
 SECStatus ssl3_EncodeFilteredSigAlgs(const sslSocket *ss,
5f43a7
                                      const SSLSignatureScheme *schemes,
5f43a7
                                      PRUint32 numSchemes, sslBuffer *buf);
5f43a7
-SECStatus ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool disableRsae,
5f43a7
+SECStatus ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool disableRsae, PRBool forCert,
5f43a7
                              unsigned int maxSchemes, SSLSignatureScheme *filteredSchemes,
5f43a7
                              unsigned int *numFilteredSchemes);
5f43a7
 SECStatus ssl_GetCertificateRequestCAs(const sslSocket *ss,
5f43a7
diff -r de661583d467 -r df1d2695e115 lib/ssl/tls13exthandle.c
5f43a7
--- a/lib/ssl/tls13exthandle.c	Thu Jul 09 22:45:27 2020 +0000
5f43a7
+++ b/lib/ssl/tls13exthandle.c	Fri Jul 10 08:01:17 2020 +0200
5f43a7
@@ -1519,7 +1519,8 @@
5f43a7
     SSLSignatureScheme filtered[MAX_SIGNATURE_SCHEMES] = { 0 };
5f43a7
     unsigned int filteredCount = 0;
5f43a7
     SECStatus rv = ssl3_FilterSigAlgs(ss, ss->vrange.max,
5f43a7
-                                      PR_TRUE,
5f43a7
+                                      PR_TRUE /* disableRsae */,
5f43a7
+                                      PR_FALSE /* forCert */,
5f43a7
                                       MAX_SIGNATURE_SCHEMES,
5f43a7
                                       filtered,
5f43a7
                                       &filteredCount);