Implement rsa_pkcs1_sha256_legacy.

See draft-ietf-tls13-pkcs1-00. The code point is disabled by default
and must be configured in SSL_set_verify_algorithm_prefs and
SSL_set_signing_algorithm_prefs. It is also only defined for TLS 1.3
client certificates and otherwise ignored.

This required reworking the tests a bit since this is the first
signature algorithm that's disabled by default, and the first algorithm
that behaves differently between client and server.

Bug: 347047841
Change-Id: If4f653a456799ed9f0173159da291a9b6b6556fb
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/69368
Auto-Submit: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 63b66b4..9d7abe8 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1205,6 +1205,11 @@
 #define SSL_SIGN_RSA_PSS_RSAE_SHA512 0x0806
 #define SSL_SIGN_ED25519 0x0807
 
+// SSL_SIGN_RSA_PKCS1_SHA256_LEGACY is a backport of RSASSA-PKCS1-v1_5 with
+// SHA-256 to TLS 1.3. It is disabled by default and only defined for client
+// certificates.
+#define SSL_SIGN_RSA_PKCS1_SHA256_LEGACY 0x0420
+
 // SSL_SIGN_RSA_PKCS1_MD5_SHA1 is an internal signature algorithm used to
 // specify raw RSASSA-PKCS1-v1_5 with an MD5/SHA-1 concatenation, as used in TLS
 // before TLS 1.2.
