| // 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 testCurves = []struct { |
| name string |
| id CurveID |
| }{ |
| {"P-256", CurveP256}, |
| {"P-384", CurveP384}, |
| {"P-521", CurveP521}, |
| {"X25519", CurveX25519}, |
| {"Kyber", CurveX25519Kyber768}, |
| {"X25519MLKEM768", CurveX25519MLKEM768}, |
| {"MLKEM1024", CurveMLKEM1024}, |
| } |
| |
| const bogusCurve = 0x1234 |
| |
| func isPqGroup(r CurveID) bool { |
| return r == CurveX25519Kyber768 || isMLKEMGroup(r) |
| } |
| |
| func isMLKEMGroup(r CurveID) bool { |
| return r == CurveX25519MLKEM768 || r == CurveMLKEM1024 |
| } |
| |
| func isECDHGroup(r CurveID) bool { |
| return r == CurveP256 || r == CurveP384 || r == CurveP521 |
| } |
| |
| func isX25519Group(r CurveID) bool { |
| return r == CurveX25519 || r == CurveX25519Kyber768 || r == CurveX25519MLKEM768 |
| } |
| |
| func addCurveTests() { |
| // A set of cipher suites that ensures some curve-using mode is used. |
| // Without this, servers may fall back to RSA key exchange. |
| ecdheCiphers := []uint16{ |
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, |
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, |
| TLS_AES_256_GCM_SHA384, |
| } |
| |
| // Not all curves are enabled by default, so these tests explicitly enable |
| // the curve under test in the shim. |
| for _, curve := range testCurves { |
| for _, ver := range tlsVersions { |
| if isPqGroup(curve.id) && ver.version < VersionTLS13 { |
| continue |
| } |
| for _, testType := range []testType{clientTest, serverTest} { |
| suffix := fmt.Sprintf("%s-%s-%s", testType, curve.name, ver.name) |
| |
| testCases = append(testCases, testCase{ |
| testType: testType, |
| name: "CurveTest-" + suffix, |
| config: Config{ |
| MaxVersion: ver.version, |
| CipherSuites: ecdheCiphers, |
| CurvePreferences: []CurveID{curve.id}, |
| }, |
| flags: append( |
| []string{"-expect-curve-id", strconv.Itoa(int(curve.id))}, |
| flagCurves("-curves", []CurveID{curve.id})..., |
| ), |
| expectations: connectionExpectations{ |
| curveID: curve.id, |
| }, |
| }) |
| |
| badKeyShareLocalError := "remote error: illegal parameter" |
| if testType == clientTest && ver.version >= VersionTLS13 { |
| // If the shim is a TLS 1.3 client and the runner sends a bad |
| // key share, the runner never reads the client's cleartext |
| // alert because the runner has already started encrypting by |
| // the time the client sees it. |
| badKeyShareLocalError = "local error: bad record MAC" |
| } |
| |
| testCases = append(testCases, testCase{ |
| testType: testType, |
| name: "CurveTest-Invalid-TruncateKeyShare-" + suffix, |
| config: Config{ |
| MaxVersion: ver.version, |
| CipherSuites: ecdheCiphers, |
| CurvePreferences: []CurveID{curve.id}, |
| Bugs: ProtocolBugs{ |
| TruncateKeyShare: true, |
| }, |
| }, |
| flags: flagCurves("-curves", []CurveID{curve.id}), |
| shouldFail: true, |
| expectedError: ":BAD_ECPOINT:", |
| expectedLocalError: badKeyShareLocalError, |
| }) |
| |
| testCases = append(testCases, testCase{ |
| testType: testType, |
| name: "CurveTest-Invalid-PadKeyShare-" + suffix, |
| config: Config{ |
| MaxVersion: ver.version, |
| CipherSuites: ecdheCiphers, |
| CurvePreferences: []CurveID{curve.id}, |
| Bugs: ProtocolBugs{ |
| PadKeyShare: true, |
| }, |
| }, |
| flags: flagCurves("-curves", []CurveID{curve.id}), |
| shouldFail: true, |
| expectedError: ":BAD_ECPOINT:", |
| expectedLocalError: badKeyShareLocalError, |
| }) |
| |
| if isECDHGroup(curve.id) { |
| testCases = append(testCases, testCase{ |
| testType: testType, |
| name: "CurveTest-Invalid-Compressed-" + suffix, |
| config: Config{ |
| MaxVersion: ver.version, |
| CipherSuites: ecdheCiphers, |
| CurvePreferences: []CurveID{curve.id}, |
| Bugs: ProtocolBugs{ |
| SendCompressedCoordinates: true, |
| }, |
| }, |
| flags: flagCurves("-curves", []CurveID{curve.id}), |
| shouldFail: true, |
| expectedError: ":BAD_ECPOINT:", |
| expectedLocalError: badKeyShareLocalError, |
| }) |
| testCases = append(testCases, testCase{ |
| testType: testType, |
| name: "CurveTest-Invalid-NotOnCurve-" + suffix, |
| config: Config{ |
| MaxVersion: ver.version, |
| CipherSuites: ecdheCiphers, |
| CurvePreferences: []CurveID{curve.id}, |
| Bugs: ProtocolBugs{ |
| ECDHPointNotOnCurve: true, |
| }, |
| }, |
| flags: flagCurves("-curves", []CurveID{curve.id}), |
| shouldFail: true, |
| expectedError: ":BAD_ECPOINT:", |
| expectedLocalError: badKeyShareLocalError, |
| }) |
| } |
| |
| if isX25519Group(curve.id) { |
| // Implementations should mask off the high order bit in X25519. |
| testCases = append(testCases, testCase{ |
| testType: testType, |
| name: "CurveTest-SetX25519HighBit-" + suffix, |
| config: Config{ |
| MaxVersion: ver.version, |
| CipherSuites: ecdheCiphers, |
| CurvePreferences: []CurveID{curve.id}, |
| Bugs: ProtocolBugs{ |
| SetX25519HighBit: true, |
| }, |
| }, |
| flags: flagCurves("-curves", []CurveID{curve.id}), |
| expectations: connectionExpectations{ |
| curveID: curve.id, |
| }, |
| }) |
| |
| // Implementations should reject low order points. |
| testCases = append(testCases, testCase{ |
| testType: testType, |
| name: "CurveTest-Invalid-LowOrderX25519Point-" + suffix, |
| config: Config{ |
| MaxVersion: ver.version, |
| CipherSuites: ecdheCiphers, |
| CurvePreferences: []CurveID{curve.id}, |
| Bugs: ProtocolBugs{ |
| LowOrderX25519Point: true, |
| }, |
| }, |
| flags: flagCurves("-curves", []CurveID{curve.id}), |
| shouldFail: true, |
| expectedError: ":BAD_ECPOINT:", |
| expectedLocalError: badKeyShareLocalError, |
| }) |
| } |
| |
| if isMLKEMGroup(curve.id) && testType == serverTest { |
| testCases = append(testCases, testCase{ |
| testType: testType, |
| name: "CurveTest-Invalid-MLKEMEncapKeyNotReduced-" + suffix, |
| config: Config{ |
| MaxVersion: ver.version, |
| CipherSuites: ecdheCiphers, |
| CurvePreferences: []CurveID{curve.id}, |
| Bugs: ProtocolBugs{ |
| MLKEMEncapKeyNotReduced: true, |
| }, |
| }, |
| flags: flagCurves("-curves", []CurveID{curve.id}), |
| shouldFail: true, |
| expectedError: ":BAD_ECPOINT:", |
| expectedLocalError: badKeyShareLocalError, |
| }) |
| } |
| } |
| } |
| } |
| |
| // The server must be tolerant to bogus curves. |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "UnknownCurve", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, |
| CurvePreferences: []CurveID{bogusCurve, CurveP256}, |
| }, |
| }) |
| |
| // The server must be tolerant to bogus curves. |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "UnknownCurve-TLS13", |
| config: Config{ |
| MaxVersion: VersionTLS13, |
| CurvePreferences: []CurveID{bogusCurve, CurveP256}, |
| }, |
| }) |
| |
| // The server must not consider ECDHE ciphers when there are no |
| // supported curves. |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "NoSupportedCurves", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, |
| Bugs: ProtocolBugs{ |
| NoSupportedCurves: true, |
| }, |
| }, |
| shouldFail: true, |
| expectedError: ":NO_SHARED_CIPHER:", |
| }) |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "NoSupportedCurves-TLS13", |
| config: Config{ |
| MaxVersion: VersionTLS13, |
| Bugs: ProtocolBugs{ |
| NoSupportedCurves: true, |
| }, |
| }, |
| shouldFail: true, |
| expectedError: ":NO_SHARED_GROUP:", |
| }) |
| |
| // The server must fall back to another cipher when there are no |
| // supported curves. |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "NoCommonCurves", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| CipherSuites: []uint16{ |
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, |
| TLS_RSA_WITH_AES_128_GCM_SHA256, |
| }, |
| CurvePreferences: []CurveID{21 /* P-224 */}, |
| }, |
| expectations: connectionExpectations{ |
| cipher: TLS_RSA_WITH_AES_128_GCM_SHA256, |
| }, |
| }) |
| |
| // The client must reject bogus curves and disabled curves. |
| testCases = append(testCases, testCase{ |
| name: "BadECDHECurve", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, |
| Bugs: ProtocolBugs{ |
| SendCurve: bogusCurve, |
| }, |
| }, |
| shouldFail: true, |
| expectedError: ":WRONG_CURVE:", |
| }) |
| testCases = append(testCases, testCase{ |
| name: "BadECDHECurve-TLS13", |
| config: Config{ |
| MaxVersion: VersionTLS13, |
| Bugs: ProtocolBugs{ |
| SendCurve: bogusCurve, |
| }, |
| }, |
| shouldFail: true, |
| expectedError: ":WRONG_CURVE:", |
| }) |
| |
| testCases = append(testCases, testCase{ |
| name: "UnsupportedCurve", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, |
| CurvePreferences: []CurveID{CurveP256}, |
| Bugs: ProtocolBugs{ |
| IgnorePeerCurvePreferences: true, |
| }, |
| }, |
| flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, |
| shouldFail: true, |
| expectedError: ":WRONG_CURVE:", |
| }) |
| |
| testCases = append(testCases, testCase{ |
| // TODO(davidben): Add a TLS 1.3 version where |
| // HelloRetryRequest requests an unsupported curve. |
| name: "UnsupportedCurve-ServerHello-TLS13", |
| config: Config{ |
| MaxVersion: VersionTLS13, |
| CurvePreferences: []CurveID{CurveP384}, |
| Bugs: ProtocolBugs{ |
| SendCurve: CurveP256, |
| }, |
| }, |
| flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, |
| shouldFail: true, |
| expectedError: ":WRONG_CURVE:", |
| }) |
| |
| // The previous curve ID should be reported on TLS 1.2 resumption. |
| testCases = append(testCases, testCase{ |
| name: "CurveID-Resume-Client", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, |
| CurvePreferences: []CurveID{CurveX25519}, |
| }, |
| flags: []string{"-expect-curve-id", strconv.Itoa(int(CurveX25519))}, |
| resumeSession: true, |
| }) |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "CurveID-Resume-Server", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, |
| CurvePreferences: []CurveID{CurveX25519}, |
| }, |
| flags: []string{"-expect-curve-id", strconv.Itoa(int(CurveX25519))}, |
| resumeSession: true, |
| }) |
| |
| // TLS 1.3 allows resuming at a differet curve. If this happens, the new |
| // one should be reported. |
| testCases = append(testCases, testCase{ |
| name: "CurveID-Resume-Client-TLS13", |
| config: Config{ |
| MaxVersion: VersionTLS13, |
| CurvePreferences: []CurveID{CurveX25519}, |
| }, |
| resumeConfig: &Config{ |
| MaxVersion: VersionTLS13, |
| CurvePreferences: []CurveID{CurveP256}, |
| }, |
| flags: []string{ |
| "-on-initial-expect-curve-id", strconv.Itoa(int(CurveX25519)), |
| "-on-resume-expect-curve-id", strconv.Itoa(int(CurveP256)), |
| }, |
| resumeSession: true, |
| }) |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "CurveID-Resume-Server-TLS13", |
| config: Config{ |
| MaxVersion: VersionTLS13, |
| CurvePreferences: []CurveID{CurveX25519}, |
| }, |
| resumeConfig: &Config{ |
| MaxVersion: VersionTLS13, |
| CurvePreferences: []CurveID{CurveP256}, |
| }, |
| flags: []string{ |
| "-on-initial-expect-curve-id", strconv.Itoa(int(CurveX25519)), |
| "-on-resume-expect-curve-id", strconv.Itoa(int(CurveP256)), |
| }, |
| resumeSession: true, |
| }) |
| |
| // Server-sent point formats are legal in TLS 1.2, but not in TLS 1.3. |
| testCases = append(testCases, testCase{ |
| name: "PointFormat-ServerHello-TLS12", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| Bugs: ProtocolBugs{ |
| SendSupportedPointFormats: []byte{pointFormatUncompressed}, |
| }, |
| }, |
| }) |
| testCases = append(testCases, testCase{ |
| name: "PointFormat-EncryptedExtensions-TLS13", |
| config: Config{ |
| MaxVersion: VersionTLS13, |
| Bugs: ProtocolBugs{ |
| SendSupportedPointFormats: []byte{pointFormatUncompressed}, |
| }, |
| }, |
| shouldFail: true, |
| expectedError: ":ERROR_PARSING_EXTENSION:", |
| }) |
| |
| // Server-sent supported groups/curves are legal in TLS 1.3. They are |
| // illegal in TLS 1.2, but some servers send them anyway, so we must |
| // tolerate them. |
| testCases = append(testCases, testCase{ |
| name: "SupportedCurves-ServerHello-TLS12", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| Bugs: ProtocolBugs{ |
| SendServerSupportedCurves: true, |
| }, |
| }, |
| }) |
| testCases = append(testCases, testCase{ |
| name: "SupportedCurves-EncryptedExtensions-TLS13", |
| config: Config{ |
| MaxVersion: VersionTLS13, |
| Bugs: ProtocolBugs{ |
| SendServerSupportedCurves: true, |
| }, |
| }, |
| }) |
| |
| // Test that we tolerate unknown point formats, as long as |
| // pointFormatUncompressed is present. Limit ciphers to ECDHE ciphers to |
| // check they are still functional. |
| testCases = append(testCases, testCase{ |
| name: "PointFormat-Client-Tolerance", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| Bugs: ProtocolBugs{ |
| SendSupportedPointFormats: []byte{42, pointFormatUncompressed, 99, pointFormatCompressedPrime}, |
| }, |
| }, |
| }) |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "PointFormat-Server-Tolerance", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, |
| Bugs: ProtocolBugs{ |
| SendSupportedPointFormats: []byte{42, pointFormatUncompressed, 99, pointFormatCompressedPrime}, |
| }, |
| }, |
| }) |
| |
| // Test TLS 1.2 does not require the point format extension to be |
| // present. |
| testCases = append(testCases, testCase{ |
| name: "PointFormat-Client-Missing", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, |
| Bugs: ProtocolBugs{ |
| SendSupportedPointFormats: []byte{}, |
| }, |
| }, |
| }) |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "PointFormat-Server-Missing", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, |
| Bugs: ProtocolBugs{ |
| SendSupportedPointFormats: []byte{}, |
| }, |
| }, |
| }) |
| |
| // If the point format extension is present, uncompressed points must be |
| // offered. BoringSSL requires this whether or not ECDHE is used. |
| testCases = append(testCases, testCase{ |
| name: "PointFormat-Client-MissingUncompressed", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| Bugs: ProtocolBugs{ |
| SendSupportedPointFormats: []byte{pointFormatCompressedPrime}, |
| }, |
| }, |
| shouldFail: true, |
| expectedError: ":ERROR_PARSING_EXTENSION:", |
| }) |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "PointFormat-Server-MissingUncompressed", |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| Bugs: ProtocolBugs{ |
| SendSupportedPointFormats: []byte{pointFormatCompressedPrime}, |
| }, |
| }, |
| shouldFail: true, |
| expectedError: ":ERROR_PARSING_EXTENSION:", |
| }) |
| |
| // Post-quantum groups require TLS 1.3. |
| for _, curve := range testCurves { |
| if !isPqGroup(curve.id) { |
| continue |
| } |
| |
| // Post-quantum groups should not be offered by a TLS 1.2 client. |
| testCases = append(testCases, testCase{ |
| name: "TLS12ClientShouldNotOffer-" + curve.name, |
| config: Config{ |
| Bugs: ProtocolBugs{ |
| FailIfPostQuantumOffered: true, |
| }, |
| }, |
| flags: []string{ |
| "-max-version", strconv.Itoa(VersionTLS12), |
| "-curves", strconv.Itoa(int(curve.id)), |
| "-curves", strconv.Itoa(int(CurveX25519)), |
| }, |
| }) |
| |
| // Post-quantum groups should not be selected by a TLS 1.2 server. |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "TLS12ServerShouldNotSelect-" + curve.name, |
| flags: []string{ |
| "-max-version", strconv.Itoa(VersionTLS12), |
| "-curves", strconv.Itoa(int(curve.id)), |
| "-curves", strconv.Itoa(int(CurveX25519)), |
| }, |
| expectations: connectionExpectations{ |
| curveID: CurveX25519, |
| }, |
| }) |
| |
| // If a TLS 1.2 server selects a post-quantum group anyway, the client |
| // should not accept it. |
| testCases = append(testCases, testCase{ |
| name: "ClientShouldNotAllowInTLS12-" + curve.name, |
| config: Config{ |
| MaxVersion: VersionTLS12, |
| Bugs: ProtocolBugs{ |
| SendCurve: curve.id, |
| }, |
| }, |
| flags: []string{ |
| "-curves", strconv.Itoa(int(curve.id)), |
| "-curves", strconv.Itoa(int(CurveX25519)), |
| }, |
| shouldFail: true, |
| expectedError: ":WRONG_CURVE:", |
| expectedLocalError: "remote error: illegal parameter", |
| }) |
| } |
| |
| // ML-KEM and Kyber should not be offered by default as a client. |
| testCases = append(testCases, testCase{ |
| name: "PostQuantumNotEnabledByDefaultInClients", |
| config: Config{ |
| MinVersion: VersionTLS13, |
| Bugs: ProtocolBugs{ |
| FailIfPostQuantumOffered: true, |
| }, |
| }, |
| }) |
| |
| for _, curve := range testCurves { |
| if !isMLKEMGroup(curve.id) { |
| continue |
| } |
| |
| // If ML-KEM is offered, both X25519 and ML-KEM should have a key-share. |
| testCases = append(testCases, testCase{ |
| name: "NotJustMLKEMKeyShare-" + curve.name, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| Bugs: ProtocolBugs{ |
| ExpectedKeyShares: []CurveID{curve.id, CurveX25519}, |
| }, |
| }, |
| flags: []string{ |
| "-curves", strconv.Itoa(int(curve.id)), |
| "-curves", strconv.Itoa(int(CurveX25519)), |
| "-expect-curve-id", strconv.Itoa(int(curve.id)), |
| }, |
| }) |
| |
| // ... and the other way around |
| testCases = append(testCases, testCase{ |
| name: "MLKEMKeyShareIncludedSecond-" + curve.name, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| Bugs: ProtocolBugs{ |
| ExpectedKeyShares: []CurveID{CurveX25519, curve.id}, |
| }, |
| }, |
| flags: []string{ |
| "-curves", strconv.Itoa(int(CurveX25519)), |
| "-curves", strconv.Itoa(int(curve.id)), |
| "-expect-curve-id", strconv.Itoa(int(CurveX25519)), |
| }, |
| }) |
| |
| // ... and even if there's another curve in the middle because it's the |
| // first classical and first post-quantum "curves" that get key shares |
| // included. |
| testCases = append(testCases, testCase{ |
| name: "MLKEMKeyShareIncludedThird-" + curve.name, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| Bugs: ProtocolBugs{ |
| ExpectedKeyShares: []CurveID{CurveX25519, curve.id}, |
| }, |
| }, |
| flags: []string{ |
| "-curves", strconv.Itoa(int(CurveX25519)), |
| "-curves", strconv.Itoa(int(CurveP256)), |
| "-curves", strconv.Itoa(int(curve.id)), |
| "-expect-curve-id", strconv.Itoa(int(CurveX25519)), |
| }, |
| }) |
| |
| // If ML-KEM is the only configured curve, the key share is sent. |
| testCases = append(testCases, testCase{ |
| name: "JustConfiguringMLKEMWorks-" + curve.name, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| Bugs: ProtocolBugs{ |
| ExpectedKeyShares: []CurveID{curve.id}, |
| }, |
| }, |
| flags: []string{ |
| "-curves", strconv.Itoa(int(curve.id)), |
| "-expect-curve-id", strconv.Itoa(int(curve.id)), |
| }, |
| }) |
| |
| // If both ML-KEM and Kyber are configured, only the preferred one's |
| // key share should be sent. |
| testCases = append(testCases, testCase{ |
| name: "BothMLKEMAndKyber-" + curve.name, |
| config: Config{ |
| MinVersion: VersionTLS13, |
| Bugs: ProtocolBugs{ |
| ExpectedKeyShares: []CurveID{curve.id}, |
| }, |
| }, |
| flags: []string{ |
| "-curves", strconv.Itoa(int(curve.id)), |
| "-curves", strconv.Itoa(int(CurveX25519Kyber768)), |
| "-expect-curve-id", strconv.Itoa(int(curve.id)), |
| }, |
| }) |
| } |
| |
| // As a server, ML-KEMs and Kyber are not yet supported by default. |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "PostQuantumNotEnabledByDefaultForAServer", |
| config: Config{ |
| MinVersion: VersionTLS13, |
| CurvePreferences: []CurveID{CurveX25519MLKEM768, CurveMLKEM1024, CurveX25519Kyber768, CurveX25519}, |
| DefaultCurves: []CurveID{CurveX25519MLKEM768, CurveMLKEM1024, CurveX25519Kyber768}, |
| }, |
| flags: []string{ |
| "-server-preference", |
| "-expect-curve-id", strconv.Itoa(int(CurveX25519)), |
| }, |
| }) |
| |
| // If two ML-KEMs are configured, only the preferred one's |
| // key share should be sent. |
| testCases = append(testCases, testCase{ |
| name: "TwoMLKEMs", |
| config: Config{ |
| MinVersion: VersionTLS13, |
| Bugs: ProtocolBugs{ |
| ExpectedKeyShares: []CurveID{CurveMLKEM1024}, |
| }, |
| }, |
| flags: []string{ |
| "-curves", strconv.Itoa(int(CurveMLKEM1024)), |
| "-curves", strconv.Itoa(int(CurveX25519MLKEM768)), |
| "-expect-curve-id", strconv.Itoa(int(CurveMLKEM1024)), |
| }, |
| }) |
| |
| // In TLS 1.2, the curve list is also used to signal ECDSA curves. |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "CheckECDSACurve-TLS12", |
| config: Config{ |
| MinVersion: VersionTLS12, |
| MaxVersion: VersionTLS12, |
| CurvePreferences: []CurveID{CurveP384}, |
| }, |
| shimCertificate: &ecdsaP256Certificate, |
| shouldFail: true, |
| expectedError: ":WRONG_CURVE:", |
| }) |
| |
| // If the ECDSA certificate is ineligible due to a curve mismatch, the |
| // server may still consider a PSK cipher suite. |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "CheckECDSACurve-PSK-TLS12", |
| config: Config{ |
| MinVersion: VersionTLS12, |
| MaxVersion: VersionTLS12, |
| CipherSuites: []uint16{ |
| TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, |
| TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, |
| }, |
| CurvePreferences: []CurveID{CurveP384}, |
| PreSharedKey: []byte("12345"), |
| PreSharedKeyIdentity: "luggage combo", |
| }, |
| shimCertificate: &ecdsaP256Certificate, |
| expectations: connectionExpectations{ |
| cipher: TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, |
| }, |
| flags: []string{ |
| "-psk", "12345", |
| "-psk-identity", "luggage combo", |
| }, |
| }) |
| |
| // In TLS 1.3, the curve list only controls ECDH. |
| testCases = append(testCases, testCase{ |
| testType: serverTest, |
| name: "CheckECDSACurve-NotApplicable-TLS13", |
| config: Config{ |
| MinVersion: VersionTLS13, |
| MaxVersion: VersionTLS13, |
| CurvePreferences: []CurveID{CurveP384}, |
| }, |
| shimCertificate: &ecdsaP256Certificate, |
| }) |
| } |