// Copyright 2025 The BoringSSL Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package runner import ( "fmt" "strconv" ) var testSignatureAlgorithms = []struct { name string id signatureAlgorithm baseCert *Credential // If non-zero, the curve that must be supported in TLS 1.2 for cert to be // accepted. curve CurveID }{ {"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}, {"ECDSA_P256_SHA256", signatureECDSAWithP256AndSHA256, &ecdsaP256Certificate, CurveP256}, {"ECDSA_P384_SHA384", signatureECDSAWithP384AndSHA384, &ecdsaP384Certificate, CurveP384}, {"ECDSA_P521_SHA512", signatureECDSAWithP521AndSHA512, &ecdsaP521Certificate, CurveP521}, {"RSA_PSS_SHA256", signatureRSAPSSWithSHA256, &rsaCertificate, 0}, {"RSA_PSS_SHA384", signatureRSAPSSWithSHA384, &rsaCertificate, 0}, {"RSA_PSS_SHA512", signatureRSAPSSWithSHA512, &rsaCertificate, 0}, {"Ed25519", signatureEd25519, &ed25519Certificate, 0}, // Tests for key types prior to TLS 1.2. {"RSA", 0, &rsaCertificate, 0}, {"ECDSA", 0, &ecdsaP256Certificate, CurveP256}, } const ( fakeSigAlg1 signatureAlgorithm = 0x2a01 fakeSigAlg2 signatureAlgorithm = 0xff01 ) func addSignatureAlgorithmTests() { // Not all ciphers involve a signature. Advertise a list which gives all // versions a signing cipher. signingCiphers := []uint16{ TLS_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, } var allAlgorithms []signatureAlgorithm for _, alg := range testSignatureAlgorithms { if alg.id != 0 { allAlgorithms = append(allAlgorithms, alg.id) } } // Make sure each signature algorithm works. Include some fake values in // the list and ensure they're ignored. for _, alg := range testSignatureAlgorithms { // Make a version of the certificate that will not sign any other algorithm. cert := alg.baseCert if alg.id != 0 { cert = cert.WithSignatureAlgorithms(alg.id) } for _, ver := range tlsVersions { if (ver.version < VersionTLS12) != (alg.id == 0) { continue } 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 } 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.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: signTestType, name: signPrefix + "Sign" + suffix, config: Config{ MaxVersion: ver.version, CurvePreferences: runnerCurves, VerifySignatureAlgorithms: []signatureAlgorithm{ fakeSigAlg1, alg.id, fakeSigAlg2, }, }, shimCertificate: cert, flags: curveFlags, shouldFail: shouldFail, 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, }, } // Test that the shim will select the algorithm when configured to only // support it. negotiateTest := testCase{ testType: signTestType, name: signPrefix + "Sign-Negotiate" + suffix, config: Config{ MaxVersion: ver.version, CurvePreferences: runnerCurves, VerifySignatureAlgorithms: allAlgorithms, }, shimCertificate: cert, flags: curveFlags, expectations: connectionExpectations{ peerSignatureAlgorithm: alg.id, }, } 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, signDefaultTest) if ver.version >= VersionTLS12 && !shouldFail { testCases = append(testCases, negotiateTest) } // Test the shim using the algorithm for verifying. verifyTest := testCase{ testType: verifyTestType, name: verifyPrefix + "Verify" + suffix, config: Config{ MaxVersion: ver.version, Credential: cert, Bugs: ProtocolBugs{ SkipECDSACurveCheck: shouldFail, IgnoreSignatureVersionChecks: shouldFail, // Some signature algorithms may not be advertised. IgnorePeerSignatureAlgorithmPreferences: shouldFail, }, }, flags: curveFlags, // Resume the session to assert the peer signature // algorithm is reported on both handshakes. resumeSession: !shouldFail, shouldFail: shouldFail, expectedError: verifyError(shouldFail), expectedLocalError: verifyLocalError(shouldFail), } if alg.id != 0 { verifyTest.flags = append(verifyTest.flags, "-expect-peer-signature-algorithm", strconv.Itoa(int(alg.id))) // The algorithm may be disabled by default, so explicitly enable it. verifyTest.flags = append(verifyTest.flags, "-verify-prefs", strconv.Itoa(int(alg.id))) } // Test whether the shim expects the algorithm enabled by default. defaultTest := testCase{ testType: verifyTestType, name: verifyPrefix + "VerifyDefault" + suffix, config: Config{ MaxVersion: ver.version, Credential: cert, Bugs: ProtocolBugs{ SkipECDSACurveCheck: !verifyDefault, IgnoreSignatureVersionChecks: !verifyDefault, // Some signature algorithms may not be advertised. IgnorePeerSignatureAlgorithmPreferences: !verifyDefault, }, }, flags: append( []string{"-expect-peer-signature-algorithm", strconv.Itoa(int(alg.id))}, curveFlags..., ), // Resume the session to assert the peer signature // algorithm is reported on both handshakes. resumeSession: verifyDefault, shouldFail: !verifyDefault, expectedError: verifyError(!verifyDefault), expectedLocalError: verifyLocalError(!verifyDefault), } // Test whether the shim handles invalid signatures for this algorithm. invalidTest := testCase{ testType: verifyTestType, name: verifyPrefix + "InvalidSignature" + suffix, config: Config{ MaxVersion: ver.version, Credential: cert, Bugs: ProtocolBugs{ InvalidSignature: true, }, }, flags: curveFlags, shouldFail: true, expectedError: ":BAD_SIGNATURE:", } if alg.id != 0 { // The algorithm may be disabled by default, so explicitly enable it. invalidTest.flags = append(invalidTest.flags, "-verify-prefs", strconv.Itoa(int(alg.id))) } 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") invalidTest.flags = append(invalidTest.flags, "-require-any-client-certificate") } else { // TLS 1.2 clients only verify on some cipher suites. verifyTest.config.CipherSuites = signingCiphers defaultTest.config.CipherSuites = signingCiphers invalidTest.config.CipherSuites = signingCiphers } testCases = append(testCases, verifyTest, defaultTest) if !shouldFail { testCases = append(testCases, invalidTest) } } } } // Test the peer's verify preferences are available. for _, ver := range tlsVersions { if ver.version < VersionTLS12 { continue } testCases = append(testCases, testCase{ name: "ClientAuth-PeerVerifyPrefs-" + ver.name, config: Config{ MaxVersion: ver.version, ClientAuth: RequireAnyClientCert, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPSSWithSHA256, signatureEd25519, signatureECDSAWithP256AndSHA256, }, }, shimCertificate: &rsaCertificate, flags: []string{ "-expect-peer-verify-pref", strconv.Itoa(int(signatureRSAPSSWithSHA256)), "-expect-peer-verify-pref", strconv.Itoa(int(signatureEd25519)), "-expect-peer-verify-pref", strconv.Itoa(int(signatureECDSAWithP256AndSHA256)), }, }) testCases = append(testCases, testCase{ testType: serverTest, name: "ServerAuth-PeerVerifyPrefs-" + ver.name, config: Config{ MaxVersion: ver.version, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPSSWithSHA256, signatureEd25519, signatureECDSAWithP256AndSHA256, }, }, shimCertificate: &rsaCertificate, flags: []string{ "-expect-peer-verify-pref", strconv.Itoa(int(signatureRSAPSSWithSHA256)), "-expect-peer-verify-pref", strconv.Itoa(int(signatureEd25519)), "-expect-peer-verify-pref", strconv.Itoa(int(signatureECDSAWithP256AndSHA256)), }, }) } // Test that algorithm selection takes the key type into account. testCases = append(testCases, testCase{ name: "ClientAuth-SignatureType", config: Config{ ClientAuth: RequireAnyClientCert, MaxVersion: VersionTLS12, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureECDSAWithP521AndSHA512, signatureRSAPKCS1WithSHA384, signatureECDSAWithSHA1, }, }, shimCertificate: &rsaCertificate, expectations: connectionExpectations{ peerSignatureAlgorithm: signatureRSAPKCS1WithSHA384, }, }) testCases = append(testCases, testCase{ name: "ClientAuth-SignatureType-TLS13", config: Config{ ClientAuth: RequireAnyClientCert, MaxVersion: VersionTLS13, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureECDSAWithP521AndSHA512, signatureRSAPKCS1WithSHA384, signatureRSAPSSWithSHA384, signatureECDSAWithSHA1, }, }, shimCertificate: &rsaCertificate, expectations: connectionExpectations{ peerSignatureAlgorithm: signatureRSAPSSWithSHA384, }, }) testCases = append(testCases, testCase{ testType: serverTest, name: "ServerAuth-SignatureType", config: Config{ MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureECDSAWithP521AndSHA512, signatureRSAPKCS1WithSHA384, signatureECDSAWithSHA1, }, }, expectations: connectionExpectations{ peerSignatureAlgorithm: signatureRSAPKCS1WithSHA384, }, }) testCases = append(testCases, testCase{ testType: serverTest, name: "ServerAuth-SignatureType-TLS13", config: Config{ MaxVersion: VersionTLS13, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureECDSAWithP521AndSHA512, signatureRSAPKCS1WithSHA384, signatureRSAPSSWithSHA384, signatureECDSAWithSHA1, }, }, expectations: connectionExpectations{ peerSignatureAlgorithm: signatureRSAPSSWithSHA384, }, }) // Test that signature verification takes the key type into account. testCases = append(testCases, testCase{ testType: serverTest, name: "Verify-ClientAuth-SignatureType", config: Config{ MaxVersion: VersionTLS12, Credential: rsaCertificate.WithSignatureAlgorithms(signatureRSAPKCS1WithSHA256), Bugs: ProtocolBugs{ SendSignatureAlgorithm: signatureECDSAWithP256AndSHA256, }, }, flags: []string{ "-require-any-client-certificate", }, shouldFail: true, expectedError: ":WRONG_SIGNATURE_TYPE:", }) testCases = append(testCases, testCase{ testType: serverTest, name: "Verify-ClientAuth-SignatureType-TLS13", config: Config{ MaxVersion: VersionTLS13, Credential: rsaCertificate.WithSignatureAlgorithms(signatureRSAPSSWithSHA256), Bugs: ProtocolBugs{ SendSignatureAlgorithm: signatureECDSAWithP256AndSHA256, }, }, flags: []string{ "-require-any-client-certificate", }, shouldFail: true, expectedError: ":WRONG_SIGNATURE_TYPE:", }) testCases = append(testCases, testCase{ name: "Verify-ServerAuth-SignatureType", config: Config{ MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, Credential: rsaCertificate.WithSignatureAlgorithms(signatureRSAPKCS1WithSHA256), Bugs: ProtocolBugs{ SendSignatureAlgorithm: signatureECDSAWithP256AndSHA256, }, }, shouldFail: true, expectedError: ":WRONG_SIGNATURE_TYPE:", }) testCases = append(testCases, testCase{ name: "Verify-ServerAuth-SignatureType-TLS13", config: Config{ MaxVersion: VersionTLS13, Credential: rsaCertificate.WithSignatureAlgorithms(signatureRSAPSSWithSHA256), Bugs: ProtocolBugs{ SendSignatureAlgorithm: signatureECDSAWithP256AndSHA256, }, }, shouldFail: true, expectedError: ":WRONG_SIGNATURE_TYPE:", }) // Test that, if the ClientHello list is missing, the server falls back // to SHA-1 in TLS 1.2, but not TLS 1.3. testCases = append(testCases, testCase{ testType: serverTest, name: "ServerAuth-SHA1-Fallback-RSA", config: Config{ MaxVersion: VersionTLS12, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithSHA1, }, Bugs: ProtocolBugs{ NoSignatureAlgorithms: true, }, }, shimCertificate: &rsaCertificate, }) testCases = append(testCases, testCase{ testType: serverTest, name: "ServerAuth-SHA1-Fallback-ECDSA", config: Config{ MaxVersion: VersionTLS12, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureECDSAWithSHA1, }, Bugs: ProtocolBugs{ NoSignatureAlgorithms: true, }, }, shimCertificate: &ecdsaP256Certificate, }) testCases = append(testCases, testCase{ testType: serverTest, name: "ServerAuth-NoFallback-TLS13", config: Config{ MaxVersion: VersionTLS13, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithSHA1, }, Bugs: ProtocolBugs{ NoSignatureAlgorithms: true, }, }, shouldFail: true, expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:", }) // The CertificateRequest list, however, may never be omitted. It is a // syntax error for it to be empty. testCases = append(testCases, testCase{ name: "ClientAuth-NoFallback-RSA", config: Config{ MaxVersion: VersionTLS12, ClientAuth: RequireAnyClientCert, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithSHA1, }, Bugs: ProtocolBugs{ NoSignatureAlgorithms: true, }, }, shimCertificate: &rsaCertificate, shouldFail: true, expectedError: ":DECODE_ERROR:", expectedLocalError: "remote error: error decoding message", }) testCases = append(testCases, testCase{ name: "ClientAuth-NoFallback-ECDSA", config: Config{ MaxVersion: VersionTLS12, ClientAuth: RequireAnyClientCert, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureECDSAWithSHA1, }, Bugs: ProtocolBugs{ NoSignatureAlgorithms: true, }, }, shimCertificate: &ecdsaP256Certificate, shouldFail: true, expectedError: ":DECODE_ERROR:", expectedLocalError: "remote error: error decoding message", }) testCases = append(testCases, testCase{ name: "ClientAuth-NoFallback-TLS13", config: Config{ MaxVersion: VersionTLS13, ClientAuth: RequireAnyClientCert, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithSHA1, }, Bugs: ProtocolBugs{ NoSignatureAlgorithms: true, }, }, shimCertificate: &rsaCertificate, shouldFail: true, expectedError: ":DECODE_ERROR:", expectedLocalError: "remote error: error decoding message", }) // Test that signature preferences are enforced. BoringSSL does not // implement MD5 signatures. testCases = append(testCases, testCase{ testType: serverTest, name: "ClientAuth-Enforced", config: Config{ MaxVersion: VersionTLS12, Credential: rsaCertificate.WithSignatureAlgorithms(signatureRSAPKCS1WithMD5), Bugs: ProtocolBugs{ IgnorePeerSignatureAlgorithmPreferences: true, }, }, flags: []string{"-require-any-client-certificate"}, shouldFail: true, expectedError: ":WRONG_SIGNATURE_TYPE:", }) testCases = append(testCases, testCase{ name: "ServerAuth-Enforced", config: Config{ MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, Credential: rsaCertificate.WithSignatureAlgorithms(signatureRSAPKCS1WithMD5), Bugs: ProtocolBugs{ IgnorePeerSignatureAlgorithmPreferences: true, }, }, shouldFail: true, expectedError: ":WRONG_SIGNATURE_TYPE:", }) testCases = append(testCases, testCase{ testType: serverTest, name: "ClientAuth-Enforced-TLS13", config: Config{ MaxVersion: VersionTLS13, Credential: rsaCertificate.WithSignatureAlgorithms(signatureRSAPKCS1WithMD5), Bugs: ProtocolBugs{ IgnorePeerSignatureAlgorithmPreferences: true, IgnoreSignatureVersionChecks: true, }, }, flags: []string{"-require-any-client-certificate"}, shouldFail: true, expectedError: ":WRONG_SIGNATURE_TYPE:", }) testCases = append(testCases, testCase{ name: "ServerAuth-Enforced-TLS13", config: Config{ MaxVersion: VersionTLS13, Credential: rsaCertificate.WithSignatureAlgorithms(signatureRSAPKCS1WithMD5), Bugs: ProtocolBugs{ IgnorePeerSignatureAlgorithmPreferences: true, IgnoreSignatureVersionChecks: true, }, }, shouldFail: true, expectedError: ":WRONG_SIGNATURE_TYPE:", }) // Test that the negotiated signature algorithm respects the client and // server preferences. testCases = append(testCases, testCase{ name: "NoCommonAlgorithms", config: Config{ MaxVersion: VersionTLS12, ClientAuth: RequireAnyClientCert, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithSHA512, signatureRSAPKCS1WithSHA1, }, }, shimCertificate: rsaCertificate.WithSignatureAlgorithms(signatureRSAPKCS1WithSHA256), shouldFail: true, expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:", }) testCases = append(testCases, testCase{ name: "NoCommonAlgorithms-TLS13", config: Config{ MaxVersion: VersionTLS13, ClientAuth: RequireAnyClientCert, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPSSWithSHA512, signatureRSAPSSWithSHA384, }, }, shimCertificate: rsaCertificate.WithSignatureAlgorithms(signatureRSAPSSWithSHA256), shouldFail: true, expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:", }) testCases = append(testCases, testCase{ name: "Agree-Digest-SHA256", config: Config{ MaxVersion: VersionTLS12, ClientAuth: RequireAnyClientCert, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithSHA1, signatureRSAPKCS1WithSHA256, }, }, shimCertificate: rsaCertificate.WithSignatureAlgorithms( signatureRSAPKCS1WithSHA256, signatureRSAPKCS1WithSHA1, ), expectations: connectionExpectations{ peerSignatureAlgorithm: signatureRSAPKCS1WithSHA256, }, }) testCases = append(testCases, testCase{ name: "Agree-Digest-SHA1", config: Config{ MaxVersion: VersionTLS12, ClientAuth: RequireAnyClientCert, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithSHA1, }, }, shimCertificate: rsaCertificate.WithSignatureAlgorithms( signatureRSAPKCS1WithSHA512, signatureRSAPKCS1WithSHA256, signatureRSAPKCS1WithSHA1, ), expectations: connectionExpectations{ peerSignatureAlgorithm: signatureRSAPKCS1WithSHA1, }, }) testCases = append(testCases, testCase{ name: "Agree-Digest-Default", config: Config{ MaxVersion: VersionTLS12, ClientAuth: RequireAnyClientCert, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithSHA256, signatureECDSAWithP256AndSHA256, signatureRSAPKCS1WithSHA1, signatureECDSAWithSHA1, }, }, shimCertificate: &rsaCertificate, expectations: connectionExpectations{ peerSignatureAlgorithm: signatureRSAPKCS1WithSHA256, }, }) // Test that the signing preference list may include extra algorithms // without negotiation problems. testCases = append(testCases, testCase{ testType: serverTest, name: "FilterExtraAlgorithms", config: Config{ MaxVersion: VersionTLS12, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithSHA256, }, }, shimCertificate: rsaCertificate.WithSignatureAlgorithms( signatureECDSAWithP256AndSHA256, signatureRSAPKCS1WithSHA256, ), expectations: connectionExpectations{ peerSignatureAlgorithm: signatureRSAPKCS1WithSHA256, }, }) // In TLS 1.2 and below, ECDSA uses the curve list rather than the // signature algorithms. testCases = append(testCases, testCase{ name: "CheckLeafCurve", config: Config{ MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, Credential: &ecdsaP256Certificate, }, flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, shouldFail: true, expectedError: ":BAD_ECC_CERT:", }) // In TLS 1.3, ECDSA does not use the ECDHE curve list. testCases = append(testCases, testCase{ name: "CheckLeafCurve-TLS13", config: Config{ MaxVersion: VersionTLS13, Credential: &ecdsaP256Certificate, }, flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, }) // In TLS 1.2, the ECDSA curve is not in the signature algorithm, so the // shim should accept P-256 with SHA-384. testCases = append(testCases, testCase{ name: "ECDSACurveMismatch-Verify-TLS12", config: Config{ MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, Credential: ecdsaP256Certificate.WithSignatureAlgorithms(signatureECDSAWithP384AndSHA384), }, }) // In TLS 1.3, the ECDSA curve comes from the signature algorithm, so the // shim should reject P-256 with SHA-384. testCases = append(testCases, testCase{ name: "ECDSACurveMismatch-Verify-TLS13", config: Config{ MaxVersion: VersionTLS13, Credential: ecdsaP256Certificate.WithSignatureAlgorithms(signatureECDSAWithP384AndSHA384), Bugs: ProtocolBugs{ SkipECDSACurveCheck: true, }, }, shouldFail: true, expectedError: ":WRONG_SIGNATURE_TYPE:", }) // Signature algorithm selection in TLS 1.3 should take the curve into // account. testCases = append(testCases, testCase{ testType: serverTest, name: "ECDSACurveMismatch-Sign-TLS13", config: Config{ MaxVersion: VersionTLS13, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureECDSAWithP384AndSHA384, signatureECDSAWithP256AndSHA256, }, }, shimCertificate: &ecdsaP256Certificate, expectations: connectionExpectations{ peerSignatureAlgorithm: signatureECDSAWithP256AndSHA256, }, }) // RSASSA-PSS with SHA-512 is too large for 1024-bit RSA. Test that the // server does not attempt to sign in that case. testCases = append(testCases, testCase{ testType: serverTest, name: "RSA-PSS-Large", config: Config{ MaxVersion: VersionTLS13, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPSSWithSHA512, }, }, shimCertificate: &rsa1024Certificate, shouldFail: true, expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:", }) // Test that RSA-PSS is enabled by default for TLS 1.2. testCases = append(testCases, testCase{ testType: clientTest, name: "RSA-PSS-Default-Verify", config: Config{ MaxVersion: VersionTLS12, Credential: rsaCertificate.WithSignatureAlgorithms(signatureRSAPSSWithSHA256), }, flags: []string{"-max-version", strconv.Itoa(VersionTLS12)}, }) testCases = append(testCases, testCase{ testType: serverTest, name: "RSA-PSS-Default-Sign", config: Config{ MaxVersion: VersionTLS12, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPSSWithSHA256, }, }, flags: []string{"-max-version", strconv.Itoa(VersionTLS12)}, }) // TLS 1.1 and below has no way to advertise support for or negotiate // Ed25519's signature algorithm. testCases = append(testCases, testCase{ testType: clientTest, name: "NoEd25519-TLS11-ServerAuth-Verify", config: Config{ MaxVersion: VersionTLS11, Credential: &ed25519Certificate, Bugs: ProtocolBugs{ // Sign with Ed25519 even though it is TLS 1.1. SigningAlgorithmForLegacyVersions: signatureEd25519, }, }, flags: []string{"-verify-prefs", strconv.Itoa(int(signatureEd25519))}, shouldFail: true, expectedError: ":PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE:", }) testCases = append(testCases, testCase{ testType: serverTest, name: "NoEd25519-TLS11-ServerAuth-Sign", config: Config{ MaxVersion: VersionTLS11, }, shimCertificate: &ed25519Certificate, shouldFail: true, expectedError: ":NO_SHARED_CIPHER:", }) testCases = append(testCases, testCase{ testType: serverTest, name: "NoEd25519-TLS11-ClientAuth-Verify", config: Config{ MaxVersion: VersionTLS11, Credential: &ed25519Certificate, Bugs: ProtocolBugs{ // Sign with Ed25519 even though it is TLS 1.1. SigningAlgorithmForLegacyVersions: signatureEd25519, }, }, flags: []string{ "-verify-prefs", strconv.Itoa(int(signatureEd25519)), "-require-any-client-certificate", }, shouldFail: true, expectedError: ":PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE:", }) testCases = append(testCases, testCase{ testType: clientTest, name: "NoEd25519-TLS11-ClientAuth-Sign", config: Config{ MaxVersion: VersionTLS11, ClientAuth: RequireAnyClientCert, }, shimCertificate: &ed25519Certificate, shouldFail: true, expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:", }) // Test Ed25519 is not advertised by default. testCases = append(testCases, testCase{ testType: clientTest, name: "Ed25519DefaultDisable-NoAdvertise", config: Config{ Credential: &ed25519Certificate, }, shouldFail: true, expectedLocalError: "tls: no common signature algorithms", }) // Test Ed25519, when disabled, is not accepted if the peer ignores our // preferences. testCases = append(testCases, testCase{ testType: clientTest, name: "Ed25519DefaultDisable-NoAccept", config: Config{ Credential: &ed25519Certificate, Bugs: ProtocolBugs{ IgnorePeerSignatureAlgorithmPreferences: true, }, }, shouldFail: true, expectedLocalError: "remote error: illegal parameter", expectedError: ":WRONG_SIGNATURE_TYPE:", }) // Test that configuring verify preferences changes what the client // advertises. testCases = append(testCases, testCase{ name: "VerifyPreferences-Advertised", config: Config{ Credential: rsaCertificate.WithSignatureAlgorithms( signatureRSAPSSWithSHA256, signatureRSAPSSWithSHA384, signatureRSAPSSWithSHA512, ), }, flags: []string{ "-verify-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA384)), "-expect-peer-signature-algorithm", strconv.Itoa(int(signatureRSAPSSWithSHA384)), }, }) // Test that the client advertises a set which the runner can find // nothing in common with. testCases = append(testCases, testCase{ name: "VerifyPreferences-NoCommonAlgorithms", config: Config{ Credential: rsaCertificate.WithSignatureAlgorithms( signatureRSAPSSWithSHA256, signatureRSAPSSWithSHA512, ), }, flags: []string{ "-verify-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA384)), }, shouldFail: true, expectedLocalError: "tls: no common signature algorithms", }) // Test that the client enforces its preferences when configured. testCases = append(testCases, testCase{ name: "VerifyPreferences-Enforced", config: Config{ Credential: rsaCertificate.WithSignatureAlgorithms( signatureRSAPSSWithSHA256, signatureRSAPSSWithSHA512, ), Bugs: ProtocolBugs{ IgnorePeerSignatureAlgorithmPreferences: true, }, }, flags: []string{ "-verify-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA384)), }, shouldFail: true, expectedLocalError: "remote error: illegal parameter", expectedError: ":WRONG_SIGNATURE_TYPE:", }) // Test that explicitly configuring Ed25519 is as good as changing the // boolean toggle. testCases = append(testCases, testCase{ name: "VerifyPreferences-Ed25519", config: Config{ Credential: &ed25519Certificate, }, flags: []string{ "-verify-prefs", strconv.Itoa(int(signatureEd25519)), }, }) for _, testType := range []testType{clientTest, serverTest} { for _, ver := range tlsVersions { if ver.version < VersionTLS12 { continue } prefix := "Client-" + ver.name + "-" noCommonAlgorithmsError := ":NO_COMMON_SIGNATURE_ALGORITHMS:" if testType == serverTest { prefix = "Server-" + ver.name + "-" // In TLS 1.2 servers, cipher selection and algorithm // selection are linked. if ver.version <= VersionTLS12 { noCommonAlgorithmsError = ":NO_SHARED_CIPHER:" } } // Test that the shim will not sign MD5/SHA1 with RSA at TLS 1.2, // even if specified in signing preferences. testCases = append(testCases, testCase{ testType: testType, name: prefix + "NoSign-RSA_PKCS1_MD5_SHA1", config: Config{ MaxVersion: ver.version, CipherSuites: signingCiphers, ClientAuth: RequireAnyClientCert, VerifySignatureAlgorithms: []signatureAlgorithm{signatureRSAPKCS1WithMD5AndSHA1}, }, shimCertificate: rsaCertificate.WithSignatureAlgorithms( signatureRSAPKCS1WithMD5AndSHA1, // Include a valid algorithm as well, to avoid an empty list // if filtered out. signatureRSAPKCS1WithSHA256, ), shouldFail: true, expectedError: noCommonAlgorithmsError, }) // Test that the shim will not accept MD5/SHA1 with RSA at TLS 1.2, // even if specified in verify preferences. testCases = append(testCases, testCase{ testType: testType, name: prefix + "NoVerify-RSA_PKCS1_MD5_SHA1", config: Config{ MaxVersion: ver.version, Credential: &rsaCertificate, Bugs: ProtocolBugs{ IgnorePeerSignatureAlgorithmPreferences: true, AlwaysSignAsLegacyVersion: true, SendSignatureAlgorithm: signatureRSAPKCS1WithMD5AndSHA1, }, }, shimCertificate: &rsaCertificate, flags: []string{ "-verify-prefs", strconv.Itoa(int(signatureRSAPKCS1WithMD5AndSHA1)), // Include a valid algorithm as well, to avoid an empty list // if filtered out. "-verify-prefs", strconv.Itoa(int(signatureRSAPKCS1WithSHA256)), "-require-any-client-certificate", }, shouldFail: true, expectedError: ":WRONG_SIGNATURE_TYPE:", }) } } // Test that, when there are no signature algorithms in common in TLS // 1.2, the server will still consider the legacy RSA key exchange. testCases = append(testCases, testCase{ testType: serverTest, name: "NoCommonSignatureAlgorithms-TLS12-Fallback", config: Config{ MaxVersion: VersionTLS12, CipherSuites: []uint16{ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, }, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureECDSAWithP256AndSHA256, }, }, expectations: connectionExpectations{ cipher: TLS_RSA_WITH_AES_128_GCM_SHA256, }, }) // id-RSASSA-PSS certificates are not accepted for use with rsa_pss_rsae_* // algorithms. There are separate codepoints, which we do not support, for // id-RSASSA-PSS. for _, ver := range tlsVersions { testCases = append(testCases, testCase{ testType: clientTest, name: "RejectPSSKeyType-Client-" + ver.name, config: Config{ MinVersion: ver.version, MaxVersion: ver.version, Credential: pssCertificate.WithSignatureAlgorithms( signatureRSAPSSWithSHA256, ), }, shouldFail: true, expectedError: ":UNSUPPORTED_ALGORITHM:", }) testCases = append(testCases, testCase{ testType: serverTest, name: "RejectPSSKeyType-Server-" + ver.name, config: Config{ MinVersion: ver.version, MaxVersion: ver.version, Credential: pssCertificate.WithSignatureAlgorithms( signatureRSAPSSWithSHA256, ), }, flags: []string{"-require-any-client-certificate"}, shouldFail: true, expectedError: ":UNSUPPORTED_ALGORITHM:", }) } } func addBadECDSASignatureTests() { for badR := BadValue(1); badR < NumBadValues; badR++ { for badS := BadValue(1); badS < NumBadValues; badS++ { testCases = append(testCases, testCase{ name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS), config: Config{ MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, Credential: &ecdsaP256Certificate, Bugs: ProtocolBugs{ BadECDSAR: badR, BadECDSAS: badS, }, }, shouldFail: true, expectedError: ":BAD_SIGNATURE:", }) testCases = append(testCases, testCase{ name: fmt.Sprintf("BadECDSA-%d-%d-TLS13", badR, badS), config: Config{ MaxVersion: VersionTLS13, Credential: &ecdsaP256Certificate, Bugs: ProtocolBugs{ BadECDSAR: badR, BadECDSAS: badS, }, }, shouldFail: true, expectedError: ":BAD_SIGNATURE:", }) } } }