| // 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 "strconv" |
| |
| func addHintMismatchTests() { |
| // Each of these tests skips split handshakes because split handshakes does |
| // not handle a mismatch between shim and handshaker. Handshake hints, |
| // however, are designed to tolerate the mismatch. |
| // |
| // Note also these tests do not specify -handshake-hints directly. Instead, |
| // we define normal tests, that run even without a handshaker, and rely on |
| // convertToSplitHandshakeTests to generate a handshaker hints variant. This |
| // avoids repeating the -is-handshaker-supported and -handshaker-path logic. |
| // (While not useful, the tests will still pass without a handshaker.) |
| for _, protocol := range []protocol{tls, quic} { |
| // If the signing payload is different, the handshake still completes |
| // successfully. Different ALPN preferences will trigger a mismatch. |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-SignatureInput", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| NextProtos: []string{"foo", "bar"}, |
| }, |
| flags: []string{ |
| "-allow-hint-mismatch", |
| "-on-shim-select-alpn", "foo", |
| "-on-handshaker-select-alpn", "bar", |
| }, |
| expectations: connectionExpectations{ |
| nextProto: "foo", |
| nextProtoType: alpn, |
| }, |
| }) |
| |
| // The shim and handshaker may have different curve preferences. |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-KeyShare", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| // Send both curves in the key share list, to avoid getting |
| // mixed up with HelloRetryRequest. |
| DefaultCurves: []CurveID{CurveX25519, CurveP256}, |
| }, |
| flags: []string{ |
| "-allow-hint-mismatch", |
| "-on-shim-curves", strconv.Itoa(int(CurveX25519)), |
| "-on-handshaker-curves", strconv.Itoa(int(CurveP256)), |
| }, |
| expectations: connectionExpectations{ |
| curveID: CurveX25519, |
| }, |
| }) |
| if protocol != quic { |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-ECDHE-Group", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS12, |
| MaxVersion: VersionTLS12, |
| DefaultCurves: []CurveID{CurveX25519, CurveP256}, |
| }, |
| flags: []string{ |
| "-allow-hint-mismatch", |
| "-on-shim-curves", strconv.Itoa(int(CurveX25519)), |
| "-on-handshaker-curves", strconv.Itoa(int(CurveP256)), |
| }, |
| expectations: connectionExpectations{ |
| curveID: CurveX25519, |
| }, |
| }) |
| } |
| |
| // If the handshaker does HelloRetryRequest, it will omit most hints. |
| // The shim should still work. |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-HandshakerHelloRetryRequest", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| DefaultCurves: []CurveID{CurveX25519}, |
| }, |
| flags: []string{ |
| "-allow-hint-mismatch", |
| "-on-shim-curves", strconv.Itoa(int(CurveX25519)), |
| "-on-handshaker-curves", strconv.Itoa(int(CurveP256)), |
| }, |
| expectations: connectionExpectations{ |
| curveID: CurveX25519, |
| }, |
| }) |
| |
| // If the shim does HelloRetryRequest, the hints from the handshaker |
| // will be ignored. This is not reported as a mismatch because hints |
| // would not have helped the shim anyway. |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-ShimHelloRetryRequest", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| DefaultCurves: []CurveID{CurveX25519}, |
| }, |
| flags: []string{ |
| "-on-shim-curves", strconv.Itoa(int(CurveP256)), |
| "-on-handshaker-curves", strconv.Itoa(int(CurveX25519)), |
| }, |
| expectations: connectionExpectations{ |
| curveID: CurveP256, |
| }, |
| }) |
| |
| // The shim and handshaker may have different signature algorithm |
| // preferences. |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-SignatureAlgorithm-TLS13", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| VerifySignatureAlgorithms: []signatureAlgorithm{ |
| signatureRSAPSSWithSHA256, |
| signatureRSAPSSWithSHA384, |
| }, |
| }, |
| shimCertificate: rsaCertificate.WithSignatureAlgorithms(signatureRSAPSSWithSHA256), |
| handshakerCertificate: rsaCertificate.WithSignatureAlgorithms(signatureRSAPSSWithSHA384), |
| flags: []string{"-allow-hint-mismatch"}, |
| expectations: connectionExpectations{ |
| peerSignatureAlgorithm: signatureRSAPSSWithSHA256, |
| }, |
| }) |
| if protocol != quic { |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-SignatureAlgorithm-TLS12", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS12, |
| MaxVersion: VersionTLS12, |
| VerifySignatureAlgorithms: []signatureAlgorithm{ |
| signatureRSAPSSWithSHA256, |
| signatureRSAPSSWithSHA384, |
| }, |
| }, |
| shimCertificate: rsaCertificate.WithSignatureAlgorithms(signatureRSAPSSWithSHA256), |
| handshakerCertificate: rsaCertificate.WithSignatureAlgorithms(signatureRSAPSSWithSHA384), |
| flags: []string{"-allow-hint-mismatch"}, |
| expectations: connectionExpectations{ |
| peerSignatureAlgorithm: signatureRSAPSSWithSHA256, |
| }, |
| }) |
| } |
| |
| // The shim and handshaker may use different certificates. In TLS 1.3, |
| // the signature input includes the certificate, so we do not need to |
| // explicitly check for a public key match. In TLS 1.2, it does not. |
| ecdsaP256Certificate2 := rootCA.Issue(X509Info{ |
| PrivateKey: &channelIDKey, |
| DNSNames: []string{"test"}, |
| }).ToCredential() |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-Certificate-TLS13", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| }, |
| shimCertificate: &ecdsaP256Certificate, |
| handshakerCertificate: &ecdsaP256Certificate2, |
| flags: []string{"-allow-hint-mismatch"}, |
| expectations: connectionExpectations{ |
| peerCertificate: &ecdsaP256Certificate, |
| }, |
| }) |
| if protocol != quic { |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-Certificate-TLS12", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS12, |
| MaxVersion: VersionTLS12, |
| }, |
| shimCertificate: &ecdsaP256Certificate, |
| handshakerCertificate: &ecdsaP256Certificate2, |
| flags: []string{"-allow-hint-mismatch"}, |
| expectations: connectionExpectations{ |
| peerCertificate: &ecdsaP256Certificate, |
| }, |
| }) |
| } |
| |
| // The shim and handshaker may disagree on whether resumption is allowed. |
| // We run the first connection with tickets enabled, so the client is |
| // issued a ticket, then disable tickets on the second connection. |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-NoTickets1-TLS13", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| }, |
| flags: []string{ |
| "-on-resume-allow-hint-mismatch", |
| "-on-shim-on-resume-no-ticket", |
| }, |
| resumeSession: true, |
| expectResumeRejected: true, |
| }) |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-NoTickets2-TLS13", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| }, |
| flags: []string{ |
| "-on-resume-allow-hint-mismatch", |
| "-on-handshaker-on-resume-no-ticket", |
| }, |
| resumeSession: true, |
| }) |
| if protocol != quic { |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-NoTickets1-TLS12", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS12, |
| MaxVersion: VersionTLS12, |
| }, |
| flags: []string{ |
| "-on-resume-allow-hint-mismatch", |
| "-on-shim-on-resume-no-ticket", |
| }, |
| resumeSession: true, |
| expectResumeRejected: true, |
| }) |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-NoTickets2-TLS12", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS12, |
| MaxVersion: VersionTLS12, |
| }, |
| flags: []string{ |
| "-on-resume-allow-hint-mismatch", |
| "-on-handshaker-on-resume-no-ticket", |
| }, |
| resumeSession: true, |
| }) |
| } |
| |
| // The shim and handshaker may disagree on whether to request a client |
| // certificate. |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-CertificateRequest", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| Credential: &rsaCertificate, |
| }, |
| flags: []string{ |
| "-allow-hint-mismatch", |
| "-on-shim-require-any-client-certificate", |
| }, |
| }) |
| |
| // The shim and handshaker may negotiate different versions altogether. |
| if protocol != quic { |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-Version1", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS12, |
| MaxVersion: VersionTLS13, |
| }, |
| flags: []string{ |
| "-allow-hint-mismatch", |
| "-on-shim-max-version", strconv.Itoa(VersionTLS12), |
| "-on-handshaker-max-version", strconv.Itoa(VersionTLS13), |
| }, |
| expectations: connectionExpectations{ |
| version: VersionTLS12, |
| }, |
| }) |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-Version2", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS12, |
| MaxVersion: VersionTLS13, |
| }, |
| flags: []string{ |
| "-allow-hint-mismatch", |
| "-on-shim-max-version", strconv.Itoa(VersionTLS13), |
| "-on-handshaker-max-version", strconv.Itoa(VersionTLS12), |
| }, |
| expectations: connectionExpectations{ |
| version: VersionTLS13, |
| }, |
| }) |
| } |
| |
| // The shim and handshaker may disagree on the certificate compression |
| // algorithm, whether to enable certificate compression, or certificate |
| // compression inputs. |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-CertificateCompression-ShimOnly", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| CertCompressionAlgs: map[uint16]CertCompressionAlg{ |
| shrinkingCompressionAlgID: shrinkingCompression, |
| }, |
| Bugs: ProtocolBugs{ |
| ExpectedCompressedCert: shrinkingCompressionAlgID, |
| }, |
| }, |
| flags: []string{ |
| "-allow-hint-mismatch", |
| "-on-shim-install-cert-compression-algs", |
| }, |
| }) |
| testCases = append(testCases, testCase{ |
| name: protocol.String() + "-HintMismatch-CertificateCompression-HandshakerOnly", |
| testType: serverTest, |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| CertCompressionAlgs: map[uint16]CertCompressionAlg{ |
| shrinkingCompressionAlgID: shrinkingCompression, |
| }, |
| Bugs: ProtocolBugs{ |
| ExpectUncompressedCert: true, |
| }, |
| }, |
| flags: []string{ |
| "-allow-hint-mismatch", |
| "-on-handshaker-install-cert-compression-algs", |
| }, |
| }) |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: protocol.String() + "-HintMismatch-CertificateCompression-AlgorithmMismatch", |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| CertCompressionAlgs: map[uint16]CertCompressionAlg{ |
| shrinkingCompressionAlgID: shrinkingCompression, |
| expandingCompressionAlgID: expandingCompression, |
| }, |
| Bugs: ProtocolBugs{ |
| // The shim's preferences should take effect. |
| ExpectedCompressedCert: shrinkingCompressionAlgID, |
| }, |
| }, |
| flags: []string{ |
| "-allow-hint-mismatch", |
| "-on-shim-install-one-cert-compression-alg", strconv.Itoa(shrinkingCompressionAlgID), |
| "-on-handshaker-install-one-cert-compression-alg", strconv.Itoa(expandingCompressionAlgID), |
| }, |
| }) |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: protocol.String() + "-HintMismatch-CertificateCompression-InputMismatch", |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| CertCompressionAlgs: map[uint16]CertCompressionAlg{ |
| shrinkingCompressionAlgID: shrinkingCompression, |
| }, |
| Bugs: ProtocolBugs{ |
| ExpectedCompressedCert: shrinkingCompressionAlgID, |
| }, |
| }, |
| // Configure the shim and handshaker with different OCSP responses, |
| // so the compression inputs do not match. |
| shimCertificate: rsaCertificate.WithOCSP(testOCSPResponse), |
| handshakerCertificate: rsaCertificate.WithOCSP(testOCSPResponse2), |
| flags: []string{ |
| "-allow-hint-mismatch", |
| "-install-cert-compression-algs", |
| }, |
| expectations: connectionExpectations{ |
| // The shim's configuration should take precendence. |
| peerCertificate: rsaCertificate.WithOCSP(testOCSPResponse), |
| }, |
| }) |
| |
| // The shim and handshaker may disagree on cipher suite, to the point |
| // that one selects RSA key exchange (no applicable hint) and the other |
| // selects ECDHE_RSA (hints are useful). |
| if protocol != quic { |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: protocol.String() + "-HintMismatch-CipherMismatch1", |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS12, |
| MaxVersion: VersionTLS12, |
| }, |
| flags: []string{ |
| "-allow-hint-mismatch", |
| "-on-shim-cipher", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", |
| "-on-handshaker-cipher", "TLS_RSA_WITH_AES_128_GCM_SHA256", |
| }, |
| expectations: connectionExpectations{ |
| cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, |
| }, |
| }) |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: protocol.String() + "-HintMismatch-CipherMismatch2", |
| protocol: protocol, |
| skipSplitHandshake: true, |
| config: Config{ |
| MinVersion: VersionTLS12, |
| MaxVersion: VersionTLS12, |
| }, |
| flags: []string{ |
| // There is no need to pass -allow-hint-mismatch. The |
| // handshaker will unnecessarily generate a signature hints. |
| // This is not reported as a mismatch because hints would |
| // not have helped the shim anyway. |
| "-on-shim-cipher", "TLS_RSA_WITH_AES_128_GCM_SHA256", |
| "-on-handshaker-cipher", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", |
| }, |
| expectations: connectionExpectations{ |
| cipher: TLS_RSA_WITH_AES_128_GCM_SHA256, |
| }, |
| }) |
| } |
| } |
| } |