diff --git a/ssl/extensions.cc b/ssl/extensions.cc
index 586edbd..3f35276 100644
--- a/ssl/extensions.cc
+++ b/ssl/extensions.cc
@@ -446,7 +446,7 @@
   // key, the TLS version, and what we advertised.
   Span<const uint16_t> sigalgs = tls12_get_verify_sigalgs(hs);
   if (std::find(sigalgs.begin(), sigalgs.end(), sigalg) == sigalgs.end() ||
-      !ssl_pkey_supports_algorithm(hs->ssl, pkey, sigalg)) {
+      !ssl_pkey_supports_algorithm(hs->ssl, pkey, sigalg, /*is_verify=*/true)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
     *out_alert = SSL_AD_ILLEGAL_PARAMETER;
     return false;
@@ -4149,7 +4149,8 @@
                                      ? MakeConstSpan(kSignSignatureAlgorithms)
                                      : cred->sigalgs;
   for (uint16_t sigalg : sigalgs) {
-    if (!ssl_pkey_supports_algorithm(ssl, cred->pubkey.get(), sigalg)) {
+    if (!ssl_pkey_supports_algorithm(ssl, cred->pubkey.get(), sigalg,
+                                     /*is_verify=*/false)) {
       continue;
     }
 
diff --git a/ssl/internal.h b/ssl/internal.h
index 7145d13..2e44641 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1094,7 +1094,7 @@
 // ssl_pkey_supports_algorithm returns whether |pkey| may be used to sign
 // |sigalg|.
 bool ssl_pkey_supports_algorithm(const SSL *ssl, EVP_PKEY *pkey,
-                                 uint16_t sigalg);
+                                 uint16_t sigalg, bool is_verify);
 
 // ssl_public_key_verify verifies that the |signature| is valid for the public
 // key |pkey| and input |in|, using the signature algorithm |sigalg|.
diff --git a/ssl/ssl_privkey.cc b/ssl/ssl_privkey.cc
index 9cf2c8f..471be76 100644
--- a/ssl/ssl_privkey.cc
+++ b/ssl/ssl_privkey.cc
@@ -85,29 +85,61 @@
   int curve;
   const EVP_MD *(*digest_func)(void);
   bool is_rsa_pss;
+  bool tls12_ok;
+  bool tls13_ok;
+  bool client_only;
 } SSL_SIGNATURE_ALGORITHM;
 
 static const SSL_SIGNATURE_ALGORITHM kSignatureAlgorithms[] = {
+    // PKCS#1 v1.5 code points are only allowed in TLS 1.2.
     {SSL_SIGN_RSA_PKCS1_MD5_SHA1, EVP_PKEY_RSA, NID_undef, &EVP_md5_sha1,
-     false},
-    {SSL_SIGN_RSA_PKCS1_SHA1, EVP_PKEY_RSA, NID_undef, &EVP_sha1, false},
-    {SSL_SIGN_RSA_PKCS1_SHA256, EVP_PKEY_RSA, NID_undef, &EVP_sha256, false},
-    {SSL_SIGN_RSA_PKCS1_SHA384, EVP_PKEY_RSA, NID_undef, &EVP_sha384, false},
-    {SSL_SIGN_RSA_PKCS1_SHA512, EVP_PKEY_RSA, NID_undef, &EVP_sha512, false},
+     /*is_rsa_pss=*/false, /*tls12_ok=*/true, /*tls13_ok=*/false,
+     /*client_only=*/false},
+    {SSL_SIGN_RSA_PKCS1_SHA1, EVP_PKEY_RSA, NID_undef, &EVP_sha1,
+     /*is_rsa_pss=*/false, /*tls12_ok=*/true, /*tls13_ok=*/false,
+     /*client_only=*/false},
+    {SSL_SIGN_RSA_PKCS1_SHA256, EVP_PKEY_RSA, NID_undef, &EVP_sha256,
+     /*is_rsa_pss=*/false, /*tls12_ok=*/true, /*tls13_ok=*/false,
+     /*client_only=*/false},
+    {SSL_SIGN_RSA_PKCS1_SHA384, EVP_PKEY_RSA, NID_undef, &EVP_sha384,
+     /*is_rsa_pss=*/false, /*tls12_ok=*/true, /*tls13_ok=*/false,
+     /*client_only=*/false},
+    {SSL_SIGN_RSA_PKCS1_SHA512, EVP_PKEY_RSA, NID_undef, &EVP_sha512,
+     /*is_rsa_pss=*/false, /*tls12_ok=*/true, /*tls13_ok=*/false,
+     /*client_only=*/false},
 
-    {SSL_SIGN_RSA_PSS_RSAE_SHA256, EVP_PKEY_RSA, NID_undef, &EVP_sha256, true},
-    {SSL_SIGN_RSA_PSS_RSAE_SHA384, EVP_PKEY_RSA, NID_undef, &EVP_sha384, true},
-    {SSL_SIGN_RSA_PSS_RSAE_SHA512, EVP_PKEY_RSA, NID_undef, &EVP_sha512, true},
+    // Legacy PKCS#1 v1.5 code points are only allowed in TLS 1.3 and
+    // client-only. See draft-ietf-tls-tls13-pkcs1-00.
+    {SSL_SIGN_RSA_PKCS1_SHA256_LEGACY, EVP_PKEY_RSA, NID_undef, &EVP_sha256,
+     /*is_rsa_pss=*/false, /*tls12_ok=*/false, /*tls13_ok=*/true,
+     /*client_only=*/true},
 
-    {SSL_SIGN_ECDSA_SHA1, EVP_PKEY_EC, NID_undef, &EVP_sha1, false},
+    {SSL_SIGN_RSA_PSS_RSAE_SHA256, EVP_PKEY_RSA, NID_undef, &EVP_sha256,
+     /*is_rsa_pss=*/true, /*tls12_ok=*/true, /*tls13_ok=*/true,
+     /*client_only=*/false},
+    {SSL_SIGN_RSA_PSS_RSAE_SHA384, EVP_PKEY_RSA, NID_undef, &EVP_sha384,
+     /*is_rsa_pss=*/true, /*tls12_ok=*/true, /*tls13_ok=*/true,
+     /*client_only=*/false},
+    {SSL_SIGN_RSA_PSS_RSAE_SHA512, EVP_PKEY_RSA, NID_undef, &EVP_sha512,
+     /*is_rsa_pss=*/true, /*tls12_ok=*/true, /*tls13_ok=*/true,
+     /*client_only=*/false},
+
+    {SSL_SIGN_ECDSA_SHA1, EVP_PKEY_EC, NID_undef, &EVP_sha1,
+     /*is_rsa_pss=*/false, /*tls12_ok=*/true, /*tls13_ok=*/false,
+     /*client_only=*/false},
     {SSL_SIGN_ECDSA_SECP256R1_SHA256, EVP_PKEY_EC, NID_X9_62_prime256v1,
-     &EVP_sha256, false},
+     &EVP_sha256, /*is_rsa_pss=*/false, /*tls12_ok=*/true, /*tls13_ok=*/true,
+     /*client_only=*/false},
     {SSL_SIGN_ECDSA_SECP384R1_SHA384, EVP_PKEY_EC, NID_secp384r1, &EVP_sha384,
-     false},
+     /*is_rsa_pss=*/false, /*tls12_ok=*/true, /*tls13_ok=*/true,
+     /*client_only=*/false},
     {SSL_SIGN_ECDSA_SECP521R1_SHA512, EVP_PKEY_EC, NID_secp521r1, &EVP_sha512,
-     false},
+     /*is_rsa_pss=*/false, /*tls12_ok=*/true, /*tls13_ok=*/true,
+     /*client_only=*/false},
 
-    {SSL_SIGN_ED25519, EVP_PKEY_ED25519, NID_undef, nullptr, false},
+    {SSL_SIGN_ED25519, EVP_PKEY_ED25519, NID_undef, nullptr,
+     /*is_rsa_pss=*/false, /*tls12_ok=*/true, /*tls13_ok=*/true,
+     /*client_only=*/false},
 };
 
 static const SSL_SIGNATURE_ALGORITHM *get_signature_algorithm(uint16_t sigalg) {
@@ -120,7 +152,7 @@
 }
 
 bool ssl_pkey_supports_algorithm(const SSL *ssl, EVP_PKEY *pkey,
-                                 uint16_t sigalg) {
+                                 uint16_t sigalg, bool is_verify) {
   const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg);
   if (alg == NULL || EVP_PKEY_id(pkey) != alg->pkey_type) {
     return false;
@@ -152,8 +184,12 @@
   }
 
   if (ssl_protocol_version(ssl) >= TLS1_3_VERSION) {
-    // RSA keys may only be used with RSA-PSS.
-    if (alg->pkey_type == EVP_PKEY_RSA && !alg->is_rsa_pss) {
+    if (!alg->tls13_ok) {
+      return false;
+    }
+
+    bool is_client_sign = ssl->server == is_verify;
+    if (alg->client_only && !is_client_sign) {
       return false;
     }
 
@@ -164,6 +200,8 @@
              EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey))) != alg->curve)) {
       return false;
     }
