| // 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 | |
| func addCompliancePolicyTests() { | |
| // When testing curves and signature algorithms, we need to exclude RSA key | |
| // exchange ciphers, otherwise the server will just fall back to those. One | |
| // of the compliance policies still allows these, despite the issues being | |
| // known since 1998. | |
| var ecdheAndSignCiphers []uint16 | |
| for _, suite := range testCipherSuites { | |
| if !isPSKSuite(suite.name) && !isRSAKeyExchange(suite.name) { | |
| ecdheAndSignCiphers = append(ecdheAndSignCiphers, suite.id) | |
| } | |
| } | |
| for _, protocol := range []protocol{tls, quic} { | |
| for _, suite := range testCipherSuites { | |
| var isFIPSCipherSuite bool | |
| switch suite.id { | |
| case TLS_AES_128_GCM_SHA256, | |
| TLS_AES_256_GCM_SHA384, | |
| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | |
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | |
| TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | |
| TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: | |
| isFIPSCipherSuite = true | |
| } | |
| var isWPACipherSuite bool | |
| var isCNSA1CipherSuite bool | |
| switch suite.id { | |
| case TLS_AES_256_GCM_SHA384, | |
| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | |
| TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: | |
| isWPACipherSuite = true | |
| isCNSA1CipherSuite = true | |
| case TLS_RSA_WITH_AES_256_GCM_SHA384: | |
| isCNSA1CipherSuite = true | |
| } | |
| var isCNSA2CipherSuite bool | |
| switch suite.id { | |
| case TLS_AES_256_GCM_SHA384: | |
| isCNSA2CipherSuite = true | |
| } | |
| var cert Credential | |
| if hasComponent(suite.name, "ECDSA") { | |
| cert = ecdsaP384Certificate | |
| } else { | |
| cert = rsaCertificate | |
| } | |
| maxVersion := uint16(VersionTLS13) | |
| if !isTLS13Suite(suite.name) { | |
| if protocol == quic { | |
| continue | |
| } | |
| maxVersion = VersionTLS12 | |
| } | |
| policies := []struct { | |
| flag string | |
| cipherSuiteOk bool | |
| }{ | |
| {"-fips-202205", isFIPSCipherSuite}, | |
| {"-fips-202609", isFIPSCipherSuite}, | |
| {"-wpa-202304", isWPACipherSuite}, | |
| {"-cnsa1-202603", isCNSA1CipherSuite}, | |
| {"-cnsa2-202603", isCNSA2CipherSuite}, | |
| } | |
| for _, policy := range policies { | |
| shouldFail := !policy.cipherSuiteOk | |
| // The CNSA2 policy requires TLS 1.3. | |
| if policy.flag == "-cnsa2-202603" && maxVersion == VersionTLS12 { | |
| shouldFail = true | |
| } | |
| testCases = append(testCases, testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "Compliance" + policy.flag + "-" + protocol.String() + "-Server-" + suite.name, | |
| config: Config{ | |
| MinVersion: VersionTLS12, | |
| MaxVersion: maxVersion, | |
| CipherSuites: []uint16{suite.id}, | |
| }, | |
| shimCertificate: &cert, | |
| flags: []string{ | |
| policy.flag, | |
| }, | |
| shouldFail: shouldFail, | |
| }) | |
| testCases = append(testCases, testCase{ | |
| testType: clientTest, | |
| protocol: protocol, | |
| name: "Compliance" + policy.flag + "-" + protocol.String() + "-Client-" + suite.name, | |
| config: Config{ | |
| MinVersion: VersionTLS12, | |
| MaxVersion: maxVersion, | |
| CipherSuites: []uint16{suite.id}, | |
| Credential: &cert, | |
| }, | |
| flags: []string{ | |
| policy.flag, | |
| }, | |
| shouldFail: shouldFail, | |
| }) | |
| } | |
| } | |
| // Check that a TLS 1.3 client won't accept ChaCha20 even if the server | |
| // picks it without it being in the client's cipher list. | |
| for _, policy := range []string{"-fips-202205", "-fips-202609"} { | |
| testCases = append(testCases, testCase{ | |
| testType: clientTest, | |
| protocol: protocol, | |
| name: "Compliance" + policy + "-" + protocol.String() + "-Client-ReallyWontAcceptChaCha", | |
| config: Config{ | |
| MinVersion: VersionTLS12, | |
| MaxVersion: maxVersion, | |
| Bugs: ProtocolBugs{ | |
| SendCipherSuite: TLS_CHACHA20_POLY1305_SHA256, | |
| }, | |
| }, | |
| flags: []string{ | |
| policy, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":WRONG_CIPHER_RETURNED:", | |
| }) | |
| } | |
| for _, curve := range testCurves { | |
| var isFIPSCurve bool | |
| switch curve.id { | |
| case CurveP256, CurveP384: | |
| isFIPSCurve = true | |
| } | |
| var isFIPSPQCurve bool | |
| switch curve.id { | |
| case CurveX25519MLKEM768, CurveMLKEM1024: | |
| isFIPSPQCurve = true | |
| } | |
| var isWPACurve bool | |
| switch curve.id { | |
| case CurveP384: | |
| isWPACurve = true | |
| } | |
| var isCNSA1Curve bool | |
| switch curve.id { | |
| case CurveP384, CurveMLKEM1024: | |
| isCNSA1Curve = true | |
| } | |
| var isCNSA2Curve bool | |
| switch curve.id { | |
| case CurveMLKEM1024: | |
| isCNSA2Curve = true | |
| } | |
| policies := []struct { | |
| flag string | |
| curveOk bool | |
| }{ | |
| {"-fips-202205", isFIPSCurve}, | |
| {"-fips-202609", isFIPSCurve || isFIPSPQCurve}, | |
| {"-wpa-202304", isWPACurve}, | |
| {"-cnsa1-202603", isCNSA1Curve}, | |
| {"-cnsa2-202603", isCNSA2Curve}, | |
| } | |
| for _, policy := range policies { | |
| testCases = append(testCases, testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "Compliance" + policy.flag + "-" + protocol.String() + "-Server-" + curve.name, | |
| config: Config{ | |
| MinVersion: VersionTLS12, | |
| MaxVersion: VersionTLS13, | |
| CipherSuites: ecdheAndSignCiphers, | |
| CurvePreferences: []CurveID{curve.id}, | |
| }, | |
| flags: []string{ | |
| policy.flag, | |
| }, | |
| shouldFail: !policy.curveOk, | |
| }) | |
| testCases = append(testCases, testCase{ | |
| testType: clientTest, | |
| protocol: protocol, | |
| name: "Compliance" + policy.flag + "-" + protocol.String() + "-Client-" + curve.name, | |
| config: Config{ | |
| MinVersion: VersionTLS12, | |
| MaxVersion: VersionTLS13, | |
| CipherSuites: ecdheAndSignCiphers, | |
| CurvePreferences: []CurveID{curve.id}, | |
| }, | |
| flags: []string{ | |
| policy.flag, | |
| }, | |
| shouldFail: !policy.curveOk, | |
| }) | |
| } | |
| } | |
| // For CNSA1 as a server, if the client supports ML-KEM-1024 (even if not | |
| // the first choice, or the first shared choice), the server will select | |
| // ML-KEM-1024, even if the client provides key shares for other groups. | |
| testCases = append(testCases, testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "Compliance-cnsa1-202603-" + protocol.String() + "-PrefersMLKEM1024", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| CurvePreferences: []CurveID{CurveP256, CurveP384, CurveMLKEM1024}, | |
| DefaultCurves: []CurveID{CurveP256, CurveP384}, | |
| }, | |
| flags: []string{ | |
| "-cnsa1-202603", | |
| }, | |
| expectations: connectionExpectations{ | |
| curveID: CurveMLKEM1024, | |
| }, | |
| }) | |
| // For FIPS 202609 as a server, X25519MLKEM768 and MLKEM1024 form an | |
| // equipreference group which takes precedence over classical curves. | |
| // The server will select between the two based on the client's preference, | |
| // even if the client prefers a classical curve overall. | |
| testCases = append(testCases, testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "Compliance-fips-202609-" + protocol.String() + "-Equipreference-PrefersX25519MLKEM768", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| CurvePreferences: []CurveID{CurveP256, CurveP384, CurveX25519MLKEM768, CurveMLKEM1024}, | |
| DefaultCurves: []CurveID{CurveP256, CurveP384}, | |
| }, | |
| flags: []string{ | |
| "-fips-202609", | |
| }, | |
| expectations: connectionExpectations{ | |
| curveID: CurveX25519MLKEM768, | |
| }, | |
| }) | |
| testCases = append(testCases, testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "Compliance-fips-202609-" + protocol.String() + "-Equipreference-PrefersMLKEM1024", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| CurvePreferences: []CurveID{CurveP256, CurveP384, CurveMLKEM1024, CurveX25519MLKEM768}, | |
| DefaultCurves: []CurveID{CurveP256, CurveP384}, | |
| }, | |
| flags: []string{ | |
| "-fips-202609", | |
| }, | |
| expectations: connectionExpectations{ | |
| curveID: CurveMLKEM1024, | |
| }, | |
| }) | |
| for _, sigalg := range testSignatureAlgorithms { | |
| // The TLS 1.0 and TLS 1.1 default signature algorithm does not | |
| // apply to these tests. | |
| if sigalg.id == 0 { | |
| continue | |
| } | |
| var isFIPSSigAlg bool | |
| switch sigalg.id { | |
| case signatureRSAPKCS1WithSHA256, | |
| signatureRSAPKCS1WithSHA384, | |
| signatureRSAPKCS1WithSHA512, | |
| signatureECDSAWithP256AndSHA256, | |
| signatureECDSAWithP384AndSHA384, | |
| signatureRSAPSSWithSHA256, | |
| signatureRSAPSSWithSHA384, | |
| signatureRSAPSSWithSHA512: | |
| isFIPSSigAlg = true | |
| } | |
| var isWPASigAlg bool | |
| switch sigalg.id { | |
| case signatureRSAPKCS1WithSHA384, | |
| signatureRSAPKCS1WithSHA512, | |
| signatureECDSAWithP384AndSHA384, | |
| signatureRSAPSSWithSHA384, | |
| signatureRSAPSSWithSHA512: | |
| isWPASigAlg = true | |
| } | |
| var isCNSASigAlg bool | |
| switch sigalg.id { | |
| case signatureRSAPKCS1WithSHA384, | |
| signatureECDSAWithP384AndSHA384, | |
| signatureRSAPSSWithSHA384: | |
| isCNSASigAlg = true | |
| } | |
| maxVersion := uint16(VersionTLS13) | |
| if hasComponent(sigalg.name, "PKCS1") { | |
| if protocol == quic { | |
| continue | |
| } | |
| maxVersion = VersionTLS12 | |
| } | |
| policies := []struct { | |
| flag string | |
| sigAlgOk bool | |
| }{ | |
| {"-fips-202205", isFIPSSigAlg}, | |
| {"-fips-202609", isFIPSSigAlg}, | |
| {"-wpa-202304", isWPASigAlg}, | |
| {"-cnsa1-202603", isCNSASigAlg}, | |
| {"-cnsa2-202603", isCNSASigAlg}, | |
| } | |
| cert := sigalg.baseCert.WithSignatureAlgorithms(sigalg.id) | |
| for _, policy := range policies { | |
| shouldFail := !policy.sigAlgOk | |
| // The CNSA2 policy requires TLS 1.3. | |
| if policy.flag == "-cnsa2-202603" && maxVersion == VersionTLS12 { | |
| shouldFail = true | |
| } | |
| testCases = append(testCases, testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "Compliance" + policy.flag + "-" + protocol.String() + "-Server-" + sigalg.name, | |
| config: Config{ | |
| MinVersion: VersionTLS12, | |
| MaxVersion: maxVersion, | |
| CipherSuites: ecdheAndSignCiphers, | |
| VerifySignatureAlgorithms: []signatureAlgorithm{sigalg.id}, | |
| }, | |
| // Use the base certificate. We wish to pick up the signature algorithm | |
| // preferences from the FIPS policy. | |
| shimCertificate: sigalg.baseCert, | |
| flags: []string{policy.flag}, | |
| shouldFail: shouldFail, | |
| }) | |
| testCases = append(testCases, testCase{ | |
| testType: clientTest, | |
| protocol: protocol, | |
| name: "Compliance" + policy.flag + "-" + protocol.String() + "-Client-" + sigalg.name, | |
| config: Config{ | |
| MinVersion: VersionTLS12, | |
| MaxVersion: maxVersion, | |
| CipherSuites: ecdheAndSignCiphers, | |
| Credential: cert, | |
| }, | |
| flags: []string{ | |
| policy.flag, | |
| }, | |
| shouldFail: shouldFail, | |
| }) | |
| } | |
| } | |
| // AES-256-GCM is the most preferred. | |
| testCases = append(testCases, testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "Compliance-cnsa202407-" + protocol.String() + "-AES-256-preferred", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384}, | |
| }, | |
| flags: []string{ | |
| "-cnsa-202407", | |
| }, | |
| expectations: connectionExpectations{cipher: TLS_AES_256_GCM_SHA384}, | |
| }) | |
| // AES-128-GCM is preferred over ChaCha20-Poly1305. | |
| testCases = append(testCases, testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "Compliance-cnsa202407-" + protocol.String() + "-AES-128-preferred", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_GCM_SHA256}, | |
| }, | |
| flags: []string{ | |
| "-cnsa-202407", | |
| }, | |
| expectations: connectionExpectations{cipher: TLS_AES_128_GCM_SHA256}, | |
| }) | |
| // AES-128-GCM and AES-256-GCM form an equipreference group in FIPS 202609. | |
| testCases = append(testCases, testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "Compliance-fips-202609-" + protocol.String() + "-CipherEquipreference-AES-128", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| CipherSuites: []uint16{TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384}, | |
| }, | |
| flags: []string{ | |
| "-fips-202609", | |
| }, | |
| expectations: connectionExpectations{cipher: TLS_AES_128_GCM_SHA256}, | |
| }) | |
| testCases = append(testCases, testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "Compliance-fips-202609-" + protocol.String() + "-CipherEquipreference-AES-256", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| CipherSuites: []uint16{TLS_AES_256_GCM_SHA384, TLS_AES_128_GCM_SHA256}, | |
| }, | |
| flags: []string{ | |
| "-fips-202609", | |
| }, | |
| expectations: connectionExpectations{cipher: TLS_AES_256_GCM_SHA384}, | |
| }) | |
| } | |
| } |