1// Copyright 2025 The BoringSSL Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package runner 16 17import ( 18 "fmt" 19 "strconv" 20) 21 22var testCurves = []struct { 23 name string 24 id CurveID 25}{ 26 {"P-256", CurveP256}, 27 {"P-384", CurveP384}, 28 {"P-521", CurveP521}, 29 {"X25519", CurveX25519}, 30 {"Kyber", CurveX25519Kyber768}, 31 {"X25519MLKEM768", CurveX25519MLKEM768}, 32 {"MLKEM1024", CurveMLKEM1024}, 33} 34 35const bogusCurve = 0x1234 36 37func isPqGroup(r CurveID) bool { 38 return r == CurveX25519Kyber768 || isMLKEMGroup(r) 39} 40 41func isMLKEMGroup(r CurveID) bool { 42 return r == CurveX25519MLKEM768 || r == CurveMLKEM1024 43} 44 45func isECDHGroup(r CurveID) bool { 46 return r == CurveP256 || r == CurveP384 || r == CurveP521 47} 48 49func isX25519Group(r CurveID) bool { 50 return r == CurveX25519 || r == CurveX25519Kyber768 || r == CurveX25519MLKEM768 51} 52 53func addCurveTests() { 54 // A set of cipher suites that ensures some curve-using mode is used. 55 // Without this, servers may fall back to RSA key exchange. 56 ecdheCiphers := []uint16{ 57 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 58 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 59 TLS_AES_256_GCM_SHA384, 60 } 61 62 // Not all curves are enabled by default, so these tests explicitly enable 63 // the curve under test in the shim. 64 for _, curve := range testCurves { 65 for _, ver := range tlsVersions { 66 if isPqGroup(curve.id) && ver.version < VersionTLS13 { 67 continue 68 } 69 for _, testType := range []testType{clientTest, serverTest} { 70 suffix := fmt.Sprintf("%s-%s-%s", testType, curve.name, ver.name) 71 72 testCases = append(testCases, testCase{ 73 testType: testType, 74 name: "CurveTest-" + suffix, 75 config: Config{ 76 MaxVersion: ver.version, 77 CipherSuites: ecdheCiphers, 78 CurvePreferences: []CurveID{curve.id}, 79 }, 80 flags: append( 81 []string{"-expect-curve-id", strconv.Itoa(int(curve.id))}, 82 flagCurves("-curves", []CurveID{curve.id})..., 83 ), 84 expectations: connectionExpectations{ 85 curveID: curve.id, 86 }, 87 }) 88 89 badKeyShareLocalError := "remote error: illegal parameter" 90 if testType == clientTest && ver.version >= VersionTLS13 { 91 // If the shim is a TLS 1.3 client and the runner sends a bad 92 // key share, the runner never reads the client's cleartext 93 // alert because the runner has already started encrypting by 94 // the time the client sees it. 95 badKeyShareLocalError = "local error: bad record MAC" 96 } 97 98 testCases = append(testCases, testCase{ 99 testType: testType, 100 name: "CurveTest-Invalid-TruncateKeyShare-" + suffix, 101 config: Config{ 102 MaxVersion: ver.version, 103 CipherSuites: ecdheCiphers, 104 CurvePreferences: []CurveID{curve.id}, 105 Bugs: ProtocolBugs{ 106 TruncateKeyShare: true, 107 }, 108 }, 109 flags: flagCurves("-curves", []CurveID{curve.id}), 110 shouldFail: true, 111 expectedError: ":BAD_ECPOINT:", 112 expectedLocalError: badKeyShareLocalError, 113 }) 114 115 testCases = append(testCases, testCase{ 116 testType: testType, 117 name: "CurveTest-Invalid-PadKeyShare-" + suffix, 118 config: Config{ 119 MaxVersion: ver.version, 120 CipherSuites: ecdheCiphers, 121 CurvePreferences: []CurveID{curve.id}, 122 Bugs: ProtocolBugs{ 123 PadKeyShare: true, 124 }, 125 }, 126 flags: flagCurves("-curves", []CurveID{curve.id}), 127 shouldFail: true, 128 expectedError: ":BAD_ECPOINT:", 129 expectedLocalError: badKeyShareLocalError, 130 }) 131 132 if isECDHGroup(curve.id) { 133 testCases = append(testCases, testCase{ 134 testType: testType, 135 name: "CurveTest-Invalid-Compressed-" + suffix, 136 config: Config{ 137 MaxVersion: ver.version, 138 CipherSuites: ecdheCiphers, 139 CurvePreferences: []CurveID{curve.id}, 140 Bugs: ProtocolBugs{ 141 SendCompressedCoordinates: true, 142 }, 143 }, 144 flags: flagCurves("-curves", []CurveID{curve.id}), 145 shouldFail: true, 146 expectedError: ":BAD_ECPOINT:", 147 expectedLocalError: badKeyShareLocalError, 148 }) 149 testCases = append(testCases, testCase{ 150 testType: testType, 151 name: "CurveTest-Invalid-NotOnCurve-" + suffix, 152 config: Config{ 153 MaxVersion: ver.version, 154 CipherSuites: ecdheCiphers, 155 CurvePreferences: []CurveID{curve.id}, 156 Bugs: ProtocolBugs{ 157 ECDHPointNotOnCurve: true, 158 }, 159 }, 160 flags: flagCurves("-curves", []CurveID{curve.id}), 161 shouldFail: true, 162 expectedError: ":BAD_ECPOINT:", 163 expectedLocalError: badKeyShareLocalError, 164 }) 165 } 166 167 if isX25519Group(curve.id) { 168 // Implementations should mask off the high order bit in X25519. 169 testCases = append(testCases, testCase{ 170 testType: testType, 171 name: "CurveTest-SetX25519HighBit-" + suffix, 172 config: Config{ 173 MaxVersion: ver.version, 174 CipherSuites: ecdheCiphers, 175 CurvePreferences: []CurveID{curve.id}, 176 Bugs: ProtocolBugs{ 177 SetX25519HighBit: true, 178 }, 179 }, 180 flags: flagCurves("-curves", []CurveID{curve.id}), 181 expectations: connectionExpectations{ 182 curveID: curve.id, 183 }, 184 }) 185 186 // Implementations should reject low order points. 187 testCases = append(testCases, testCase{ 188 testType: testType, 189 name: "CurveTest-Invalid-LowOrderX25519Point-" + suffix, 190 config: Config{ 191 MaxVersion: ver.version, 192 CipherSuites: ecdheCiphers, 193 CurvePreferences: []CurveID{curve.id}, 194 Bugs: ProtocolBugs{ 195 LowOrderX25519Point: true, 196 }, 197 }, 198 flags: flagCurves("-curves", []CurveID{curve.id}), 199 shouldFail: true, 200 expectedError: ":BAD_ECPOINT:", 201 expectedLocalError: badKeyShareLocalError, 202 }) 203 } 204 205 if isMLKEMGroup(curve.id) && testType == serverTest { 206 testCases = append(testCases, testCase{ 207 testType: testType, 208 name: "CurveTest-Invalid-MLKEMEncapKeyNotReduced-" + suffix, 209 config: Config{ 210 MaxVersion: ver.version, 211 CipherSuites: ecdheCiphers, 212 CurvePreferences: []CurveID{curve.id}, 213 Bugs: ProtocolBugs{ 214 MLKEMEncapKeyNotReduced: true, 215 }, 216 }, 217 flags: flagCurves("-curves", []CurveID{curve.id}), 218 shouldFail: true, 219 expectedError: ":BAD_ECPOINT:", 220 expectedLocalError: badKeyShareLocalError, 221 }) 222 } 223 } 224 } 225 } 226 227 // The server must be tolerant to bogus curves. 228 testCases = append(testCases, testCase{ 229 testType: serverTest, 230 name: "UnknownCurve", 231 config: Config{ 232 MaxVersion: VersionTLS12, 233 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, 234 CurvePreferences: []CurveID{bogusCurve, CurveP256}, 235 }, 236 }) 237 238 // The server must be tolerant to bogus curves. 239 testCases = append(testCases, testCase{ 240 testType: serverTest, 241 name: "UnknownCurve-TLS13", 242 config: Config{ 243 MaxVersion: VersionTLS13, 244 CurvePreferences: []CurveID{bogusCurve, CurveP256}, 245 }, 246 }) 247 248 // The server must not consider ECDHE ciphers when there are no 249 // supported curves. 250 testCases = append(testCases, testCase{ 251 testType: serverTest, 252 name: "NoSupportedCurves", 253 config: Config{ 254 MaxVersion: VersionTLS12, 255 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, 256 Bugs: ProtocolBugs{ 257 NoSupportedCurves: true, 258 }, 259 }, 260 shouldFail: true, 261 expectedError: ":NO_SHARED_CIPHER:", 262 }) 263 testCases = append(testCases, testCase{ 264 testType: serverTest, 265 name: "NoSupportedCurves-TLS13", 266 config: Config{ 267 MaxVersion: VersionTLS13, 268 Bugs: ProtocolBugs{ 269 NoSupportedCurves: true, 270 }, 271 }, 272 shouldFail: true, 273 expectedError: ":NO_SHARED_GROUP:", 274 }) 275 276 // The server must fall back to another cipher when there are no 277 // supported curves. 278 testCases = append(testCases, testCase{ 279 testType: serverTest, 280 name: "NoCommonCurves", 281 config: Config{ 282 MaxVersion: VersionTLS12, 283 CipherSuites: []uint16{ 284 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 285 TLS_RSA_WITH_AES_128_GCM_SHA256, 286 }, 287 CurvePreferences: []CurveID{21 /* P-224 */}, 288 }, 289 expectations: connectionExpectations{ 290 cipher: TLS_RSA_WITH_AES_128_GCM_SHA256, 291 }, 292 }) 293 294 // The client must reject bogus curves and disabled curves. 295 testCases = append(testCases, testCase{ 296 name: "BadECDHECurve", 297 config: Config{ 298 MaxVersion: VersionTLS12, 299 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, 300 Bugs: ProtocolBugs{ 301 SendCurve: bogusCurve, 302 }, 303 }, 304 shouldFail: true, 305 expectedError: ":WRONG_CURVE:", 306 }) 307 testCases = append(testCases, testCase{ 308 name: "BadECDHECurve-TLS13", 309 config: Config{ 310 MaxVersion: VersionTLS13, 311 Bugs: ProtocolBugs{ 312 SendCurve: bogusCurve, 313 }, 314 }, 315 shouldFail: true, 316 expectedError: ":WRONG_CURVE:", 317 }) 318 319 testCases = append(testCases, testCase{ 320 name: "UnsupportedCurve", 321 config: Config{ 322 MaxVersion: VersionTLS12, 323 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, 324 CurvePreferences: []CurveID{CurveP256}, 325 Bugs: ProtocolBugs{ 326 IgnorePeerCurvePreferences: true, 327 }, 328 }, 329 flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, 330 shouldFail: true, 331 expectedError: ":WRONG_CURVE:", 332 }) 333 334 testCases = append(testCases, testCase{ 335 // TODO(davidben): Add a TLS 1.3 version where 336 // HelloRetryRequest requests an unsupported curve. 337 name: "UnsupportedCurve-ServerHello-TLS13", 338 config: Config{ 339 MaxVersion: VersionTLS13, 340 CurvePreferences: []CurveID{CurveP384}, 341 Bugs: ProtocolBugs{ 342 SendCurve: CurveP256, 343 }, 344 }, 345 flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, 346 shouldFail: true, 347 expectedError: ":WRONG_CURVE:", 348 }) 349 350 // The previous curve ID should be reported on TLS 1.2 resumption. 351 testCases = append(testCases, testCase{ 352 name: "CurveID-Resume-Client", 353 config: Config{ 354 MaxVersion: VersionTLS12, 355 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, 356 CurvePreferences: []CurveID{CurveX25519}, 357 }, 358 flags: []string{"-expect-curve-id", strconv.Itoa(int(CurveX25519))}, 359 resumeSession: true, 360 }) 361 testCases = append(testCases, testCase{ 362 testType: serverTest, 363 name: "CurveID-Resume-Server", 364 config: Config{ 365 MaxVersion: VersionTLS12, 366 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, 367 CurvePreferences: []CurveID{CurveX25519}, 368 }, 369 flags: []string{"-expect-curve-id", strconv.Itoa(int(CurveX25519))}, 370 resumeSession: true, 371 }) 372 373 // TLS 1.3 allows resuming at a differet curve. If this happens, the new 374 // one should be reported. 375 testCases = append(testCases, testCase{ 376 name: "CurveID-Resume-Client-TLS13", 377 config: Config{ 378 MaxVersion: VersionTLS13, 379 CurvePreferences: []CurveID{CurveX25519}, 380 }, 381 resumeConfig: &Config{ 382 MaxVersion: VersionTLS13, 383 CurvePreferences: []CurveID{CurveP256}, 384 }, 385 flags: []string{ 386 "-on-initial-expect-curve-id", strconv.Itoa(int(CurveX25519)), 387 "-on-resume-expect-curve-id", strconv.Itoa(int(CurveP256)), 388 }, 389 resumeSession: true, 390 }) 391 testCases = append(testCases, testCase{ 392 testType: serverTest, 393 name: "CurveID-Resume-Server-TLS13", 394 config: Config{ 395 MaxVersion: VersionTLS13, 396 CurvePreferences: []CurveID{CurveX25519}, 397 }, 398 resumeConfig: &Config{ 399 MaxVersion: VersionTLS13, 400 CurvePreferences: []CurveID{CurveP256}, 401 }, 402 flags: []string{ 403 "-on-initial-expect-curve-id", strconv.Itoa(int(CurveX25519)), 404 "-on-resume-expect-curve-id", strconv.Itoa(int(CurveP256)), 405 }, 406 resumeSession: true, 407 }) 408 409 // Server-sent point formats are legal in TLS 1.2, but not in TLS 1.3. 410 testCases = append(testCases, testCase{ 411 name: "PointFormat-ServerHello-TLS12", 412 config: Config{ 413 MaxVersion: VersionTLS12, 414 Bugs: ProtocolBugs{ 415 SendSupportedPointFormats: []byte{pointFormatUncompressed}, 416 }, 417 }, 418 }) 419 testCases = append(testCases, testCase{ 420 name: "PointFormat-EncryptedExtensions-TLS13", 421 config: Config{ 422 MaxVersion: VersionTLS13, 423 Bugs: ProtocolBugs{ 424 SendSupportedPointFormats: []byte{pointFormatUncompressed}, 425 }, 426 }, 427 shouldFail: true, 428 expectedError: ":ERROR_PARSING_EXTENSION:", 429 }) 430 431 // Server-sent supported groups/curves are legal in TLS 1.3. They are 432 // illegal in TLS 1.2, but some servers send them anyway, so we must 433 // tolerate them. 434 testCases = append(testCases, testCase{ 435 name: "SupportedCurves-ServerHello-TLS12", 436 config: Config{ 437 MaxVersion: VersionTLS12, 438 Bugs: ProtocolBugs{ 439 SendServerSupportedCurves: true, 440 }, 441 }, 442 }) 443 testCases = append(testCases, testCase{ 444 name: "SupportedCurves-EncryptedExtensions-TLS13", 445 config: Config{ 446 MaxVersion: VersionTLS13, 447 Bugs: ProtocolBugs{ 448 SendServerSupportedCurves: true, 449 }, 450 }, 451 }) 452 453 // Test that we tolerate unknown point formats, as long as 454 // pointFormatUncompressed is present. Limit ciphers to ECDHE ciphers to 455 // check they are still functional. 456 testCases = append(testCases, testCase{ 457 name: "PointFormat-Client-Tolerance", 458 config: Config{ 459 MaxVersion: VersionTLS12, 460 Bugs: ProtocolBugs{ 461 SendSupportedPointFormats: []byte{42, pointFormatUncompressed, 99, pointFormatCompressedPrime}, 462 }, 463 }, 464 }) 465 testCases = append(testCases, testCase{ 466 testType: serverTest, 467 name: "PointFormat-Server-Tolerance", 468 config: Config{ 469 MaxVersion: VersionTLS12, 470 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, 471 Bugs: ProtocolBugs{ 472 SendSupportedPointFormats: []byte{42, pointFormatUncompressed, 99, pointFormatCompressedPrime}, 473 }, 474 }, 475 }) 476 477 // Test TLS 1.2 does not require the point format extension to be 478 // present. 479 testCases = append(testCases, testCase{ 480 name: "PointFormat-Client-Missing", 481 config: Config{ 482 MaxVersion: VersionTLS12, 483 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, 484 Bugs: ProtocolBugs{ 485 SendSupportedPointFormats: []byte{}, 486 }, 487 }, 488 }) 489 testCases = append(testCases, testCase{ 490 testType: serverTest, 491 name: "PointFormat-Server-Missing", 492 config: Config{ 493 MaxVersion: VersionTLS12, 494 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, 495 Bugs: ProtocolBugs{ 496 SendSupportedPointFormats: []byte{}, 497 }, 498 }, 499 }) 500 501 // If the point format extension is present, uncompressed points must be 502 // offered. BoringSSL requires this whether or not ECDHE is used. 503 testCases = append(testCases, testCase{ 504 name: "PointFormat-Client-MissingUncompressed", 505 config: Config{ 506 MaxVersion: VersionTLS12, 507 Bugs: ProtocolBugs{ 508 SendSupportedPointFormats: []byte{pointFormatCompressedPrime}, 509 }, 510 }, 511 shouldFail: true, 512 expectedError: ":ERROR_PARSING_EXTENSION:", 513 }) 514 testCases = append(testCases, testCase{ 515 testType: serverTest, 516 name: "PointFormat-Server-MissingUncompressed", 517 config: Config{ 518 MaxVersion: VersionTLS12, 519 Bugs: ProtocolBugs{ 520 SendSupportedPointFormats: []byte{pointFormatCompressedPrime}, 521 }, 522 }, 523 shouldFail: true, 524 expectedError: ":ERROR_PARSING_EXTENSION:", 525 }) 526 527 // Post-quantum groups require TLS 1.3. 528 for _, curve := range testCurves { 529 if !isPqGroup(curve.id) { 530 continue 531 } 532 533 // Post-quantum groups should not be offered by a TLS 1.2 client. 534 testCases = append(testCases, testCase{ 535 name: "TLS12ClientShouldNotOffer-" + curve.name, 536 config: Config{ 537 Bugs: ProtocolBugs{ 538 FailIfPostQuantumOffered: true, 539 }, 540 }, 541 flags: []string{ 542 "-max-version", strconv.Itoa(VersionTLS12), 543 "-curves", strconv.Itoa(int(curve.id)), 544 "-curves", strconv.Itoa(int(CurveX25519)), 545 }, 546 }) 547 548 // Post-quantum groups should not be selected by a TLS 1.2 server. 549 testCases = append(testCases, testCase{ 550 testType: serverTest, 551 name: "TLS12ServerShouldNotSelect-" + curve.name, 552 flags: []string{ 553 "-max-version", strconv.Itoa(VersionTLS12), 554 "-curves", strconv.Itoa(int(curve.id)), 555 "-curves", strconv.Itoa(int(CurveX25519)), 556 }, 557 expectations: connectionExpectations{ 558 curveID: CurveX25519, 559 }, 560 }) 561 562 // If a TLS 1.2 server selects a post-quantum group anyway, the client 563 // should not accept it. 564 testCases = append(testCases, testCase{ 565 name: "ClientShouldNotAllowInTLS12-" + curve.name, 566 config: Config{ 567 MaxVersion: VersionTLS12, 568 Bugs: ProtocolBugs{ 569 SendCurve: curve.id, 570 }, 571 }, 572 flags: []string{ 573 "-curves", strconv.Itoa(int(curve.id)), 574 "-curves", strconv.Itoa(int(CurveX25519)), 575 }, 576 shouldFail: true, 577 expectedError: ":WRONG_CURVE:", 578 expectedLocalError: "remote error: illegal parameter", 579 }) 580 } 581 582 // ML-KEM and Kyber should not be offered by default as a client. 583 testCases = append(testCases, testCase{ 584 name: "PostQuantumNotEnabledByDefaultInClients", 585 config: Config{ 586 MinVersion: VersionTLS13, 587 Bugs: ProtocolBugs{ 588 FailIfPostQuantumOffered: true, 589 }, 590 }, 591 }) 592 593 for _, curve := range testCurves { 594 if !isMLKEMGroup(curve.id) { 595 continue 596 } 597 598 // If ML-KEM is offered, both X25519 and ML-KEM should have a key-share. 599 testCases = append(testCases, testCase{ 600 name: "NotJustMLKEMKeyShare-" + curve.name, 601 config: Config{ 602 MinVersion: VersionTLS13, 603 Bugs: ProtocolBugs{ 604 ExpectedKeyShares: []CurveID{curve.id, CurveX25519}, 605 }, 606 }, 607 flags: []string{ 608 "-curves", strconv.Itoa(int(curve.id)), 609 "-curves", strconv.Itoa(int(CurveX25519)), 610 "-expect-curve-id", strconv.Itoa(int(curve.id)), 611 }, 612 }) 613 614 // ... and the other way around 615 testCases = append(testCases, testCase{ 616 name: "MLKEMKeyShareIncludedSecond-" + curve.name, 617 config: Config{ 618 MinVersion: VersionTLS13, 619 Bugs: ProtocolBugs{ 620 ExpectedKeyShares: []CurveID{CurveX25519, curve.id}, 621 }, 622 }, 623 flags: []string{ 624 "-curves", strconv.Itoa(int(CurveX25519)), 625 "-curves", strconv.Itoa(int(curve.id)), 626 "-expect-curve-id", strconv.Itoa(int(CurveX25519)), 627 }, 628 }) 629 630 // ... and even if there's another curve in the middle because it's the 631 // first classical and first post-quantum "curves" that get key shares 632 // included. 633 testCases = append(testCases, testCase{ 634 name: "MLKEMKeyShareIncludedThird-" + curve.name, 635 config: Config{ 636 MinVersion: VersionTLS13, 637 Bugs: ProtocolBugs{ 638 ExpectedKeyShares: []CurveID{CurveX25519, curve.id}, 639 }, 640 }, 641 flags: []string{ 642 "-curves", strconv.Itoa(int(CurveX25519)), 643 "-curves", strconv.Itoa(int(CurveP256)), 644 "-curves", strconv.Itoa(int(curve.id)), 645 "-expect-curve-id", strconv.Itoa(int(CurveX25519)), 646 }, 647 }) 648 649 // If ML-KEM is the only configured curve, the key share is sent. 650 testCases = append(testCases, testCase{ 651 name: "JustConfiguringMLKEMWorks-" + curve.name, 652 config: Config{ 653 MinVersion: VersionTLS13, 654 Bugs: ProtocolBugs{ 655 ExpectedKeyShares: []CurveID{curve.id}, 656 }, 657 }, 658 flags: []string{ 659 "-curves", strconv.Itoa(int(curve.id)), 660 "-expect-curve-id", strconv.Itoa(int(curve.id)), 661 }, 662 }) 663 664 // If both ML-KEM and Kyber are configured, only the preferred one's 665 // key share should be sent. 666 testCases = append(testCases, testCase{ 667 name: "BothMLKEMAndKyber-" + curve.name, 668 config: Config{ 669 MinVersion: VersionTLS13, 670 Bugs: ProtocolBugs{ 671 ExpectedKeyShares: []CurveID{curve.id}, 672 }, 673 }, 674 flags: []string{ 675 "-curves", strconv.Itoa(int(curve.id)), 676 "-curves", strconv.Itoa(int(CurveX25519Kyber768)), 677 "-expect-curve-id", strconv.Itoa(int(curve.id)), 678 }, 679 }) 680 } 681 682 // As a server, ML-KEMs and Kyber are not yet supported by default. 683 testCases = append(testCases, testCase{ 684 testType: serverTest, 685 name: "PostQuantumNotEnabledByDefaultForAServer", 686 config: Config{ 687 MinVersion: VersionTLS13, 688 CurvePreferences: []CurveID{CurveX25519MLKEM768, CurveMLKEM1024, CurveX25519Kyber768, CurveX25519}, 689 DefaultCurves: []CurveID{CurveX25519MLKEM768, CurveMLKEM1024, CurveX25519Kyber768}, 690 }, 691 flags: []string{ 692 "-server-preference", 693 "-expect-curve-id", strconv.Itoa(int(CurveX25519)), 694 }, 695 }) 696 697 // If two ML-KEMs are configured, only the preferred one's 698 // key share should be sent. 699 testCases = append(testCases, testCase{ 700 name: "TwoMLKEMs", 701 config: Config{ 702 MinVersion: VersionTLS13, 703 Bugs: ProtocolBugs{ 704 ExpectedKeyShares: []CurveID{CurveMLKEM1024}, 705 }, 706 }, 707 flags: []string{ 708 "-curves", strconv.Itoa(int(CurveMLKEM1024)), 709 "-curves", strconv.Itoa(int(CurveX25519MLKEM768)), 710 "-expect-curve-id", strconv.Itoa(int(CurveMLKEM1024)), 711 }, 712 }) 713 714 // In TLS 1.2, the curve list is also used to signal ECDSA curves. 715 testCases = append(testCases, testCase{ 716 testType: serverTest, 717 name: "CheckECDSACurve-TLS12", 718 config: Config{ 719 MinVersion: VersionTLS12, 720 MaxVersion: VersionTLS12, 721 CurvePreferences: []CurveID{CurveP384}, 722 }, 723 shimCertificate: &ecdsaP256Certificate, 724 shouldFail: true, 725 expectedError: ":WRONG_CURVE:", 726 }) 727 728 // If the ECDSA certificate is ineligible due to a curve mismatch, the 729 // server may still consider a PSK cipher suite. 730 testCases = append(testCases, testCase{ 731 testType: serverTest, 732 name: "CheckECDSACurve-PSK-TLS12", 733 config: Config{ 734 MinVersion: VersionTLS12, 735 MaxVersion: VersionTLS12, 736 CipherSuites: []uint16{ 737 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 738 TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, 739 }, 740 CurvePreferences: []CurveID{CurveP384}, 741 PreSharedKey: []byte("12345"), 742 PreSharedKeyIdentity: "luggage combo", 743 }, 744 shimCertificate: &ecdsaP256Certificate, 745 expectations: connectionExpectations{ 746 cipher: TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, 747 }, 748 flags: []string{ 749 "-psk", "12345", 750 "-psk-identity", "luggage combo", 751 }, 752 }) 753 754 // In TLS 1.3, the curve list only controls ECDH. 755 testCases = append(testCases, testCase{ 756 testType: serverTest, 757 name: "CheckECDSACurve-NotApplicable-TLS13", 758 config: Config{ 759 MinVersion: VersionTLS13, 760 MaxVersion: VersionTLS13, 761 CurvePreferences: []CurveID{CurveP384}, 762 }, 763 shimCertificate: &ecdsaP256Certificate, 764 }) 765} 766