diff options
-rw-r--r-- | src/include/openssl/ssl.h | 5 | ||||
-rw-r--r-- | src/ssl/extensions.cc | 5 | ||||
-rw-r--r-- | src/ssl/internal.h | 2 | ||||
-rw-r--r-- | src/ssl/ssl_privkey.cc | 79 | ||||
-rw-r--r-- | src/ssl/test/runner/common.go | 3 | ||||
-rw-r--r-- | src/ssl/test/runner/handshake_client.go | 14 | ||||
-rw-r--r-- | src/ssl/test/runner/handshake_server.go | 8 | ||||
-rw-r--r-- | src/ssl/test/runner/key_agreement.go | 10 | ||||
-rw-r--r-- | src/ssl/test/runner/runner.go | 206 | ||||
-rw-r--r-- | src/ssl/test/runner/sign.go | 23 |
10 files changed, 235 insertions, 120 deletions
diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h index 63b66b4..9d7abe8 100644 --- a/src/include/openssl/ssl.h +++ b/src/include/openssl/ssl.h @@ -1205,6 +1205,11 @@ OPENSSL_EXPORT int SSL_set_ocsp_response(SSL *ssl, #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/src/ssl/extensions.cc b/src/ssl/extensions.cc index 586edbd..3f35276 100644 --- a/src/ssl/extensions.cc +++ b/src/ssl/extensions.cc @@ -446,7 +446,7 @@ bool tls12_check_peer_sigalg(const SSL_HANDSHAKE *hs, uint8_t *out_alert, // 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 @@ bool tls1_choose_signature_algorithm(SSL_HANDSHAKE *hs, ? 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/src/ssl/internal.h b/src/ssl/internal.h index 7145d13..2e44641 100644 --- a/src/ssl/internal.h +++ b/src/ssl/internal.h @@ -1094,7 +1094,7 @@ enum ssl_private_key_result_t ssl_private_key_decrypt(SSL_HANDSHAKE *hs, // 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/src/ssl/ssl_privkey.cc b/src/ssl/ssl_privkey.cc index 9cf2c8f..471be76 100644 --- a/src/ssl/ssl_privkey.cc +++ b/src/ssl/ssl_privkey.cc @@ -85,29 +85,61 @@ typedef struct { 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}, - - {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}, - - {SSL_SIGN_ECDSA_SHA1, EVP_PKEY_EC, NID_undef, &EVP_sha1, 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}, + + // 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_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 @@ static const SSL_SIGNATURE_ALGORITHM *get_signature_algorithm(uint16_t sigalg) { } 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 @@ bool ssl_pkey_supports_algorithm(const SSL *ssl, EVP_PKEY *pkey, } 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 @@ bool ssl_pkey_supports_algorithm(const SSL *ssl, EVP_PKEY *pkey, 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 @@ bool ssl_pkey_supports_algorithm(const SSL *ssl, EVP_PKEY *pkey, 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 @@ void SSL_CTX_set_private_key_method(SSL_CTX *ctx, 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 @@ static const SignatureAlgorithmName kSignatureAlgorithmNames[] = { {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/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go index 1681c2b..3a8caa1 100644 --- a/src/ssl/test/runner/common.go +++ b/src/ssl/test/runner/common.go @@ -215,6 +215,9 @@ const ( 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/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go index 7172b3d..a0a81f9 100644 --- a/src/ssl/test/runner/handshake_client.go +++ b/src/ssl/test/runner/handshake_client.go @@ -1300,9 +1300,9 @@ func (hs *clientHandshakeState) doTLS13Handshake(msg any) error { 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 @@ func (hs *clientHandshakeState) doTLS13Handshake(msg any) error { // 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 @@ func (hs *clientHandshakeState) doTLS13Handshake(msg any) error { 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 @@ func (hs *clientHandshakeState) doFullHandshake() error { // 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 @@ func (hs *clientHandshakeState) doFullHandshake() error { } 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 @@ func (hs *clientHandshakeState) verifyCertificates(certMsg *certificateMsg) erro } 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/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go index 7459b5b..2e87d54 100644 --- a/src/ssl/test/runner/handshake_server.go +++ b/src/ssl/test/runner/handshake_server.go @@ -1169,7 +1169,7 @@ ResendHelloRetryRequest: // 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 @@ ResendHelloRetryRequest: 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 @@ ResendHelloRetryRequest: 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 @@ func (hs *serverHandshakeState) doFullHandshake() error { 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/src/ssl/test/runner/key_agreement.go b/src/ssl/test/runner/key_agreement.go index 39377f8..aff0820 100644 --- a/src/ssl/test/runner/key_agreement.go +++ b/src/ssl/test/runner/key_agreement.go @@ -65,13 +65,13 @@ func (ka *rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Crede 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 @@ func (ka *signedKeyAgreement) signParameters(config *Config, cert *Credential, c 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 @@ func (ka *signedKeyAgreement) verifyParameters(config *Config, clientHello *clie } 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/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go index 2e1b407..3aab605 100644 --- a/src/ssl/test/runner/runner.go +++ b/src/ssl/test/runner/runner.go @@ -374,7 +374,7 @@ func createDelegatedCredential(parent *Credential, config delegatedCredentialCon 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 @@ func runTest(dispatcher *shimDispatcher, statusChan chan statusMsg, test *testCa 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 @@ var testSignatureAlgorithms = []struct { }{ {"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 @@ func addSignatureAlgorithmTests() { 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 - } + 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 + } - // 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 shouldFail bool + isTLS12PKCS1 := hasComponent(alg.name, "PKCS1") && !hasComponent(alg.name, "LEGACY") + isTLS13PKCS1 := hasComponent(alg.name, "PKCS1") && hasComponent(alg.name, "LEGACY") - 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} - } + // TLS 1.3 removes a number of signature algorithms. + if ver.version >= VersionTLS13 && (alg.curve == CurveP224 || alg.id == signatureECDSAWithSHA1 || isTLS12PKCS1) { + shouldFail = true + } - 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" - } + // The backported RSA-PKCS1 code points only exist for TLS 1.3 + // client certificates. + if (ver.version < VersionTLS13 || signTestType == serverTest) && isTLS13PKCS1 { + shouldFail = true + } - suffix := "-" + alg.name + "-" + ver.name + // By default, BoringSSL does not sign with these algorithms. + signDefault := !shouldFail + if isTLS13PKCS1 { + signDefault = false + } - for _, testType := range []testType{clientTest, serverTest} { - prefix := "Client-" - if testType == serverTest { - prefix = "Server-" + // 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 @@ func addSignatureAlgorithmTests() { 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 @@ func addSignatureAlgorithmTests() { // 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 @@ func addSignatureAlgorithmTests() { }, } - 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 @@ func addSignatureAlgorithmTests() { // 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 @@ func addSignatureAlgorithmTests() { // 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 @@ func addSignatureAlgorithmTests() { ), // 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 @@ func addSignatureAlgorithmTests() { 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/src/ssl/test/runner/sign.go b/src/ssl/test/runner/sign.go index a57b2e7..65568a3 100644 --- a/src/ssl/test/runner/sign.go +++ b/src/ssl/test/runner/sign.go @@ -27,7 +27,7 @@ type signer interface { 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 @@ func selectSignatureAlgorithm(version uint16, cred *Credential, config *Config, 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 @@ func selectSignatureAlgorithm(version uint16, cred *Credential, config *Config, 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 @@ func signMessage(version uint16, key crypto.PrivateKey, config *Config, sigAlg s 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 @@ func signMessage(version uint16, key crypto.PrivateKey, config *Config, sigAlg s 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 @@ func verifyMessage(version uint16, key crypto.PublicKey, config *Config, sigAlg 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 @@ func (e *ed25519Signer) verifyMessage(key crypto.PublicKey, msg, sig []byte) err 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 @@ func getSigner(version uint16, key any, config *Config, sigAlg signatureAlgorith sigAlg = config.Bugs.SigningAlgorithmForLegacyVersions } + isClientSign := isClient != isVerify switch sigAlg { case signatureRSAPKCS1WithMD5: if version < VersionTLS13 || config.Bugs.IgnoreSignatureVersionChecks { @@ -325,6 +326,10 @@ func getSigner(version uint16, key any, config *Config, sigAlg signatureAlgorith 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: |