+  } else if (!alg->tls12_ok) {
+    return false;
   }
 
   return true;
@@ -171,7 +209,7 @@
 
 static bool setup_ctx(SSL *ssl, EVP_MD_CTX *ctx, EVP_PKEY *pkey,
                       uint16_t sigalg, bool is_verify) {
-  if (!ssl_pkey_supports_algorithm(ssl, pkey, sigalg)) {
+  if (!ssl_pkey_supports_algorithm(ssl, pkey, sigalg, is_verify)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
     return false;
   }
@@ -448,7 +486,7 @@
       ctx->cert->default_credential.get(), key_method));
 }
 
-static constexpr size_t kMaxSignatureAlgorithmNameLen = 23;
+static constexpr size_t kMaxSignatureAlgorithmNameLen = 24;
 
 struct SignatureAlgorithmName {
   uint16_t signature_algorithm;
@@ -461,6 +499,7 @@
     {SSL_SIGN_RSA_PKCS1_MD5_SHA1, "rsa_pkcs1_md5_sha1"},
     {SSL_SIGN_RSA_PKCS1_SHA1, "rsa_pkcs1_sha1"},
     {SSL_SIGN_RSA_PKCS1_SHA256, "rsa_pkcs1_sha256"},
+    {SSL_SIGN_RSA_PKCS1_SHA256_LEGACY, "rsa_pkcs1_sha256_legacy"},
     {SSL_SIGN_RSA_PKCS1_SHA384, "rsa_pkcs1_sha384"},
     {SSL_SIGN_RSA_PKCS1_SHA512, "rsa_pkcs1_sha512"},
     {SSL_SIGN_ECDSA_SHA1, "ecdsa_sha1"},
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 1681c2b..3a8caa1 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -215,6 +215,9 @@
 	signatureEd25519 signatureAlgorithm = 0x0807
 	signatureEd448   signatureAlgorithm = 0x0808
 
+	// draft-ietf-tls-tls13-pkcs1-00
+	signatureRSAPKCS1WithSHA256Legacy signatureAlgorithm = 0x0420
+
 	// signatureRSAPKCS1WithMD5AndSHA1 is the internal value BoringSSL uses to
 	// represent the TLS 1.0/1.1 RSA MD5/SHA1 concatenation. We define the
 	// constant here to test that this doesn't leak into the protocol.
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index 7172b3d..a0a81f9 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -1300,9 +1300,9 @@
 		c.peerSignatureAlgorithm = certVerifyMsg.signatureAlgorithm
 		input := hs.finishedHash.certificateVerifyInput(serverCertificateVerifyContextTLS13)
 		if c.peerDelegatedCredential != nil {
-			err = verifyMessageDC(c.vers, hs.peerPublicKey, c.config, certVerifyMsg.signatureAlgorithm, input, certVerifyMsg.signature)
+			err = verifyMessageDC(c.isClient, c.vers, hs.peerPublicKey, c.config, certVerifyMsg.signatureAlgorithm, input, certVerifyMsg.signature)
 		} else {
-			err = verifyMessage(c.vers, hs.peerPublicKey, c.config, certVerifyMsg.signatureAlgorithm, input, certVerifyMsg.signature)
+			err = verifyMessage(c.isClient, c.vers, hs.peerPublicKey, c.config, certVerifyMsg.signatureAlgorithm, input, certVerifyMsg.signature)
 		}
 		if err != nil {
 			return err
@@ -1452,7 +1452,7 @@
 
 			// Determine the hash to sign.
 			var err error
-			certVerify.signatureAlgorithm, err = selectSignatureAlgorithm(c.vers, credential, c.config, certReq.signatureAlgorithms)
+			certVerify.signatureAlgorithm, err = selectSignatureAlgorithm(c.isClient, c.vers, credential, c.config, certReq.signatureAlgorithms)
 			if err != nil {
 				c.sendAlert(alertInternalError)
 				return err
@@ -1460,7 +1460,7 @@
 
 			privKey := credential.PrivateKey
 			input := hs.finishedHash.certificateVerifyInput(clientCertificateVerifyContextTLS13)
-			certVerify.signature, err = signMessage(c.vers, privKey, c.config, certVerify.signatureAlgorithm, input)
+			certVerify.signature, err = signMessage(c.isClient, c.vers, privKey, c.config, certVerify.signatureAlgorithm, input)
 			if err != nil {
 				c.sendAlert(alertInternalError)
 				return err
@@ -1765,7 +1765,7 @@
 
 		// Determine the hash to sign.
 		if certVerify.hasSignatureAlgorithm {
-			certVerify.signatureAlgorithm, err = selectSignatureAlgorithm(c.vers, credential, c.config, certReq.signatureAlgorithms)
+			certVerify.signatureAlgorithm, err = selectSignatureAlgorithm(c.isClient, c.vers, credential, c.config, certReq.signatureAlgorithms)
 			if err != nil {
 				c.sendAlert(alertInternalError)
 				return err
@@ -1773,7 +1773,7 @@
 		}
 
 		privKey := c.config.Credential.PrivateKey
-		certVerify.signature, err = signMessage(c.vers, privKey, c.config, certVerify.signatureAlgorithm, hs.finishedHash.buffer)
+		certVerify.signature, err = signMessage(c.isClient, c.vers, privKey, c.config, certVerify.signatureAlgorithm, hs.finishedHash.buffer)
 		if err == nil && c.config.Bugs.SendSignatureAlgorithm != 0 {
 			certVerify.signatureAlgorithm = c.config.Bugs.SendSignatureAlgorithm
 		}
@@ -1885,7 +1885,7 @@
 		}
 
 		signedMsg := delegatedCredentialSignedMessage(dc.signedBytes, dc.algorithm, certs[0].Raw)
-		if err := verifyMessage(c.vers, leafPublicKey, c.config, dc.algorithm, signedMsg, dc.signature); err != nil {
+		if err := verifyMessage(c.isClient, c.vers, leafPublicKey, c.config, dc.algorithm, signedMsg, dc.signature); err != nil {
 			c.sendAlert(alertBadCertificate)
 			return errors.New("tls: failed to verify delegated credential: " + err.Error())
 		}
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 7459b5b..2e87d54 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -1169,7 +1169,7 @@
 
 		// Determine the hash to sign.
 		var err error
-		certVerify.signatureAlgorithm, err = selectSignatureAlgorithm(c.vers, hs.cert, config, hs.clientHello.signatureAlgorithms)
+		certVerify.signatureAlgorithm, err = selectSignatureAlgorithm(c.isClient, c.vers, hs.cert, config, hs.clientHello.signatureAlgorithms)
 		if err != nil {
 			c.sendAlert(alertInternalError)
 			return err
@@ -1177,7 +1177,7 @@
 
 		privKey := hs.cert.PrivateKey
 		input := hs.finishedHash.certificateVerifyInput(serverCertificateVerifyContextTLS13)
-		certVerify.signature, err = signMessage(c.vers, privKey, c.config, certVerify.signatureAlgorithm, input)
+		certVerify.signature, err = signMessage(c.isClient, c.vers, privKey, c.config, certVerify.signatureAlgorithm, input)
 		if err != nil {
 			c.sendAlert(alertInternalError)
 			return err
@@ -1362,7 +1362,7 @@
 
 			c.peerSignatureAlgorithm = certVerify.signatureAlgorithm
 			input := hs.finishedHash.certificateVerifyInput(clientCertificateVerifyContextTLS13)
-			if err := verifyMessage(c.vers, pub, config, certVerify.signatureAlgorithm, input, certVerify.signature); err != nil {
+			if err := verifyMessage(c.isClient, c.vers, pub, config, certVerify.signatureAlgorithm, input, certVerify.signature); err != nil {
 				c.sendAlert(alertBadCertificate)
 				return err
 			}
@@ -2093,7 +2093,7 @@
 			c.peerSignatureAlgorithm = sigAlg
 		}
 
-		if err := verifyMessage(c.vers, pub, c.config, sigAlg, hs.finishedHash.buffer, certVerify.signature); err != nil {
+		if err := verifyMessage(c.isClient, c.vers, pub, c.config, sigAlg, hs.finishedHash.buffer, certVerify.signature); err != nil {
 			c.sendAlert(alertBadCertificate)
 			return errors.New("could not validate signature of connection nonces: " + err.Error())
 		}
diff --git a/ssl/test/runner/key_agreement.go b/ssl/test/runner/key_agreement.go
index 39377f8..aff0820 100644
--- a/ssl/test/runner/key_agreement.go
+++ b/ssl/test/runner/key_agreement.go
@@ -65,13 +65,13 @@
 
 	var sigAlg signatureAlgorithm
 	if ka.version >= VersionTLS12 {
-		sigAlg, err = selectSignatureAlgorithm(ka.version, cert, config, clientHello.signatureAlgorithms)
+		sigAlg, err = selectSignatureAlgorithm(false /* server */, ka.version, cert, config, clientHello.signatureAlgorithms)
 		if err != nil {
 			return nil, err
 		}
 	}
 
-	sig, err := signMessage(ka.version, cert.PrivateKey, config, sigAlg, serverRSAParams)
+	sig, err := signMessage(false /* server */, ka.version, cert.PrivateKey, config, sigAlg, serverRSAParams)
 	if err != nil {
 		return nil, errors.New("failed to sign RSA parameters: " + err.Error())
 	}
@@ -489,13 +489,13 @@
 	var sigAlg signatureAlgorithm
 	var err error
 	if ka.version >= VersionTLS12 {
-		sigAlg, err = selectSignatureAlgorithm(ka.version, cert, config, clientHello.signatureAlgorithms)
+		sigAlg, err = selectSignatureAlgorithm(false /* server */, ka.version, cert, config, clientHello.signatureAlgorithms)
 		if err != nil {
 			return nil, err
 		}
 	}
 
-	sig, err := signMessage(ka.version, cert.PrivateKey, config, sigAlg, msg)
+	sig, err := signMessage(false /* server */, ka.version, cert.PrivateKey, config, sigAlg, msg)
 	if err != nil {
 		return nil, err
 	}
@@ -571,7 +571,7 @@
 	}
 	sig = sig[2:]
 
-	return verifyMessage(ka.version, publicKey, config, sigAlg, msg, sig)
+	return verifyMessage(true /* client */, ka.version, publicKey, config, sigAlg, msg, sig)
 }
 
 // ecdheKeyAgreement implements a TLS key agreement where the server
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 2e1b407..3aab605 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -374,7 +374,7 @@
 	addUint24LengthPrefixedBytes(dc, pubBytes)
 
 	var dummyConfig Config
-	parentSignature, err := signMessage(VersionTLS13, parent.PrivateKey, &dummyConfig, config.algo, delegatedCredentialSignedMessage(dc.BytesOrPanic(), config.algo, parent.Leaf.Raw))
+	parentSignature, err := signMessage(false /* server */, VersionTLS13, parent.PrivateKey, &dummyConfig, config.algo, delegatedCredentialSignedMessage(dc.BytesOrPanic(), config.algo, parent.Leaf.Raw))
 	if err != nil {
 		panic(err)
 	}
@@ -1738,16 +1738,16 @@
 		case failed && !test.shouldFail:
 			msg = "unexpected failure"
 		case !failed && test.shouldFail:
-			msg = "unexpected success"
+			msg = fmt.Sprintf("unexpected success (wanted failure with %q / %q)", expectedError, test.expectedLocalError)
 		case failed && !correctFailure:
-			msg = "bad error (wanted '" + expectedError + "' / '" + test.expectedLocalError + "')"
+			msg = fmt.Sprintf("bad error (wanted %q / %q)", expectedError, test.expectedLocalError)
 		case mustFail:
 			msg = "test failure"
 		default:
 			panic("internal error")
 		}
 
-		return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s\n%s", msg, localErrString, childErrString, stdout, stderr, extraStderr)
+		return fmt.Errorf("%s: local error %q, child error %q, stdout:\n%s\nstderr:\n%s\n%s", msg, localErrString, childErrString, stdout, stderr, extraStderr)
 	}
 
 	if len(extraStderr) > 0 || (!failed && len(stderr) > 0) {
@@ -10016,6 +10016,7 @@
 }{
 	{"RSA_PKCS1_SHA1", signatureRSAPKCS1WithSHA1, &rsaCertificate, 0},
 	{"RSA_PKCS1_SHA256", signatureRSAPKCS1WithSHA256, &rsaCertificate, 0},
+	{"RSA_PKCS1_SHA256_LEGACY", signatureRSAPKCS1WithSHA256Legacy, &rsaCertificate, 0},
 	{"RSA_PKCS1_SHA384", signatureRSAPKCS1WithSHA384, &rsaCertificate, 0},
 	{"RSA_PKCS1_SHA512", signatureRSAPKCS1WithSHA512, &rsaCertificate, 0},
 	{"ECDSA_SHA1", signatureECDSAWithSHA1, &ecdsaP256Certificate, CurveP256},
@@ -10070,61 +10071,95 @@
 				continue
 			}
 
-			var shouldFail, rejectByDefault bool
-			// ecdsa_sha1 does not exist in TLS 1.3.
-			if ver.version >= VersionTLS13 && alg.id == signatureECDSAWithSHA1 {
-				shouldFail = true
-			}
-			// RSA-PKCS1 does not exist in TLS 1.3.
-			if ver.version >= VersionTLS13 && hasComponent(alg.name, "PKCS1") {
-				shouldFail = true
-			}
-			// SHA-224 has been removed from TLS 1.3 and, in 1.3,
-			// the curve has to match the hash size.
-			if ver.version >= VersionTLS13 && alg.curve == CurveP224 {
-				shouldFail = true
-			}
-
-			// By default, BoringSSL does not enable ecdsa_sha1, ecdsa_secp521_sha512, and ed25519.
-			if alg.id == signatureECDSAWithSHA1 || alg.id == signatureECDSAWithP521AndSHA512 || alg.id == signatureEd25519 {
-				rejectByDefault = true
-			}
-
-			var curveFlags []string
-			var runnerCurves []CurveID
-			if alg.curve != 0 && ver.version <= VersionTLS12 {
-				// In TLS 1.2, the ECDH curve list also constrains ECDSA keys. Ensure the
-				// corresponding curve is enabled. Also include X25519 to ensure the shim
-				// and runner have something in common for ECDH.
-				curveFlags = flagInts("-curves", []int{int(CurveX25519), int(alg.curve)})
-				runnerCurves = []CurveID{CurveX25519, alg.curve}
-			}
-
-			var signError, signLocalError, verifyError, verifyLocalError, defaultError, defaultLocalError string
-			if shouldFail {
-				signError = ":NO_COMMON_SIGNATURE_ALGORITHMS:"
-				signLocalError = "remote error: handshake failure"
-				verifyError = ":WRONG_SIGNATURE_TYPE:"
-				verifyLocalError = "remote error: illegal parameter"
-				rejectByDefault = true
-			}
-			if rejectByDefault {
-				defaultError = ":WRONG_SIGNATURE_TYPE:"
-				defaultLocalError = "remote error: illegal parameter"
-			}
-
 			suffix := "-" + alg.name + "-" + ver.name
+			for _, signTestType := range []testType{clientTest, serverTest} {
+				signPrefix := "Client-"
+				verifyPrefix := "Server-"
+				verifyTestType := serverTest
+				if signTestType == serverTest {
+					verifyTestType = clientTest
+					signPrefix, verifyPrefix = verifyPrefix, signPrefix
+				}
 
-			for _, testType := range []testType{clientTest, serverTest} {
-				prefix := "Client-"
-				if testType == serverTest {
-					prefix = "Server-"
+				var shouldFail bool
+				isTLS12PKCS1 := hasComponent(alg.name, "PKCS1") && !hasComponent(alg.name, "LEGACY")
+				isTLS13PKCS1 := hasComponent(alg.name, "PKCS1") && hasComponent(alg.name, "LEGACY")
+
+				// TLS 1.3 removes a number of signature algorithms.
+				if ver.version >= VersionTLS13 && (alg.curve == CurveP224 || alg.id == signatureECDSAWithSHA1 || isTLS12PKCS1) {
+					shouldFail = true
+				}
+
+				// The backported RSA-PKCS1 code points only exist for TLS 1.3
+				// client certificates.
+				if (ver.version < VersionTLS13 || signTestType == serverTest) && isTLS13PKCS1 {
+					shouldFail = true
+				}
+
+				// By default, BoringSSL does not sign with these algorithms.
+				signDefault := !shouldFail
+				if isTLS13PKCS1 {
+					signDefault = false
+				}
+
+				// By default, BoringSSL does not accept these algorithms.
+				verifyDefault := !shouldFail
+				if alg.id == signatureECDSAWithSHA1 || alg.id == signatureECDSAWithP521AndSHA512 || alg.id == signatureEd25519 || isTLS13PKCS1 {
+					verifyDefault = false
+				}
+
+				var curveFlags []string
+				var runnerCurves []CurveID
+				if alg.curve != 0 && ver.version <= VersionTLS12 {
+					// In TLS 1.2, the ECDH curve list also constrains ECDSA keys. Ensure the
+					// corresponding curve is enabled. Also include X25519 to ensure the shim
+					// and runner have something in common for ECDH.
+					curveFlags = flagInts("-curves", []int{int(CurveX25519), int(alg.curve)})
+					runnerCurves = []CurveID{CurveX25519, alg.curve}
+				}
+
+				signError := func(shouldFail bool) string {
+					if !shouldFail {
+						return ""
+					}
+					// In TLS 1.3, the shim should report no common signature algorithms if
+					// it cannot generate a signature. In TLS 1.2 servers, signature
+					// algorithm and cipher selection are integrated, so it is reported as
+					// no shared cipher.
+					if ver.version <= VersionTLS12 && signTestType == serverTest {
+						return ":NO_SHARED_CIPHER:"
+					}
+					return ":NO_COMMON_SIGNATURE_ALGORITHMS:"
+				}
+				signLocalError := func(shouldFail bool) string {
+					if !shouldFail {
+						return ""
+					}
+					// The shim should send handshake_failure when it cannot
+					// negotiate parameters.
+					return "remote error: handshake failure"
+				}
+				verifyError := func(shouldFail bool) string {
+					if !shouldFail {
+						return ""
+					}
+					// If the shim rejects the signature algorithm, but the
+					// runner forcibly selects it anyway, the shim should notice.
+					return ":WRONG_SIGNATURE_TYPE:"
+				}
+				verifyLocalError := func(shouldFail bool) string {
+					if !shouldFail {
+						return ""
+					}
+					// The shim should send an illegal_parameter alert if the runner
+					// uses a signature algorithm it isn't allowed to use.
+					return "remote error: illegal parameter"
 				}
 
 				// Test the shim using the algorithm for signing.
 				signTest := testCase{
-					testType: testType,
-					name:     prefix + "Sign" + suffix,
+					testType: signTestType,
+					name:     signPrefix + "Sign" + suffix,
 					config: Config{
 						MaxVersion:       ver.version,
 						CurvePreferences: runnerCurves,
@@ -10137,8 +10172,33 @@
 					shimCertificate:    cert,
 					flags:              curveFlags,
 					shouldFail:         shouldFail,
-					expectedError:      signError,
-					expectedLocalError: signLocalError,
+					expectedError:      signError(shouldFail),
+					expectedLocalError: signLocalError(shouldFail),
+					expectations: connectionExpectations{
+						peerSignatureAlgorithm: alg.id,
+					},
+				}
+
+				// Test whether the shim enables the algorithm by default.
+				signDefaultTest := testCase{
+					testType: signTestType,
+					name:     signPrefix + "SignDefault" + suffix,
+					config: Config{
+						MaxVersion:       ver.version,
+						CurvePreferences: runnerCurves,
+						VerifySignatureAlgorithms: []signatureAlgorithm{
+							fakeSigAlg1,
+							alg.id,
+							fakeSigAlg2,
+						},
+					},
+					// cert has been configured with the specified algorithm,
+					// while alg.baseCert uses the defaults.
+					shimCertificate:    alg.baseCert,
+					flags:              curveFlags,
+					shouldFail:         !signDefault,
+					expectedError:      signError(!signDefault),
+					expectedLocalError: signLocalError(!signDefault),
 					expectations: connectionExpectations{
 						peerSignatureAlgorithm: alg.id,
 					},
@@ -10147,8 +10207,8 @@
 				// Test that the shim will select the algorithm when configured to only
 				// support it.
 				negotiateTest := testCase{
-					testType: testType,
-					name:     prefix + "Sign-Negotiate" + suffix,
+					testType: signTestType,
+					name:     signPrefix + "Sign-Negotiate" + suffix,
 					config: Config{
 						MaxVersion:                ver.version,
 						CurvePreferences:          runnerCurves,
@@ -10161,24 +10221,26 @@
 					},
 				}
 
-				if testType == serverTest {
+				if signTestType == serverTest {
 					// TLS 1.2 servers only sign on some cipher suites.
 					signTest.config.CipherSuites = signingCiphers
+					signDefaultTest.config.CipherSuites = signingCiphers
 					negotiateTest.config.CipherSuites = signingCiphers
 				} else {
 					// TLS 1.2 clients only sign when the server requests certificates.
 					signTest.config.ClientAuth = RequireAnyClientCert
+					signDefaultTest.config.ClientAuth = RequireAnyClientCert
 					negotiateTest.config.ClientAuth = RequireAnyClientCert
 				}
-				testCases = append(testCases, signTest)
+				testCases = append(testCases, signTest, signDefaultTest)
 				if ver.version >= VersionTLS12 && !shouldFail {
 					testCases = append(testCases, negotiateTest)
 				}
 
 				// Test the shim using the algorithm for verifying.
 				verifyTest := testCase{
-					testType: testType,
-					name:     prefix + "Verify" + suffix,
+					testType: verifyTestType,
+					name:     verifyPrefix + "Verify" + suffix,
 					config: Config{
 						MaxVersion: ver.version,
 						Credential: cert,
@@ -10194,8 +10256,8 @@
 					// algorithm is reported on both handshakes.
 					resumeSession:      !shouldFail,
 					shouldFail:         shouldFail,
-					expectedError:      verifyError,
-					expectedLocalError: verifyLocalError,
+					expectedError:      verifyError(shouldFail),
+					expectedLocalError: verifyLocalError(shouldFail),
 				}
 				if alg.id != 0 {
 					verifyTest.flags = append(verifyTest.flags, "-expect-peer-signature-algorithm", strconv.Itoa(int(alg.id)))
@@ -10205,16 +10267,16 @@
 
 				// Test whether the shim expects the algorithm enabled by default.
 				defaultTest := testCase{
-					testType: testType,
-					name:     prefix + "VerifyDefault" + suffix,
+					testType: verifyTestType,
+					name:     verifyPrefix + "VerifyDefault" + suffix,
 					config: Config{
 						MaxVersion: ver.version,
 						Credential: cert,
 						Bugs: ProtocolBugs{
-							SkipECDSACurveCheck:          rejectByDefault,
-							IgnoreSignatureVersionChecks: rejectByDefault,
+							SkipECDSACurveCheck:          !verifyDefault,
+							IgnoreSignatureVersionChecks: !verifyDefault,
 							// Some signature algorithms may not be advertised.
-							IgnorePeerSignatureAlgorithmPreferences: rejectByDefault,
+							IgnorePeerSignatureAlgorithmPreferences: !verifyDefault,
 						},
 					},
 					flags: append(
@@ -10223,16 +10285,16 @@
 					),
 					// Resume the session to assert the peer signature
 					// algorithm is reported on both handshakes.
-					resumeSession:      !rejectByDefault,
-					shouldFail:         rejectByDefault,
-					expectedError:      defaultError,
-					expectedLocalError: defaultLocalError,
+					resumeSession:      verifyDefault,
+					shouldFail:         !verifyDefault,
+					expectedError:      verifyError(!verifyDefault),
+					expectedLocalError: verifyLocalError(!verifyDefault),
 				}
 
 				// Test whether the shim handles invalid signatures for this algorithm.
 				invalidTest := testCase{
-					testType: testType,
-					name:     prefix + "InvalidSignature" + suffix,
+					testType: verifyTestType,
+					name:     verifyPrefix + "InvalidSignature" + suffix,
 					config: Config{
 						MaxVersion: ver.version,
 						Credential: cert,
@@ -10249,7 +10311,7 @@
 					invalidTest.flags = append(invalidTest.flags, "-verify-prefs", strconv.Itoa(int(alg.id)))
 				}
 
-				if testType == serverTest {
+				if verifyTestType == serverTest {
 					// TLS 1.2 servers only verify when they request client certificates.
 					verifyTest.flags = append(verifyTest.flags, "-require-any-client-certificate")
 					defaultTest.flags = append(defaultTest.flags, "-require-any-client-certificate")
diff --git a/ssl/test/runner/sign.go b/ssl/test/runner/sign.go
index a57b2e7..65568a3 100644
--- a/ssl/test/runner/sign.go
+++ b/ssl/test/runner/sign.go
@@ -27,7 +27,7 @@
 	verifyMessage(key crypto.PublicKey, msg, sig []byte) error
 }
 
-func selectSignatureAlgorithm(version uint16, cred *Credential, config *Config, peerSigAlgs []signatureAlgorithm) (signatureAlgorithm, error) {
+func selectSignatureAlgorithm(isClient bool, version uint16, cred *Credential, config *Config, peerSigAlgs []signatureAlgorithm) (signatureAlgorithm, error) {
 	// If the client didn't specify any signature_algorithms extension then
 	// we can assume that it supports SHA1. See
 	// http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
@@ -40,7 +40,7 @@
 			continue
 		}
 
-		signer, err := getSigner(version, cred.PrivateKey, config, sigAlg, false)
+		signer, err := getSigner(isClient, version, cred.PrivateKey, config, sigAlg, false)
 		if err != nil {
 			continue
 		}
@@ -52,7 +52,7 @@
 	return 0, errors.New("tls: no common signature algorithms")
 }
 
-func signMessage(version uint16, key crypto.PrivateKey, config *Config, sigAlg signatureAlgorithm, msg []byte) ([]byte, error) {
+func signMessage(isClient bool, version uint16, key crypto.PrivateKey, config *Config, sigAlg signatureAlgorithm, msg []byte) ([]byte, error) {
 	if config.Bugs.InvalidSignature {
 		newMsg := make([]byte, len(msg))
 		copy(newMsg, msg)
@@ -60,7 +60,7 @@
 		msg = newMsg
 	}
 
-	signer, err := getSigner(version, key, config, sigAlg, false)
+	signer, err := getSigner(isClient, version, key, config, sigAlg, false)
 	if err != nil {
 		return nil, err
 	}
@@ -68,12 +68,12 @@
 	return signer.signMessage(key, config, msg)
 }
 
-func verifyMessage(version uint16, key crypto.PublicKey, config *Config, sigAlg signatureAlgorithm, msg, sig []byte) error {
+func verifyMessage(isClient bool, version uint16, key crypto.PublicKey, config *Config, sigAlg signatureAlgorithm, msg, sig []byte) error {
 	if version >= VersionTLS12 && !slices.Contains(config.verifySignatureAlgorithms(), sigAlg) {
 		return errors.New("tls: unsupported signature algorithm")
 	}
 
-	signer, err := getSigner(version, key, config, sigAlg, true)
+	signer, err := getSigner(isClient, version, key, config, sigAlg, true)
 	if err != nil {
 		return err
 	}
@@ -81,12 +81,12 @@
 	return signer.verifyMessage(key, msg, sig)
 }
 
-func verifyMessageDC(version uint16, key crypto.PublicKey, config *Config, sigAlg signatureAlgorithm, msg, sig []byte) error {
+func verifyMessageDC(isClient bool, version uint16, key crypto.PublicKey, config *Config, sigAlg signatureAlgorithm, msg, sig []byte) error {
 	if version >= VersionTLS12 && !slices.Contains(config.DelegatedCredentialAlgorithms, sigAlg) {
 		return errors.New("tls: unsupported signature algorithm")
 	}
 
-	signer, err := getSigner(version, key, config, sigAlg, true)
+	signer, err := getSigner(isClient, version, key, config, sigAlg, true)
 	if err != nil {
 		return err
 	}
@@ -286,7 +286,7 @@
 	return nil
 }
 
-func getSigner(version uint16, key any, config *Config, sigAlg signatureAlgorithm, isVerify bool) (signer, error) {
+func getSigner(isClient bool, version uint16, key any, config *Config, sigAlg signatureAlgorithm, isVerify bool) (signer, error) {
 	// TLS 1.1 and below use legacy signature algorithms.
 	if version < VersionTLS12 || (!isVerify && config.Bugs.AlwaysSignAsLegacyVersion) {
 		if config.Bugs.SigningAlgorithmForLegacyVersions == 0 || isVerify {
@@ -304,6 +304,7 @@
 		sigAlg = config.Bugs.SigningAlgorithmForLegacyVersions
 	}
 
+	isClientSign := isClient != isVerify
 	switch sigAlg {
 	case signatureRSAPKCS1WithMD5:
 		if version < VersionTLS13 || config.Bugs.IgnoreSignatureVersionChecks {
@@ -325,6 +326,10 @@
 		if version < VersionTLS13 || config.Bugs.IgnoreSignatureVersionChecks {
 			return &rsaPKCS1Signer{crypto.SHA512}, nil
 		}
+	case signatureRSAPKCS1WithSHA256Legacy:
+		if (isClientSign && version >= VersionTLS13) || config.Bugs.IgnoreSignatureVersionChecks {
+			return &rsaPKCS1Signer{crypto.SHA256}, nil
+		}
 	case signatureECDSAWithSHA1:
 		return &ecdsaSigner{version, config, nil, crypto.SHA1}, nil
 	case signatureECDSAWithP256AndSHA256: