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) 20 21func addExtensionTests() { 22 exampleCertificate := rootCA.Issue(X509Info{ 23 PrivateKey: &ecdsaP256Key, 24 DNSNames: []string{"example.com"}, 25 }).ToCredential() 26 27 // Repeat extensions tests at all versions. 28 for _, protocol := range []protocol{tls, dtls, quic} { 29 for _, ver := range allVersions(protocol) { 30 suffix := fmt.Sprintf("%s-%s", protocol.String(), ver.name) 31 32 // Test that duplicate extensions are rejected. 33 testCases = append(testCases, testCase{ 34 protocol: protocol, 35 testType: clientTest, 36 name: "DuplicateExtensionClient-" + suffix, 37 config: Config{ 38 MaxVersion: ver.version, 39 Bugs: ProtocolBugs{ 40 DuplicateExtension: true, 41 }, 42 }, 43 shouldFail: true, 44 expectedLocalError: "remote error: error decoding message", 45 }) 46 testCases = append(testCases, testCase{ 47 protocol: protocol, 48 testType: serverTest, 49 name: "DuplicateExtensionServer-" + suffix, 50 config: Config{ 51 MaxVersion: ver.version, 52 Bugs: ProtocolBugs{ 53 DuplicateExtension: true, 54 }, 55 }, 56 shouldFail: true, 57 expectedLocalError: "remote error: error decoding message", 58 }) 59 60 // Test SNI. 61 testCases = append(testCases, testCase{ 62 protocol: protocol, 63 testType: clientTest, 64 name: "ServerNameExtensionClient-" + suffix, 65 config: Config{ 66 MaxVersion: ver.version, 67 Bugs: ProtocolBugs{ 68 ExpectServerName: "example.com", 69 }, 70 Credential: &exampleCertificate, 71 }, 72 flags: []string{"-host-name", "example.com"}, 73 }) 74 testCases = append(testCases, testCase{ 75 protocol: protocol, 76 testType: clientTest, 77 name: "ServerNameExtensionClientMismatch-" + suffix, 78 config: Config{ 79 MaxVersion: ver.version, 80 Bugs: ProtocolBugs{ 81 ExpectServerName: "mismatch.com", 82 }, 83 }, 84 flags: []string{"-host-name", "example.com"}, 85 shouldFail: true, 86 expectedLocalError: "tls: unexpected server name", 87 }) 88 testCases = append(testCases, testCase{ 89 protocol: protocol, 90 testType: clientTest, 91 name: "ServerNameExtensionClientMissing-" + suffix, 92 config: Config{ 93 MaxVersion: ver.version, 94 Bugs: ProtocolBugs{ 95 ExpectServerName: "missing.com", 96 }, 97 }, 98 shouldFail: true, 99 expectedLocalError: "tls: unexpected server name", 100 }) 101 testCases = append(testCases, testCase{ 102 protocol: protocol, 103 testType: clientTest, 104 name: "TolerateServerNameAck-" + suffix, 105 config: Config{ 106 MaxVersion: ver.version, 107 Bugs: ProtocolBugs{ 108 SendServerNameAck: true, 109 }, 110 Credential: &exampleCertificate, 111 }, 112 flags: []string{"-host-name", "example.com"}, 113 resumeSession: true, 114 }) 115 testCases = append(testCases, testCase{ 116 protocol: protocol, 117 testType: clientTest, 118 name: "UnsolicitedServerNameAck-" + suffix, 119 config: Config{ 120 MaxVersion: ver.version, 121 Bugs: ProtocolBugs{ 122 SendServerNameAck: true, 123 }, 124 }, 125 shouldFail: true, 126 expectedError: ":UNEXPECTED_EXTENSION:", 127 expectedLocalError: "remote error: unsupported extension", 128 }) 129 testCases = append(testCases, testCase{ 130 protocol: protocol, 131 testType: serverTest, 132 name: "ServerNameExtensionServer-" + suffix, 133 config: Config{ 134 MaxVersion: ver.version, 135 ServerName: "example.com", 136 }, 137 flags: []string{"-expect-server-name", "example.com"}, 138 resumeSession: true, 139 expectations: connectionExpectations{ 140 serverNameAck: ptrTo(true), 141 }, 142 }) 143 testCases = append(testCases, testCase{ 144 protocol: protocol, 145 testType: serverTest, 146 name: "ServerNameExtensionServer-NoACK-" + suffix, 147 config: Config{ 148 MaxVersion: ver.version, 149 ServerName: "example.com", 150 }, 151 flags: []string{ 152 "-expect-server-name", "example.com", 153 "-no-server-name-ack", 154 }, 155 resumeSession: true, 156 expectations: connectionExpectations{ 157 serverNameAck: ptrTo(false), 158 }, 159 }) 160 161 // Test ALPN. 162 testCases = append(testCases, testCase{ 163 protocol: protocol, 164 testType: clientTest, 165 skipQUICALPNConfig: true, 166 name: "ALPNClient-" + suffix, 167 config: Config{ 168 MaxVersion: ver.version, 169 NextProtos: []string{"foo"}, 170 }, 171 flags: []string{ 172 "-advertise-alpn", "\x03foo\x03bar\x03baz", 173 "-expect-alpn", "foo", 174 }, 175 expectations: connectionExpectations{ 176 nextProto: "foo", 177 nextProtoType: alpn, 178 }, 179 resumeSession: true, 180 }) 181 testCases = append(testCases, testCase{ 182 protocol: protocol, 183 testType: clientTest, 184 skipQUICALPNConfig: true, 185 name: "ALPNClient-RejectUnknown-" + suffix, 186 config: Config{ 187 MaxVersion: ver.version, 188 Bugs: ProtocolBugs{ 189 SendALPN: "baz", 190 }, 191 }, 192 flags: []string{ 193 "-advertise-alpn", "\x03foo\x03bar", 194 }, 195 shouldFail: true, 196 expectedError: ":INVALID_ALPN_PROTOCOL:", 197 expectedLocalError: "remote error: illegal parameter", 198 }) 199 testCases = append(testCases, testCase{ 200 protocol: protocol, 201 testType: clientTest, 202 skipQUICALPNConfig: true, 203 name: "ALPNClient-AllowUnknown-" + suffix, 204 config: Config{ 205 MaxVersion: ver.version, 206 Bugs: ProtocolBugs{ 207 SendALPN: "baz", 208 }, 209 }, 210 flags: []string{ 211 "-advertise-alpn", "\x03foo\x03bar", 212 "-allow-unknown-alpn-protos", 213 "-expect-alpn", "baz", 214 }, 215 }) 216 testCases = append(testCases, testCase{ 217 protocol: protocol, 218 testType: serverTest, 219 skipQUICALPNConfig: true, 220 name: "ALPNServer-" + suffix, 221 config: Config{ 222 MaxVersion: ver.version, 223 NextProtos: []string{"foo", "bar", "baz"}, 224 }, 225 flags: []string{ 226 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz", 227 "-select-alpn", "foo", 228 }, 229 expectations: connectionExpectations{ 230 nextProto: "foo", 231 nextProtoType: alpn, 232 }, 233 resumeSession: true, 234 }) 235 236 var shouldDeclineALPNFail bool 237 var declineALPNError, declineALPNLocalError string 238 if protocol == quic { 239 // ALPN is mandatory in QUIC. 240 shouldDeclineALPNFail = true 241 declineALPNError = ":NO_APPLICATION_PROTOCOL:" 242 declineALPNLocalError = "remote error: no application protocol" 243 } 244 testCases = append(testCases, testCase{ 245 protocol: protocol, 246 testType: serverTest, 247 skipQUICALPNConfig: true, 248 name: "ALPNServer-Decline-" + suffix, 249 config: Config{ 250 MaxVersion: ver.version, 251 NextProtos: []string{"foo", "bar", "baz"}, 252 }, 253 flags: []string{"-decline-alpn"}, 254 expectations: connectionExpectations{ 255 noNextProto: true, 256 }, 257 resumeSession: true, 258 shouldFail: shouldDeclineALPNFail, 259 expectedError: declineALPNError, 260 expectedLocalError: declineALPNLocalError, 261 }) 262 263 testCases = append(testCases, testCase{ 264 protocol: protocol, 265 testType: serverTest, 266 skipQUICALPNConfig: true, 267 name: "ALPNServer-Reject-" + suffix, 268 config: Config{ 269 MaxVersion: ver.version, 270 NextProtos: []string{"foo", "bar", "baz"}, 271 }, 272 flags: []string{"-reject-alpn"}, 273 shouldFail: true, 274 expectedError: ":NO_APPLICATION_PROTOCOL:", 275 expectedLocalError: "remote error: no application protocol", 276 }) 277 278 // Test that the server implementation catches itself if the 279 // callback tries to return an invalid empty ALPN protocol. 280 testCases = append(testCases, testCase{ 281 protocol: protocol, 282 testType: serverTest, 283 skipQUICALPNConfig: true, 284 name: "ALPNServer-SelectEmpty-" + suffix, 285 config: Config{ 286 MaxVersion: ver.version, 287 NextProtos: []string{"foo", "bar", "baz"}, 288 }, 289 flags: []string{ 290 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz", 291 "-select-empty-alpn", 292 }, 293 shouldFail: true, 294 expectedLocalError: "remote error: internal error", 295 expectedError: ":INVALID_ALPN_PROTOCOL:", 296 }) 297 298 // Test ALPN in async mode as well to ensure that extensions callbacks are only 299 // called once. 300 testCases = append(testCases, testCase{ 301 protocol: protocol, 302 testType: serverTest, 303 skipQUICALPNConfig: true, 304 name: "ALPNServer-Async-" + suffix, 305 config: Config{ 306 MaxVersion: ver.version, 307 NextProtos: []string{"foo", "bar", "baz"}, 308 // Prior to TLS 1.3, exercise the asynchronous session callback. 309 SessionTicketsDisabled: ver.version < VersionTLS13, 310 }, 311 flags: []string{ 312 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz", 313 "-select-alpn", "foo", 314 "-async", 315 }, 316 expectations: connectionExpectations{ 317 nextProto: "foo", 318 nextProtoType: alpn, 319 }, 320 resumeSession: true, 321 }) 322 323 var emptyString string 324 testCases = append(testCases, testCase{ 325 protocol: protocol, 326 testType: clientTest, 327 skipQUICALPNConfig: true, 328 name: "ALPNClient-EmptyProtocolName-" + suffix, 329 config: Config{ 330 MaxVersion: ver.version, 331 NextProtos: []string{""}, 332 Bugs: ProtocolBugs{ 333 // A server returning an empty ALPN protocol 334 // should be rejected. 335 ALPNProtocol: &emptyString, 336 }, 337 }, 338 flags: []string{ 339 "-advertise-alpn", "\x03foo", 340 }, 341 shouldFail: true, 342 expectedError: ":PARSE_TLSEXT:", 343 }) 344 testCases = append(testCases, testCase{ 345 protocol: protocol, 346 testType: serverTest, 347 skipQUICALPNConfig: true, 348 name: "ALPNServer-EmptyProtocolName-" + suffix, 349 config: Config{ 350 MaxVersion: ver.version, 351 // A ClientHello containing an empty ALPN protocol 352 // should be rejected. 353 NextProtos: []string{"foo", "", "baz"}, 354 }, 355 flags: []string{ 356 "-select-alpn", "foo", 357 }, 358 shouldFail: true, 359 expectedError: ":PARSE_TLSEXT:", 360 }) 361 362 // Test NPN and the interaction with ALPN. 363 if ver.version < VersionTLS13 && protocol == tls { 364 // Test that the server prefers ALPN over NPN. 365 testCases = append(testCases, testCase{ 366 protocol: protocol, 367 testType: serverTest, 368 name: "ALPNServer-Preferred-" + suffix, 369 config: Config{ 370 MaxVersion: ver.version, 371 NextProtos: []string{"foo", "bar", "baz"}, 372 }, 373 flags: []string{ 374 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz", 375 "-select-alpn", "foo", 376 "-advertise-npn", "\x03foo\x03bar\x03baz", 377 }, 378 expectations: connectionExpectations{ 379 nextProto: "foo", 380 nextProtoType: alpn, 381 }, 382 resumeSession: true, 383 }) 384 testCases = append(testCases, testCase{ 385 protocol: protocol, 386 testType: serverTest, 387 name: "ALPNServer-Preferred-Swapped-" + suffix, 388 config: Config{ 389 MaxVersion: ver.version, 390 NextProtos: []string{"foo", "bar", "baz"}, 391 Bugs: ProtocolBugs{ 392 SwapNPNAndALPN: true, 393 }, 394 }, 395 flags: []string{ 396 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz", 397 "-select-alpn", "foo", 398 "-advertise-npn", "\x03foo\x03bar\x03baz", 399 }, 400 expectations: connectionExpectations{ 401 nextProto: "foo", 402 nextProtoType: alpn, 403 }, 404 resumeSession: true, 405 }) 406 407 // Test that negotiating both NPN and ALPN is forbidden. 408 testCases = append(testCases, testCase{ 409 protocol: protocol, 410 name: "NegotiateALPNAndNPN-" + suffix, 411 config: Config{ 412 MaxVersion: ver.version, 413 NextProtos: []string{"foo", "bar", "baz"}, 414 Bugs: ProtocolBugs{ 415 NegotiateALPNAndNPN: true, 416 }, 417 }, 418 flags: []string{ 419 "-advertise-alpn", "\x03foo", 420 "-select-next-proto", "foo", 421 }, 422 shouldFail: true, 423 expectedError: ":NEGOTIATED_BOTH_NPN_AND_ALPN:", 424 }) 425 testCases = append(testCases, testCase{ 426 protocol: protocol, 427 name: "NegotiateALPNAndNPN-Swapped-" + suffix, 428 config: Config{ 429 MaxVersion: ver.version, 430 NextProtos: []string{"foo", "bar", "baz"}, 431 Bugs: ProtocolBugs{ 432 NegotiateALPNAndNPN: true, 433 SwapNPNAndALPN: true, 434 }, 435 }, 436 flags: []string{ 437 "-advertise-alpn", "\x03foo", 438 "-select-next-proto", "foo", 439 }, 440 shouldFail: true, 441 expectedError: ":NEGOTIATED_BOTH_NPN_AND_ALPN:", 442 }) 443 } 444 445 // Test missing ALPN in QUIC 446 if protocol == quic { 447 testCases = append(testCases, testCase{ 448 testType: clientTest, 449 protocol: protocol, 450 name: "Client-ALPNMissingFromConfig-" + suffix, 451 config: Config{ 452 MinVersion: ver.version, 453 MaxVersion: ver.version, 454 }, 455 skipQUICALPNConfig: true, 456 shouldFail: true, 457 expectedError: ":NO_APPLICATION_PROTOCOL:", 458 }) 459 testCases = append(testCases, testCase{ 460 testType: clientTest, 461 protocol: protocol, 462 name: "Client-ALPNMissing-" + suffix, 463 config: Config{ 464 MinVersion: ver.version, 465 MaxVersion: ver.version, 466 }, 467 flags: []string{ 468 "-advertise-alpn", "\x03foo", 469 }, 470 skipQUICALPNConfig: true, 471 shouldFail: true, 472 expectedError: ":NO_APPLICATION_PROTOCOL:", 473 expectedLocalError: "remote error: no application protocol", 474 }) 475 testCases = append(testCases, testCase{ 476 testType: serverTest, 477 protocol: protocol, 478 name: "Server-ALPNMissing-" + suffix, 479 config: Config{ 480 MinVersion: ver.version, 481 MaxVersion: ver.version, 482 }, 483 skipQUICALPNConfig: true, 484 shouldFail: true, 485 expectedError: ":NO_APPLICATION_PROTOCOL:", 486 expectedLocalError: "remote error: no application protocol", 487 }) 488 testCases = append(testCases, testCase{ 489 testType: serverTest, 490 protocol: protocol, 491 name: "Server-ALPNMismatch-" + suffix, 492 config: Config{ 493 MinVersion: ver.version, 494 MaxVersion: ver.version, 495 NextProtos: []string{"foo"}, 496 }, 497 flags: []string{ 498 "-decline-alpn", 499 }, 500 skipQUICALPNConfig: true, 501 shouldFail: true, 502 expectedError: ":NO_APPLICATION_PROTOCOL:", 503 expectedLocalError: "remote error: no application protocol", 504 }) 505 } 506 507 // Test ALPS. 508 if ver.version >= VersionTLS13 { 509 // Test basic client with different ALPS codepoint. 510 for _, alpsCodePoint := range []ALPSUseCodepoint{ALPSUseCodepointNew, ALPSUseCodepointOld} { 511 useAlpsCodepointFlag := "0" 512 if alpsCodePoint == ALPSUseCodepointNew { 513 useAlpsCodepointFlag = "1" 514 } 515 516 flags := []string{"-alps-use-new-codepoint", useAlpsCodepointFlag} 517 expectations := connectionExpectations{ 518 peerApplicationSettingsOld: []byte("shim1"), 519 } 520 resumeExpectations := &connectionExpectations{ 521 peerApplicationSettingsOld: []byte("shim2"), 522 } 523 524 if alpsCodePoint == ALPSUseCodepointNew { 525 expectations = connectionExpectations{ 526 peerApplicationSettings: []byte("shim1"), 527 } 528 resumeExpectations = &connectionExpectations{ 529 peerApplicationSettings: []byte("shim2"), 530 } 531 } 532 533 flags = append(flags, 534 "-advertise-alpn", "\x05proto", 535 "-expect-alpn", "proto", 536 "-on-initial-application-settings", "proto,shim1", 537 "-on-initial-expect-peer-application-settings", "runner1", 538 "-on-resume-application-settings", "proto,shim2", 539 "-on-resume-expect-peer-application-settings", "runner2") 540 541 // Test that server can negotiate ALPS, including different values 542 // on resumption. 543 testCases = append(testCases, testCase{ 544 protocol: protocol, 545 testType: clientTest, 546 name: fmt.Sprintf("ALPS-Basic-Client-%s-%s", alpsCodePoint, suffix), 547 skipQUICALPNConfig: true, 548 config: Config{ 549 MaxVersion: ver.version, 550 NextProtos: []string{"proto"}, 551 ApplicationSettings: map[string][]byte{"proto": []byte("runner1")}, 552 ALPSUseNewCodepoint: alpsCodePoint, 553 }, 554 resumeConfig: &Config{ 555 MaxVersion: ver.version, 556 NextProtos: []string{"proto"}, 557 ApplicationSettings: map[string][]byte{"proto": []byte("runner2")}, 558 ALPSUseNewCodepoint: alpsCodePoint, 559 }, 560 resumeSession: true, 561 expectations: expectations, 562 resumeExpectations: resumeExpectations, 563 flags: flags, 564 }) 565 566 // Test basic server with different ALPS codepoint. 567 flags = []string{"-alps-use-new-codepoint", useAlpsCodepointFlag} 568 expectations = connectionExpectations{ 569 peerApplicationSettingsOld: []byte("shim1"), 570 } 571 resumeExpectations = &connectionExpectations{ 572 peerApplicationSettingsOld: []byte("shim2"), 573 } 574 575 if alpsCodePoint == ALPSUseCodepointNew { 576 expectations = connectionExpectations{ 577 peerApplicationSettings: []byte("shim1"), 578 } 579 resumeExpectations = &connectionExpectations{ 580 peerApplicationSettings: []byte("shim2"), 581 } 582 } 583 584 flags = append(flags, 585 "-select-alpn", "proto", 586 "-on-initial-application-settings", "proto,shim1", 587 "-on-initial-expect-peer-application-settings", "runner1", 588 "-on-resume-application-settings", "proto,shim2", 589 "-on-resume-expect-peer-application-settings", "runner2") 590 591 // Test that server can negotiate ALPS, including different values 592 // on resumption. 593 testCases = append(testCases, testCase{ 594 protocol: protocol, 595 testType: serverTest, 596 name: fmt.Sprintf("ALPS-Basic-Server-%s-%s", alpsCodePoint, suffix), 597 skipQUICALPNConfig: true, 598 config: Config{ 599 MaxVersion: ver.version, 600 NextProtos: []string{"proto"}, 601 ApplicationSettings: map[string][]byte{"proto": []byte("runner1")}, 602 ALPSUseNewCodepoint: alpsCodePoint, 603 }, 604 resumeConfig: &Config{ 605 MaxVersion: ver.version, 606 NextProtos: []string{"proto"}, 607 ApplicationSettings: map[string][]byte{"proto": []byte("runner2")}, 608 ALPSUseNewCodepoint: alpsCodePoint, 609 }, 610 resumeSession: true, 611 expectations: expectations, 612 resumeExpectations: resumeExpectations, 613 flags: flags, 614 }) 615 616 // Try different ALPS codepoint for all the existing tests. 617 alpsFlags := []string{"-alps-use-new-codepoint", useAlpsCodepointFlag} 618 expectations = connectionExpectations{ 619 peerApplicationSettingsOld: []byte("shim1"), 620 } 621 resumeExpectations = &connectionExpectations{ 622 peerApplicationSettingsOld: []byte("shim2"), 623 } 624 if alpsCodePoint == ALPSUseCodepointNew { 625 expectations = connectionExpectations{ 626 peerApplicationSettings: []byte("shim1"), 627 } 628 resumeExpectations = &connectionExpectations{ 629 peerApplicationSettings: []byte("shim2"), 630 } 631 } 632 633 // Test that the server can defer its ALPS configuration to the ALPN 634 // selection callback. 635 testCases = append(testCases, testCase{ 636 protocol: protocol, 637 testType: serverTest, 638 name: fmt.Sprintf("ALPS-Basic-Server-Defer-%s-%s", alpsCodePoint, suffix), 639 skipQUICALPNConfig: true, 640 config: Config{ 641 MaxVersion: ver.version, 642 NextProtos: []string{"proto"}, 643 ApplicationSettings: map[string][]byte{"proto": []byte("runner1")}, 644 ALPSUseNewCodepoint: alpsCodePoint, 645 }, 646 resumeConfig: &Config{ 647 MaxVersion: ver.version, 648 NextProtos: []string{"proto"}, 649 ApplicationSettings: map[string][]byte{"proto": []byte("runner2")}, 650 ALPSUseNewCodepoint: alpsCodePoint, 651 }, 652 resumeSession: true, 653 expectations: expectations, 654 resumeExpectations: resumeExpectations, 655 flags: append([]string{ 656 "-select-alpn", "proto", 657 "-defer-alps", 658 "-on-initial-application-settings", "proto,shim1", 659 "-on-initial-expect-peer-application-settings", "runner1", 660 "-on-resume-application-settings", "proto,shim2", 661 "-on-resume-expect-peer-application-settings", "runner2", 662 }, alpsFlags...), 663 }) 664 665 expectations = connectionExpectations{ 666 peerApplicationSettingsOld: []byte{}, 667 } 668 if alpsCodePoint == ALPSUseCodepointNew { 669 expectations = connectionExpectations{ 670 peerApplicationSettings: []byte{}, 671 } 672 } 673 // Test the client and server correctly handle empty settings. 674 testCases = append(testCases, testCase{ 675 protocol: protocol, 676 testType: clientTest, 677 name: fmt.Sprintf("ALPS-Empty-Client-%s-%s", alpsCodePoint, suffix), 678 skipQUICALPNConfig: true, 679 config: Config{ 680 MaxVersion: ver.version, 681 NextProtos: []string{"proto"}, 682 ApplicationSettings: map[string][]byte{"proto": {}}, 683 ALPSUseNewCodepoint: alpsCodePoint, 684 }, 685 resumeSession: true, 686 expectations: expectations, 687 flags: append([]string{ 688 "-advertise-alpn", "\x05proto", 689 "-expect-alpn", "proto", 690 "-application-settings", "proto,", 691 "-expect-peer-application-settings", "", 692 }, alpsFlags...), 693 }) 694 testCases = append(testCases, testCase{ 695 protocol: protocol, 696 testType: serverTest, 697 name: fmt.Sprintf("ALPS-Empty-Server-%s-%s", alpsCodePoint, suffix), 698 skipQUICALPNConfig: true, 699 config: Config{ 700 MaxVersion: ver.version, 701 NextProtos: []string{"proto"}, 702 ApplicationSettings: map[string][]byte{"proto": {}}, 703 ALPSUseNewCodepoint: alpsCodePoint, 704 }, 705 resumeSession: true, 706 expectations: expectations, 707 flags: append([]string{ 708 "-select-alpn", "proto", 709 "-application-settings", "proto,", 710 "-expect-peer-application-settings", "", 711 }, alpsFlags...), 712 }) 713 714 bugs := ProtocolBugs{ 715 AlwaysNegotiateApplicationSettingsOld: true, 716 } 717 if alpsCodePoint == ALPSUseCodepointNew { 718 bugs = ProtocolBugs{ 719 AlwaysNegotiateApplicationSettingsNew: true, 720 } 721 } 722 // Test the client rejects application settings from the server on 723 // protocols it doesn't have them. 724 testCases = append(testCases, testCase{ 725 protocol: protocol, 726 testType: clientTest, 727 name: fmt.Sprintf("ALPS-UnsupportedProtocol-Client-%s-%s", alpsCodePoint, suffix), 728 skipQUICALPNConfig: true, 729 config: Config{ 730 MaxVersion: ver.version, 731 NextProtos: []string{"proto1"}, 732 ApplicationSettings: map[string][]byte{"proto1": []byte("runner")}, 733 Bugs: bugs, 734 ALPSUseNewCodepoint: alpsCodePoint, 735 }, 736 // The client supports ALPS with "proto2", but not "proto1". 737 flags: append([]string{ 738 "-advertise-alpn", "\x06proto1\x06proto2", 739 "-application-settings", "proto2,shim", 740 "-expect-alpn", "proto1", 741 }, alpsFlags...), 742 // The server sends ALPS with "proto1", which is invalid. 743 shouldFail: true, 744 expectedError: ":INVALID_ALPN_PROTOCOL:", 745 expectedLocalError: "remote error: illegal parameter", 746 }) 747 748 // Test client rejects application settings from the server when 749 // server sends the wrong ALPS codepoint. 750 bugs = ProtocolBugs{ 751 AlwaysNegotiateApplicationSettingsOld: true, 752 } 753 if alpsCodePoint == ALPSUseCodepointOld { 754 bugs = ProtocolBugs{ 755 AlwaysNegotiateApplicationSettingsNew: true, 756 } 757 } 758 759 testCases = append(testCases, testCase{ 760 protocol: protocol, 761 testType: clientTest, 762 name: fmt.Sprintf("ALPS-WrongServerCodepoint-Client-%s-%s", alpsCodePoint, suffix), 763 skipQUICALPNConfig: true, 764 config: Config{ 765 MaxVersion: ver.version, 766 NextProtos: []string{"proto"}, 767 ApplicationSettings: map[string][]byte{"proto": {}}, 768 Bugs: bugs, 769 ALPSUseNewCodepoint: alpsCodePoint, 770 }, 771 flags: append([]string{ 772 "-advertise-alpn", "\x05proto", 773 "-expect-alpn", "proto", 774 "-application-settings", "proto,", 775 "-expect-peer-application-settings", "", 776 }, alpsFlags...), 777 shouldFail: true, 778 expectedError: ":UNEXPECTED_EXTENSION:", 779 expectedLocalError: "remote error: unsupported extension", 780 }) 781 782 // Test server ignore wrong codepoint from client. 783 clientSends := ALPSUseCodepointNew 784 if alpsCodePoint == ALPSUseCodepointNew { 785 clientSends = ALPSUseCodepointOld 786 } 787 788 testCases = append(testCases, testCase{ 789 protocol: protocol, 790 testType: serverTest, 791 name: fmt.Sprintf("ALPS-IgnoreClientWrongCodepoint-Server-%s-%s", alpsCodePoint, suffix), 792 skipQUICALPNConfig: true, 793 config: Config{ 794 MaxVersion: ver.version, 795 NextProtos: []string{"proto"}, 796 ApplicationSettings: map[string][]byte{"proto": []byte("runner1")}, 797 ALPSUseNewCodepoint: clientSends, 798 }, 799 resumeConfig: &Config{ 800 MaxVersion: ver.version, 801 NextProtos: []string{"proto"}, 802 ApplicationSettings: map[string][]byte{"proto": []byte("runner2")}, 803 ALPSUseNewCodepoint: clientSends, 804 }, 805 resumeSession: true, 806 flags: append([]string{ 807 "-select-alpn", "proto", 808 "-on-initial-application-settings", "proto,shim1", 809 "-on-resume-application-settings", "proto,shim2", 810 }, alpsFlags...), 811 }) 812 813 // Test the server declines ALPS if it doesn't support it for the 814 // specified protocol. 815 testCases = append(testCases, testCase{ 816 protocol: protocol, 817 testType: serverTest, 818 name: fmt.Sprintf("ALPS-UnsupportedProtocol-Server-%s-%s", alpsCodePoint, suffix), 819 skipQUICALPNConfig: true, 820 config: Config{ 821 MaxVersion: ver.version, 822 NextProtos: []string{"proto1"}, 823 ApplicationSettings: map[string][]byte{"proto1": []byte("runner")}, 824 ALPSUseNewCodepoint: alpsCodePoint, 825 }, 826 // The server supports ALPS with "proto2", but not "proto1". 827 flags: append([]string{ 828 "-select-alpn", "proto1", 829 "-application-settings", "proto2,shim", 830 }, alpsFlags...), 831 }) 832 833 // Test the client rejects application settings from the server when 834 // it always negotiate both codepoint. 835 testCases = append(testCases, testCase{ 836 protocol: protocol, 837 testType: clientTest, 838 name: fmt.Sprintf("ALPS-UnsupportedProtocol-Client-ServerBoth-%s-%s", alpsCodePoint, suffix), 839 skipQUICALPNConfig: true, 840 config: Config{ 841 MaxVersion: ver.version, 842 NextProtos: []string{"proto1"}, 843 ApplicationSettings: map[string][]byte{"proto1": []byte("runner")}, 844 Bugs: ProtocolBugs{ 845 AlwaysNegotiateApplicationSettingsBoth: true, 846 }, 847 ALPSUseNewCodepoint: alpsCodePoint, 848 }, 849 flags: append([]string{ 850 "-advertise-alpn", "\x06proto1\x06proto2", 851 "-application-settings", "proto1,shim", 852 "-expect-alpn", "proto1", 853 }, alpsFlags...), 854 // The server sends ALPS with both application settings, which is invalid. 855 shouldFail: true, 856 expectedError: ":UNEXPECTED_EXTENSION:", 857 expectedLocalError: "remote error: unsupported extension", 858 }) 859 860 expectations = connectionExpectations{ 861 peerApplicationSettingsOld: []byte("shim"), 862 } 863 if alpsCodePoint == ALPSUseCodepointNew { 864 expectations = connectionExpectations{ 865 peerApplicationSettings: []byte("shim"), 866 } 867 } 868 869 // Test that the server rejects a missing application_settings extension. 870 testCases = append(testCases, testCase{ 871 protocol: protocol, 872 testType: serverTest, 873 name: fmt.Sprintf("ALPS-OmitClientApplicationSettings-%s-%s", alpsCodePoint, suffix), 874 skipQUICALPNConfig: true, 875 config: Config{ 876 MaxVersion: ver.version, 877 NextProtos: []string{"proto"}, 878 ApplicationSettings: map[string][]byte{"proto": []byte("runner")}, 879 Bugs: ProtocolBugs{ 880 OmitClientApplicationSettings: true, 881 }, 882 ALPSUseNewCodepoint: alpsCodePoint, 883 }, 884 flags: append([]string{ 885 "-select-alpn", "proto", 886 "-application-settings", "proto,shim", 887 }, alpsFlags...), 888 // The runner is a client, so it only processes the shim's alert 889 // after checking connection state. 890 expectations: expectations, 891 shouldFail: true, 892 expectedError: ":MISSING_EXTENSION:", 893 expectedLocalError: "remote error: missing extension", 894 }) 895 896 // Test that the server rejects a missing EncryptedExtensions message. 897 testCases = append(testCases, testCase{ 898 protocol: protocol, 899 testType: serverTest, 900 name: fmt.Sprintf("ALPS-OmitClientEncryptedExtensions-%s-%s", alpsCodePoint, suffix), 901 skipQUICALPNConfig: true, 902 config: Config{ 903 MaxVersion: ver.version, 904 NextProtos: []string{"proto"}, 905 ApplicationSettings: map[string][]byte{"proto": []byte("runner")}, 906 Bugs: ProtocolBugs{ 907 OmitClientEncryptedExtensions: true, 908 }, 909 ALPSUseNewCodepoint: alpsCodePoint, 910 }, 911 flags: append([]string{ 912 "-select-alpn", "proto", 913 "-application-settings", "proto,shim", 914 }, alpsFlags...), 915 // The runner is a client, so it only processes the shim's alert 916 // after checking connection state. 917 expectations: expectations, 918 shouldFail: true, 919 expectedError: ":UNEXPECTED_MESSAGE:", 920 expectedLocalError: "remote error: unexpected message", 921 }) 922 923 // Test that the server rejects an unexpected EncryptedExtensions message. 924 testCases = append(testCases, testCase{ 925 protocol: protocol, 926 testType: serverTest, 927 name: fmt.Sprintf("UnexpectedClientEncryptedExtensions-%s-%s", alpsCodePoint, suffix), 928 config: Config{ 929 MaxVersion: ver.version, 930 Bugs: ProtocolBugs{ 931 AlwaysSendClientEncryptedExtensions: true, 932 }, 933 ALPSUseNewCodepoint: alpsCodePoint, 934 }, 935 shouldFail: true, 936 expectedError: ":UNEXPECTED_MESSAGE:", 937 expectedLocalError: "remote error: unexpected message", 938 }) 939 940 // Test that the server rejects an unexpected extension in an 941 // expected EncryptedExtensions message. 942 testCases = append(testCases, testCase{ 943 protocol: protocol, 944 testType: serverTest, 945 name: fmt.Sprintf("ExtraClientEncryptedExtension-%s-%s", alpsCodePoint, suffix), 946 skipQUICALPNConfig: true, 947 config: Config{ 948 MaxVersion: ver.version, 949 NextProtos: []string{"proto"}, 950 ApplicationSettings: map[string][]byte{"proto": []byte("runner")}, 951 Bugs: ProtocolBugs{ 952 SendExtraClientEncryptedExtension: true, 953 }, 954 ALPSUseNewCodepoint: alpsCodePoint, 955 }, 956 flags: append([]string{ 957 "-select-alpn", "proto", 958 "-application-settings", "proto,shim", 959 }, alpsFlags...), 960 // The runner is a client, so it only processes the shim's alert 961 // after checking connection state. 962 expectations: expectations, 963 shouldFail: true, 964 expectedError: ":UNEXPECTED_EXTENSION:", 965 expectedLocalError: "remote error: unsupported extension", 966 }) 967 968 // Test that ALPS is carried over on 0-RTT. 969 // TODO(crbug.com/381113363): Support 0-RTT in DTLS 1.3. 970 if protocol != dtls { 971 for _, empty := range []bool{false, true} { 972 maybeEmpty := "" 973 runnerSettings := "runner" 974 shimSettings := "shim" 975 if empty { 976 maybeEmpty = "Empty-" 977 runnerSettings = "" 978 shimSettings = "" 979 } 980 981 expectations = connectionExpectations{ 982 peerApplicationSettingsOld: []byte(shimSettings), 983 } 984 if alpsCodePoint == ALPSUseCodepointNew { 985 expectations = connectionExpectations{ 986 peerApplicationSettings: []byte(shimSettings), 987 } 988 } 989 testCases = append(testCases, testCase{ 990 protocol: protocol, 991 testType: clientTest, 992 name: fmt.Sprintf("ALPS-EarlyData-Client-%s-%s-%s", alpsCodePoint, maybeEmpty, suffix), 993 skipQUICALPNConfig: true, 994 config: Config{ 995 MaxVersion: ver.version, 996 NextProtos: []string{"proto"}, 997 ApplicationSettings: map[string][]byte{"proto": []byte(runnerSettings)}, 998 ALPSUseNewCodepoint: alpsCodePoint, 999 }, 1000 resumeSession: true, 1001 earlyData: true, 1002 flags: append([]string{ 1003 "-advertise-alpn", "\x05proto", 1004 "-expect-alpn", "proto", 1005 "-application-settings", "proto," + shimSettings, 1006 "-expect-peer-application-settings", runnerSettings, 1007 }, alpsFlags...), 1008 expectations: expectations, 1009 }) 1010 testCases = append(testCases, testCase{ 1011 protocol: protocol, 1012 testType: serverTest, 1013 name: fmt.Sprintf("ALPS-EarlyData-Server-%s-%s-%s", alpsCodePoint, maybeEmpty, suffix), 1014 skipQUICALPNConfig: true, 1015 config: Config{ 1016 MaxVersion: ver.version, 1017 NextProtos: []string{"proto"}, 1018 ApplicationSettings: map[string][]byte{"proto": []byte(runnerSettings)}, 1019 ALPSUseNewCodepoint: alpsCodePoint, 1020 }, 1021 resumeSession: true, 1022 earlyData: true, 1023 flags: append([]string{ 1024 "-select-alpn", "proto", 1025 "-application-settings", "proto," + shimSettings, 1026 "-expect-peer-application-settings", runnerSettings, 1027 }, alpsFlags...), 1028 expectations: expectations, 1029 }) 1030 1031 // Sending application settings in 0-RTT handshakes is forbidden. 1032 testCases = append(testCases, testCase{ 1033 protocol: protocol, 1034 testType: clientTest, 1035 name: fmt.Sprintf("ALPS-EarlyData-SendApplicationSettingsWithEarlyData-Client-%s-%s-%s", alpsCodePoint, maybeEmpty, suffix), 1036 skipQUICALPNConfig: true, 1037 config: Config{ 1038 MaxVersion: ver.version, 1039 NextProtos: []string{"proto"}, 1040 ApplicationSettings: map[string][]byte{"proto": []byte(runnerSettings)}, 1041 Bugs: ProtocolBugs{ 1042 SendApplicationSettingsWithEarlyData: true, 1043 }, 1044 ALPSUseNewCodepoint: alpsCodePoint, 1045 }, 1046 resumeSession: true, 1047 earlyData: true, 1048 flags: append([]string{ 1049 "-advertise-alpn", "\x05proto", 1050 "-expect-alpn", "proto", 1051 "-application-settings", "proto," + shimSettings, 1052 "-expect-peer-application-settings", runnerSettings, 1053 }, alpsFlags...), 1054 expectations: expectations, 1055 shouldFail: true, 1056 expectedError: ":UNEXPECTED_EXTENSION_ON_EARLY_DATA:", 1057 expectedLocalError: "remote error: illegal parameter", 1058 }) 1059 testCases = append(testCases, testCase{ 1060 protocol: protocol, 1061 testType: serverTest, 1062 name: fmt.Sprintf("ALPS-EarlyData-SendApplicationSettingsWithEarlyData-Server-%s-%s-%s", alpsCodePoint, maybeEmpty, suffix), 1063 skipQUICALPNConfig: true, 1064 config: Config{ 1065 MaxVersion: ver.version, 1066 NextProtos: []string{"proto"}, 1067 ApplicationSettings: map[string][]byte{"proto": []byte(runnerSettings)}, 1068 Bugs: ProtocolBugs{ 1069 SendApplicationSettingsWithEarlyData: true, 1070 }, 1071 ALPSUseNewCodepoint: alpsCodePoint, 1072 }, 1073 resumeSession: true, 1074 earlyData: true, 1075 flags: append([]string{ 1076 "-select-alpn", "proto", 1077 "-application-settings", "proto," + shimSettings, 1078 "-expect-peer-application-settings", runnerSettings, 1079 }, alpsFlags...), 1080 expectations: expectations, 1081 shouldFail: true, 1082 expectedError: ":UNEXPECTED_MESSAGE:", 1083 expectedLocalError: "remote error: unexpected message", 1084 }) 1085 } 1086 1087 // Test that the client and server each decline early data if local 1088 // ALPS preferences has changed for the current connection. 1089 alpsMismatchTests := []struct { 1090 name string 1091 initialSettings, resumeSettings []byte 1092 }{ 1093 {"DifferentValues", []byte("settings1"), []byte("settings2")}, 1094 {"OnOff", []byte("settings"), nil}, 1095 {"OffOn", nil, []byte("settings")}, 1096 // The empty settings value should not be mistaken for ALPS not 1097 // being negotiated. 1098 {"OnEmpty", []byte("settings"), []byte{}}, 1099 {"EmptyOn", []byte{}, []byte("settings")}, 1100 {"EmptyOff", []byte{}, nil}, 1101 {"OffEmpty", nil, []byte{}}, 1102 } 1103 for _, test := range alpsMismatchTests { 1104 flags := []string{"-on-resume-expect-early-data-reason", "alps_mismatch"} 1105 flags = append(flags, alpsFlags...) 1106 if test.initialSettings != nil { 1107 flags = append(flags, "-on-initial-application-settings", "proto,"+string(test.initialSettings)) 1108 flags = append(flags, "-on-initial-expect-peer-application-settings", "runner") 1109 } 1110 if test.resumeSettings != nil { 1111 flags = append(flags, "-on-resume-application-settings", "proto,"+string(test.resumeSettings)) 1112 flags = append(flags, "-on-resume-expect-peer-application-settings", "runner") 1113 } 1114 1115 expectations = connectionExpectations{ 1116 peerApplicationSettingsOld: test.initialSettings, 1117 } 1118 resumeExpectations = &connectionExpectations{ 1119 peerApplicationSettingsOld: test.resumeSettings, 1120 } 1121 if alpsCodePoint == ALPSUseCodepointNew { 1122 expectations = connectionExpectations{ 1123 peerApplicationSettings: test.initialSettings, 1124 } 1125 resumeExpectations = &connectionExpectations{ 1126 peerApplicationSettings: test.resumeSettings, 1127 } 1128 } 1129 // The client should not offer early data if the session is 1130 // inconsistent with the new configuration. Note that if 1131 // the session did not negotiate ALPS (test.initialSettings 1132 // is nil), the client always offers early data. 1133 if test.initialSettings != nil { 1134 testCases = append(testCases, testCase{ 1135 protocol: protocol, 1136 testType: clientTest, 1137 name: fmt.Sprintf("ALPS-EarlyData-Mismatch-%s-Client-%s-%s", test.name, alpsCodePoint, suffix), 1138 skipQUICALPNConfig: true, 1139 config: Config{ 1140 MaxVersion: ver.version, 1141 MaxEarlyDataSize: 16384, 1142 NextProtos: []string{"proto"}, 1143 ApplicationSettings: map[string][]byte{"proto": []byte("runner")}, 1144 ALPSUseNewCodepoint: alpsCodePoint, 1145 }, 1146 resumeSession: true, 1147 flags: append([]string{ 1148 "-enable-early-data", 1149 "-expect-ticket-supports-early-data", 1150 "-expect-no-offer-early-data", 1151 "-advertise-alpn", "\x05proto", 1152 "-expect-alpn", "proto", 1153 }, flags...), 1154 expectations: expectations, 1155 resumeExpectations: resumeExpectations, 1156 }) 1157 } 1158 1159 // The server should reject early data if the session is 1160 // inconsistent with the new selection. 1161 testCases = append(testCases, testCase{ 1162 protocol: protocol, 1163 testType: serverTest, 1164 name: fmt.Sprintf("ALPS-EarlyData-Mismatch-%s-Server-%s-%s", test.name, alpsCodePoint, suffix), 1165 skipQUICALPNConfig: true, 1166 config: Config{ 1167 MaxVersion: ver.version, 1168 NextProtos: []string{"proto"}, 1169 ApplicationSettings: map[string][]byte{"proto": []byte("runner")}, 1170 ALPSUseNewCodepoint: alpsCodePoint, 1171 }, 1172 resumeSession: true, 1173 earlyData: true, 1174 expectEarlyDataRejected: true, 1175 flags: append([]string{ 1176 "-select-alpn", "proto", 1177 }, flags...), 1178 expectations: expectations, 1179 resumeExpectations: resumeExpectations, 1180 }) 1181 } 1182 1183 // Test that 0-RTT continues working when the shim configures 1184 // ALPS but the peer does not. 1185 testCases = append(testCases, testCase{ 1186 protocol: protocol, 1187 testType: clientTest, 1188 name: fmt.Sprintf("ALPS-EarlyData-Client-ServerDecline-%s-%s", alpsCodePoint, suffix), 1189 skipQUICALPNConfig: true, 1190 config: Config{ 1191 MaxVersion: ver.version, 1192 NextProtos: []string{"proto"}, 1193 ALPSUseNewCodepoint: alpsCodePoint, 1194 }, 1195 resumeSession: true, 1196 earlyData: true, 1197 flags: append([]string{ 1198 "-advertise-alpn", "\x05proto", 1199 "-expect-alpn", "proto", 1200 "-application-settings", "proto,shim", 1201 }, alpsFlags...), 1202 }) 1203 testCases = append(testCases, testCase{ 1204 protocol: protocol, 1205 testType: serverTest, 1206 name: fmt.Sprintf("ALPS-EarlyData-Server-ClientNoOffe-%s-%s", alpsCodePoint, suffix), 1207 skipQUICALPNConfig: true, 1208 config: Config{ 1209 MaxVersion: ver.version, 1210 NextProtos: []string{"proto"}, 1211 ALPSUseNewCodepoint: alpsCodePoint, 1212 }, 1213 resumeSession: true, 1214 earlyData: true, 1215 flags: append([]string{ 1216 "-select-alpn", "proto", 1217 "-application-settings", "proto,shim", 1218 }, alpsFlags...), 1219 }) 1220 } 1221 } 1222 } else { 1223 // Test the client rejects the ALPS extension if the server 1224 // negotiated TLS 1.2 or below. 1225 for _, alpsCodePoint := range []ALPSUseCodepoint{ALPSUseCodepointNew, ALPSUseCodepointOld} { 1226 useAlpsCodepointFlag := "0" 1227 if alpsCodePoint == ALPSUseCodepointNew { 1228 useAlpsCodepointFlag = "1" 1229 } 1230 1231 flags := []string{ 1232 "-advertise-alpn", "\x03foo", 1233 "-expect-alpn", "foo", 1234 "-application-settings", "foo,shim", 1235 "-alps-use-new-codepoint", useAlpsCodepointFlag, 1236 } 1237 bugs := ProtocolBugs{ 1238 AlwaysNegotiateApplicationSettingsOld: true, 1239 } 1240 if alpsCodePoint == ALPSUseCodepointNew { 1241 bugs = ProtocolBugs{ 1242 AlwaysNegotiateApplicationSettingsNew: true, 1243 } 1244 } 1245 testCases = append(testCases, testCase{ 1246 protocol: protocol, 1247 testType: clientTest, 1248 name: fmt.Sprintf("ALPS-Reject-Client-%s-%s", alpsCodePoint, suffix), 1249 config: Config{ 1250 MaxVersion: ver.version, 1251 NextProtos: []string{"foo"}, 1252 ApplicationSettings: map[string][]byte{"foo": []byte("runner")}, 1253 Bugs: bugs, 1254 ALPSUseNewCodepoint: alpsCodePoint, 1255 }, 1256 flags: flags, 1257 shouldFail: true, 1258 expectedError: ":UNEXPECTED_EXTENSION:", 1259 expectedLocalError: "remote error: unsupported extension", 1260 }) 1261 1262 flags = []string{ 1263 "-on-resume-advertise-alpn", "\x03foo", 1264 "-on-resume-expect-alpn", "foo", 1265 "-on-resume-application-settings", "foo,shim", 1266 "-alps-use-new-codepoint", useAlpsCodepointFlag, 1267 } 1268 bugs = ProtocolBugs{ 1269 AlwaysNegotiateApplicationSettingsOld: true, 1270 } 1271 if alpsCodePoint == ALPSUseCodepointNew { 1272 bugs = ProtocolBugs{ 1273 AlwaysNegotiateApplicationSettingsNew: true, 1274 } 1275 } 1276 testCases = append(testCases, testCase{ 1277 protocol: protocol, 1278 testType: clientTest, 1279 name: fmt.Sprintf("ALPS-Reject-Client-Resume-%s-%s", alpsCodePoint, suffix), 1280 config: Config{ 1281 MaxVersion: ver.version, 1282 }, 1283 resumeConfig: &Config{ 1284 MaxVersion: ver.version, 1285 NextProtos: []string{"foo"}, 1286 ApplicationSettings: map[string][]byte{"foo": []byte("runner")}, 1287 Bugs: bugs, 1288 ALPSUseNewCodepoint: alpsCodePoint, 1289 }, 1290 resumeSession: true, 1291 flags: flags, 1292 shouldFail: true, 1293 expectedError: ":UNEXPECTED_EXTENSION:", 1294 expectedLocalError: "remote error: unsupported extension", 1295 }) 1296 1297 // Test the server declines ALPS if it negotiates TLS 1.2 or below. 1298 flags = []string{ 1299 "-select-alpn", "foo", 1300 "-application-settings", "foo,shim", 1301 "-alps-use-new-codepoint", useAlpsCodepointFlag, 1302 } 1303 1304 testCases = append(testCases, testCase{ 1305 protocol: protocol, 1306 testType: serverTest, 1307 name: fmt.Sprintf("ALPS-Decline-Server-%s-%s", alpsCodePoint, suffix), 1308 config: Config{ 1309 MaxVersion: ver.version, 1310 NextProtos: []string{"foo"}, 1311 ApplicationSettings: map[string][]byte{"foo": []byte("runner")}, 1312 ALPSUseNewCodepoint: alpsCodePoint, 1313 }, 1314 // Test both TLS 1.2 full and resumption handshakes. 1315 resumeSession: true, 1316 flags: flags, 1317 // If not specified, runner and shim both implicitly expect ALPS 1318 // is not negotiated. 1319 }) 1320 } 1321 } 1322 1323 // Test QUIC transport params 1324 if protocol == quic { 1325 // Client sends params 1326 for _, clientConfig := range []QUICUseCodepoint{QUICUseCodepointStandard, QUICUseCodepointLegacy} { 1327 for _, serverSends := range []QUICUseCodepoint{QUICUseCodepointStandard, QUICUseCodepointLegacy, QUICUseCodepointBoth, QUICUseCodepointNeither} { 1328 useCodepointFlag := "0" 1329 if clientConfig == QUICUseCodepointLegacy { 1330 useCodepointFlag = "1" 1331 } 1332 flags := []string{ 1333 "-quic-transport-params", 1334 base64FlagValue([]byte{1, 2}), 1335 "-quic-use-legacy-codepoint", useCodepointFlag, 1336 } 1337 expectations := connectionExpectations{ 1338 quicTransportParams: []byte{1, 2}, 1339 } 1340 shouldFail := false 1341 expectedError := "" 1342 expectedLocalError := "" 1343 if clientConfig == QUICUseCodepointLegacy { 1344 expectations = connectionExpectations{ 1345 quicTransportParamsLegacy: []byte{1, 2}, 1346 } 1347 } 1348 if serverSends != clientConfig { 1349 expectations = connectionExpectations{} 1350 shouldFail = true 1351 if serverSends == QUICUseCodepointNeither { 1352 expectedError = ":MISSING_EXTENSION:" 1353 } else { 1354 expectedLocalError = "remote error: unsupported extension" 1355 } 1356 } else { 1357 flags = append(flags, 1358 "-expect-quic-transport-params", 1359 base64FlagValue([]byte{3, 4})) 1360 } 1361 testCases = append(testCases, testCase{ 1362 testType: clientTest, 1363 protocol: protocol, 1364 name: fmt.Sprintf("QUICTransportParams-Client-Client%s-Server%s-%s", clientConfig, serverSends, suffix), 1365 config: Config{ 1366 MinVersion: ver.version, 1367 MaxVersion: ver.version, 1368 QUICTransportParams: []byte{3, 4}, 1369 QUICTransportParamsUseLegacyCodepoint: serverSends, 1370 }, 1371 flags: flags, 1372 expectations: expectations, 1373 shouldFail: shouldFail, 1374 expectedError: expectedError, 1375 expectedLocalError: expectedLocalError, 1376 skipTransportParamsConfig: true, 1377 }) 1378 } 1379 } 1380 // Server sends params 1381 for _, clientSends := range []QUICUseCodepoint{QUICUseCodepointStandard, QUICUseCodepointLegacy, QUICUseCodepointBoth, QUICUseCodepointNeither} { 1382 for _, serverConfig := range []QUICUseCodepoint{QUICUseCodepointStandard, QUICUseCodepointLegacy} { 1383 expectations := connectionExpectations{ 1384 quicTransportParams: []byte{3, 4}, 1385 } 1386 shouldFail := false 1387 expectedError := "" 1388 useCodepointFlag := "0" 1389 if serverConfig == QUICUseCodepointLegacy { 1390 useCodepointFlag = "1" 1391 expectations = connectionExpectations{ 1392 quicTransportParamsLegacy: []byte{3, 4}, 1393 } 1394 } 1395 flags := []string{ 1396 "-quic-transport-params", 1397 base64FlagValue([]byte{3, 4}), 1398 "-quic-use-legacy-codepoint", useCodepointFlag, 1399 } 1400 if clientSends != QUICUseCodepointBoth && clientSends != serverConfig { 1401 expectations = connectionExpectations{} 1402 shouldFail = true 1403 expectedError = ":MISSING_EXTENSION:" 1404 } else { 1405 flags = append(flags, 1406 "-expect-quic-transport-params", 1407 base64FlagValue([]byte{1, 2}), 1408 ) 1409 } 1410 testCases = append(testCases, testCase{ 1411 testType: serverTest, 1412 protocol: protocol, 1413 name: fmt.Sprintf("QUICTransportParams-Server-Client%s-Server%s-%s", clientSends, serverConfig, suffix), 1414 config: Config{ 1415 MinVersion: ver.version, 1416 MaxVersion: ver.version, 1417 QUICTransportParams: []byte{1, 2}, 1418 QUICTransportParamsUseLegacyCodepoint: clientSends, 1419 }, 1420 flags: flags, 1421 expectations: expectations, 1422 shouldFail: shouldFail, 1423 expectedError: expectedError, 1424 skipTransportParamsConfig: true, 1425 }) 1426 } 1427 } 1428 } else { 1429 // Ensure non-QUIC client doesn't send QUIC transport parameters. 1430 for _, clientConfig := range []QUICUseCodepoint{QUICUseCodepointStandard, QUICUseCodepointLegacy} { 1431 useCodepointFlag := "0" 1432 if clientConfig == QUICUseCodepointLegacy { 1433 useCodepointFlag = "1" 1434 } 1435 testCases = append(testCases, testCase{ 1436 protocol: protocol, 1437 testType: clientTest, 1438 name: fmt.Sprintf("QUICTransportParams-Client-NotSentInNonQUIC-%s-%s", clientConfig, suffix), 1439 config: Config{ 1440 MinVersion: ver.version, 1441 MaxVersion: ver.version, 1442 QUICTransportParamsUseLegacyCodepoint: clientConfig, 1443 }, 1444 flags: []string{ 1445 "-max-version", 1446 ver.shimFlag(protocol), 1447 "-quic-transport-params", 1448 base64FlagValue([]byte{3, 4}), 1449 "-quic-use-legacy-codepoint", useCodepointFlag, 1450 }, 1451 shouldFail: true, 1452 expectedError: ":QUIC_TRANSPORT_PARAMETERS_MISCONFIGURED:", 1453 skipTransportParamsConfig: true, 1454 }) 1455 } 1456 // Ensure non-QUIC server rejects codepoint 57 but ignores legacy 0xffa5. 1457 for _, clientSends := range []QUICUseCodepoint{QUICUseCodepointStandard, QUICUseCodepointLegacy, QUICUseCodepointBoth, QUICUseCodepointNeither} { 1458 for _, serverConfig := range []QUICUseCodepoint{QUICUseCodepointStandard, QUICUseCodepointLegacy} { 1459 shouldFail := false 1460 expectedLocalError := "" 1461 useCodepointFlag := "0" 1462 if serverConfig == QUICUseCodepointLegacy { 1463 useCodepointFlag = "1" 1464 } 1465 if clientSends == QUICUseCodepointStandard || clientSends == QUICUseCodepointBoth { 1466 shouldFail = true 1467 expectedLocalError = "remote error: unsupported extension" 1468 } 1469 testCases = append(testCases, testCase{ 1470 protocol: protocol, 1471 testType: serverTest, 1472 name: fmt.Sprintf("QUICTransportParams-NonQUICServer-Client%s-Server%s-%s", clientSends, serverConfig, suffix), 1473 config: Config{ 1474 MinVersion: ver.version, 1475 MaxVersion: ver.version, 1476 QUICTransportParams: []byte{1, 2}, 1477 QUICTransportParamsUseLegacyCodepoint: clientSends, 1478 }, 1479 flags: []string{ 1480 "-quic-use-legacy-codepoint", useCodepointFlag, 1481 }, 1482 shouldFail: shouldFail, 1483 expectedLocalError: expectedLocalError, 1484 skipTransportParamsConfig: true, 1485 }) 1486 } 1487 } 1488 1489 } 1490 1491 // Test ticket behavior. 1492 1493 // Resume with a corrupt ticket. 1494 testCases = append(testCases, testCase{ 1495 protocol: protocol, 1496 testType: serverTest, 1497 name: "CorruptTicket-" + suffix, 1498 config: Config{ 1499 MaxVersion: ver.version, 1500 Bugs: ProtocolBugs{ 1501 FilterTicket: func(in []byte) ([]byte, error) { 1502 in[len(in)-1] ^= 1 1503 return in, nil 1504 }, 1505 }, 1506 }, 1507 resumeSession: true, 1508 expectResumeRejected: true, 1509 }) 1510 // Test the ticket callbacks. 1511 for _, aeadCallback := range []bool{false, true} { 1512 flag := "-use-ticket-callback" 1513 callbackSuffix := suffix 1514 if aeadCallback { 1515 flag = "-use-ticket-aead-callback" 1516 callbackSuffix += "-AEAD" 1517 } 1518 testCases = append(testCases, testCase{ 1519 protocol: protocol, 1520 testType: serverTest, 1521 name: "TicketCallback-" + callbackSuffix, 1522 config: Config{ 1523 MaxVersion: ver.version, 1524 }, 1525 resumeSession: true, 1526 flags: []string{flag}, 1527 }) 1528 // Only the old callback supports renewal. 1529 if !aeadCallback { 1530 testCases = append(testCases, testCase{ 1531 protocol: protocol, 1532 testType: serverTest, 1533 name: "TicketCallback-Renew-" + callbackSuffix, 1534 config: Config{ 1535 MaxVersion: ver.version, 1536 Bugs: ProtocolBugs{ 1537 ExpectNewTicket: true, 1538 }, 1539 }, 1540 flags: []string{flag, "-renew-ticket"}, 1541 resumeSession: true, 1542 }) 1543 } 1544 testCases = append(testCases, testCase{ 1545 protocol: protocol, 1546 testType: serverTest, 1547 name: "TicketCallback-Skip-" + callbackSuffix, 1548 config: Config{ 1549 MaxVersion: ver.version, 1550 Bugs: ProtocolBugs{ 1551 ExpectNoNonEmptyNewSessionTicket: true, 1552 }, 1553 }, 1554 flags: []string{flag, "-skip-ticket"}, 1555 }) 1556 1557 // Test that the ticket callback is only called once when everything before 1558 // it in the ClientHello is asynchronous. This corrupts the ticket so 1559 // certificate selection callbacks run. 1560 testCases = append(testCases, testCase{ 1561 protocol: protocol, 1562 testType: serverTest, 1563 name: "TicketCallback-SingleCall-" + callbackSuffix, 1564 config: Config{ 1565 MaxVersion: ver.version, 1566 Bugs: ProtocolBugs{ 1567 FilterTicket: func(in []byte) ([]byte, error) { 1568 in[len(in)-1] ^= 1 1569 return in, nil 1570 }, 1571 }, 1572 }, 1573 resumeSession: true, 1574 expectResumeRejected: true, 1575 flags: []string{ 1576 flag, 1577 "-async", 1578 }, 1579 }) 1580 } 1581 1582 // Resume with various lengths of ticket session id. 1583 if ver.version < VersionTLS13 { 1584 testCases = append(testCases, testCase{ 1585 protocol: protocol, 1586 testType: serverTest, 1587 name: "TicketSessionIDLength-0-" + suffix, 1588 config: Config{ 1589 MaxVersion: ver.version, 1590 Bugs: ProtocolBugs{ 1591 EmptyTicketSessionID: true, 1592 }, 1593 }, 1594 resumeSession: true, 1595 }) 1596 testCases = append(testCases, testCase{ 1597 protocol: protocol, 1598 testType: serverTest, 1599 name: "TicketSessionIDLength-16-" + suffix, 1600 config: Config{ 1601 MaxVersion: ver.version, 1602 Bugs: ProtocolBugs{ 1603 TicketSessionIDLength: 16, 1604 }, 1605 }, 1606 resumeSession: true, 1607 }) 1608 testCases = append(testCases, testCase{ 1609 protocol: protocol, 1610 testType: serverTest, 1611 name: "TicketSessionIDLength-32-" + suffix, 1612 config: Config{ 1613 MaxVersion: ver.version, 1614 Bugs: ProtocolBugs{ 1615 TicketSessionIDLength: 32, 1616 }, 1617 }, 1618 resumeSession: true, 1619 }) 1620 testCases = append(testCases, testCase{ 1621 protocol: protocol, 1622 testType: serverTest, 1623 name: "TicketSessionIDLength-33-" + suffix, 1624 config: Config{ 1625 MaxVersion: ver.version, 1626 Bugs: ProtocolBugs{ 1627 TicketSessionIDLength: 33, 1628 }, 1629 }, 1630 resumeSession: true, 1631 shouldFail: true, 1632 // The maximum session ID length is 32. 1633 expectedError: ":CLIENTHELLO_PARSE_FAILED:", 1634 }) 1635 } 1636 1637 // Basic DTLS-SRTP tests. Include fake profiles to ensure they 1638 // are ignored. 1639 if protocol == dtls { 1640 testCases = append(testCases, testCase{ 1641 protocol: protocol, 1642 name: "SRTP-Client-" + suffix, 1643 config: Config{ 1644 MaxVersion: ver.version, 1645 SRTPProtectionProfiles: []uint16{40, SRTP_AES128_CM_HMAC_SHA1_80, 42}, 1646 }, 1647 flags: []string{ 1648 "-srtp-profiles", 1649 "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32", 1650 }, 1651 expectations: connectionExpectations{ 1652 srtpProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80, 1653 }, 1654 }) 1655 testCases = append(testCases, testCase{ 1656 protocol: protocol, 1657 testType: serverTest, 1658 name: "SRTP-Server-" + suffix, 1659 config: Config{ 1660 MaxVersion: ver.version, 1661 SRTPProtectionProfiles: []uint16{40, SRTP_AES128_CM_HMAC_SHA1_80, 42}, 1662 }, 1663 flags: []string{ 1664 "-srtp-profiles", 1665 "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32", 1666 }, 1667 expectations: connectionExpectations{ 1668 srtpProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80, 1669 }, 1670 }) 1671 // Test that the MKI is ignored. 1672 testCases = append(testCases, testCase{ 1673 protocol: protocol, 1674 testType: serverTest, 1675 name: "SRTP-Server-IgnoreMKI-" + suffix, 1676 config: Config{ 1677 MaxVersion: ver.version, 1678 SRTPProtectionProfiles: []uint16{SRTP_AES128_CM_HMAC_SHA1_80}, 1679 Bugs: ProtocolBugs{ 1680 SRTPMasterKeyIdentifier: "bogus", 1681 }, 1682 }, 1683 flags: []string{ 1684 "-srtp-profiles", 1685 "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32", 1686 }, 1687 expectations: connectionExpectations{ 1688 srtpProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80, 1689 }, 1690 }) 1691 // Test that SRTP isn't negotiated on the server if there were 1692 // no matching profiles. 1693 testCases = append(testCases, testCase{ 1694 protocol: protocol, 1695 testType: serverTest, 1696 name: "SRTP-Server-NoMatch-" + suffix, 1697 config: Config{ 1698 MaxVersion: ver.version, 1699 SRTPProtectionProfiles: []uint16{100, 101, 102}, 1700 }, 1701 flags: []string{ 1702 "-srtp-profiles", 1703 "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32", 1704 }, 1705 expectations: connectionExpectations{ 1706 srtpProtectionProfile: 0, 1707 }, 1708 }) 1709 // Test that the server returning an invalid SRTP profile is 1710 // flagged as an error by the client. 1711 testCases = append(testCases, testCase{ 1712 protocol: protocol, 1713 name: "SRTP-Client-NoMatch-" + suffix, 1714 config: Config{ 1715 MaxVersion: ver.version, 1716 Bugs: ProtocolBugs{ 1717 SendSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_32, 1718 }, 1719 }, 1720 flags: []string{ 1721 "-srtp-profiles", 1722 "SRTP_AES128_CM_SHA1_80", 1723 }, 1724 shouldFail: true, 1725 expectedError: ":BAD_SRTP_PROTECTION_PROFILE_LIST:", 1726 }) 1727 } else { 1728 // DTLS-SRTP is not defined for other protocols. Configuring it 1729 // on the client and server should ignore the extension. 1730 testCases = append(testCases, testCase{ 1731 protocol: protocol, 1732 name: "SRTP-Client-Ignore-" + suffix, 1733 config: Config{ 1734 MaxVersion: ver.version, 1735 SRTPProtectionProfiles: []uint16{40, SRTP_AES128_CM_HMAC_SHA1_80, 42}, 1736 }, 1737 flags: []string{ 1738 "-srtp-profiles", 1739 "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32", 1740 }, 1741 expectations: connectionExpectations{ 1742 srtpProtectionProfile: 0, 1743 }, 1744 }) 1745 testCases = append(testCases, testCase{ 1746 protocol: protocol, 1747 testType: serverTest, 1748 name: "SRTP-Server-Ignore-" + suffix, 1749 config: Config{ 1750 MaxVersion: ver.version, 1751 SRTPProtectionProfiles: []uint16{40, SRTP_AES128_CM_HMAC_SHA1_80, 42}, 1752 }, 1753 flags: []string{ 1754 "-srtp-profiles", 1755 "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32", 1756 }, 1757 expectations: connectionExpectations{ 1758 srtpProtectionProfile: 0, 1759 }, 1760 }) 1761 } 1762 1763 // Test SCT list. 1764 testCases = append(testCases, testCase{ 1765 protocol: protocol, 1766 name: "SignedCertificateTimestampList-Client-" + suffix, 1767 testType: clientTest, 1768 config: Config{ 1769 MaxVersion: ver.version, 1770 Credential: rsaCertificate.WithSCTList(testSCTList), 1771 }, 1772 flags: []string{ 1773 "-enable-signed-cert-timestamps", 1774 "-expect-signed-cert-timestamps", 1775 base64FlagValue(testSCTList), 1776 }, 1777 resumeSession: true, 1778 }) 1779 1780 var differentSCTList []byte 1781 differentSCTList = append(differentSCTList, testSCTList...) 1782 differentSCTList[len(differentSCTList)-1] ^= 1 1783 1784 // The SCT extension did not specify that it must only be sent on the inital handshake as it 1785 // should have, so test that we tolerate but ignore it. This is only an issue pre-1.3, since 1786 // SCTs are sent in the CertificateEntry message in 1.3, whereas they were previously sent 1787 // in an extension in the ServerHello pre-1.3. 1788 testCases = append(testCases, testCase{ 1789 protocol: protocol, 1790 name: "SendSCTListOnResume-" + suffix, 1791 config: Config{ 1792 MaxVersion: ver.version, 1793 Credential: rsaCertificate.WithSCTList(testSCTList), 1794 Bugs: ProtocolBugs{ 1795 SendSCTListOnResume: differentSCTList, 1796 }, 1797 }, 1798 flags: []string{ 1799 "-enable-signed-cert-timestamps", 1800 "-expect-signed-cert-timestamps", 1801 base64FlagValue(testSCTList), 1802 }, 1803 resumeSession: true, 1804 }) 1805 1806 testCases = append(testCases, testCase{ 1807 protocol: protocol, 1808 name: "SignedCertificateTimestampList-Server-" + suffix, 1809 testType: serverTest, 1810 config: Config{ 1811 MaxVersion: ver.version, 1812 }, 1813 shimCertificate: rsaCertificate.WithSCTList(testSCTList), 1814 expectations: connectionExpectations{ 1815 peerCertificate: rsaCertificate.WithSCTList(testSCTList), 1816 }, 1817 resumeSession: true, 1818 }) 1819 1820 // Test empty SCT list. 1821 testCases = append(testCases, testCase{ 1822 protocol: protocol, 1823 name: "SignedCertificateTimestampListEmpty-Client-" + suffix, 1824 testType: clientTest, 1825 config: Config{ 1826 MaxVersion: ver.version, 1827 Credential: rsaCertificate.WithSCTList([]byte{0, 0}), 1828 }, 1829 flags: []string{ 1830 "-enable-signed-cert-timestamps", 1831 }, 1832 shouldFail: true, 1833 expectedError: ":ERROR_PARSING_EXTENSION:", 1834 }) 1835 1836 // Test empty SCT in non-empty list. 1837 testCases = append(testCases, testCase{ 1838 protocol: protocol, 1839 name: "SignedCertificateTimestampListEmptySCT-Client-" + suffix, 1840 testType: clientTest, 1841 config: Config{ 1842 MaxVersion: ver.version, 1843 Credential: rsaCertificate.WithSCTList([]byte{0, 6, 0, 2, 1, 2, 0, 0}), 1844 }, 1845 flags: []string{ 1846 "-enable-signed-cert-timestamps", 1847 }, 1848 shouldFail: true, 1849 expectedError: ":ERROR_PARSING_EXTENSION:", 1850 }) 1851 1852 // Test that certificate-related extensions are not sent unsolicited. 1853 testCases = append(testCases, testCase{ 1854 protocol: protocol, 1855 testType: serverTest, 1856 name: "UnsolicitedCertificateExtensions-" + suffix, 1857 config: Config{ 1858 MaxVersion: ver.version, 1859 Bugs: ProtocolBugs{ 1860 NoOCSPStapling: true, 1861 NoSignedCertificateTimestamps: true, 1862 }, 1863 }, 1864 shimCertificate: rsaCertificate.WithOCSP(testOCSPResponse).WithSCTList(testSCTList), 1865 }) 1866 1867 // Extension permutation should interact correctly with other extensions, 1868 // HelloVerifyRequest, HelloRetryRequest, and ECH. SSLTest.PermuteExtensions 1869 // in ssl_test.cc tests that the extensions are actually permuted. This 1870 // tests the handshake still works. 1871 // 1872 // This test also tests that all our extensions interact with each other. 1873 for _, ech := range []bool{false, true} { 1874 if ech && ver.version < VersionTLS13 { 1875 continue 1876 } 1877 1878 test := testCase{ 1879 protocol: protocol, 1880 name: "AllExtensions-Client-Permute", 1881 skipQUICALPNConfig: true, 1882 config: Config{ 1883 MinVersion: ver.version, 1884 MaxVersion: ver.version, 1885 Credential: rsaCertificate.WithOCSP(testOCSPResponse).WithSCTList(testSCTList), 1886 NextProtos: []string{"proto"}, 1887 ApplicationSettings: map[string][]byte{"proto": []byte("runner1")}, 1888 Bugs: ProtocolBugs{ 1889 SendServerNameAck: true, 1890 ExpectServerName: "example.com", 1891 ExpectGREASE: true, 1892 }, 1893 }, 1894 resumeSession: true, 1895 flags: []string{ 1896 "-permute-extensions", 1897 "-enable-grease", 1898 "-enable-ocsp-stapling", 1899 "-enable-signed-cert-timestamps", 1900 "-advertise-alpn", "\x05proto", 1901 "-expect-alpn", "proto", 1902 "-host-name", "example.com", 1903 }, 1904 } 1905 1906 if ech { 1907 test.name += "-ECH" 1908 echConfig := generateServerECHConfig(&ECHConfig{ConfigID: 42}) 1909 test.config.ServerECHConfigs = []ServerECHConfig{echConfig} 1910 test.flags = append(test.flags, 1911 "-ech-config-list", base64FlagValue(CreateECHConfigList(echConfig.ECHConfig.Raw)), 1912 "-expect-ech-accept", 1913 ) 1914 test.expectations.echAccepted = true 1915 } 1916 1917 if ver.version >= VersionTLS13 { 1918 // Trigger a HelloRetryRequest to test both ClientHellos. Note 1919 // our DTLS tests always enable HelloVerifyRequest. 1920 test.name += "-HelloRetryRequest" 1921 1922 // ALPS is only available on TLS 1.3. 1923 test.config.ApplicationSettings = map[string][]byte{"proto": []byte("runner")} 1924 test.flags = append(test.flags, 1925 "-application-settings", "proto,shim", 1926 "-alps-use-new-codepoint", "1", 1927 "-expect-peer-application-settings", "runner") 1928 test.expectations.peerApplicationSettings = []byte("shim") 1929 } 1930 1931 if protocol == dtls { 1932 test.config.SRTPProtectionProfiles = []uint16{SRTP_AES128_CM_HMAC_SHA1_80} 1933 test.flags = append(test.flags, "-srtp-profiles", "SRTP_AES128_CM_SHA1_80") 1934 test.expectations.srtpProtectionProfile = SRTP_AES128_CM_HMAC_SHA1_80 1935 } 1936 1937 test.name += "-" + suffix 1938 testCases = append(testCases, test) 1939 } 1940 } 1941 } 1942 1943 testCases = append(testCases, testCase{ 1944 testType: clientTest, 1945 name: "ClientHelloPadding", 1946 config: Config{ 1947 Bugs: ProtocolBugs{ 1948 RequireClientHelloSize: 512, 1949 }, 1950 }, 1951 // This hostname just needs to be long enough to push the 1952 // ClientHello into F5's danger zone between 256 and 511 bytes 1953 // long. 1954 flags: []string{"-host-name", "01234567890123456789012345678901234567890123456789012345678901234567890123456789.com"}, 1955 }) 1956 1957 // Test that illegal extensions in TLS 1.3 are rejected by the client if 1958 // in ServerHello. 1959 testCases = append(testCases, testCase{ 1960 name: "NPN-Forbidden-TLS13", 1961 config: Config{ 1962 MaxVersion: VersionTLS13, 1963 NextProtos: []string{"foo"}, 1964 Bugs: ProtocolBugs{ 1965 NegotiateNPNAtAllVersions: true, 1966 }, 1967 }, 1968 flags: []string{"-select-next-proto", "foo"}, 1969 shouldFail: true, 1970 expectedError: ":ERROR_PARSING_EXTENSION:", 1971 }) 1972 testCases = append(testCases, testCase{ 1973 name: "EMS-Forbidden-TLS13", 1974 config: Config{ 1975 MaxVersion: VersionTLS13, 1976 Bugs: ProtocolBugs{ 1977 NegotiateEMSAtAllVersions: true, 1978 }, 1979 }, 1980 shouldFail: true, 1981 expectedError: ":ERROR_PARSING_EXTENSION:", 1982 }) 1983 testCases = append(testCases, testCase{ 1984 name: "RenegotiationInfo-Forbidden-TLS13", 1985 config: Config{ 1986 MaxVersion: VersionTLS13, 1987 Bugs: ProtocolBugs{ 1988 NegotiateRenegotiationInfoAtAllVersions: true, 1989 }, 1990 }, 1991 shouldFail: true, 1992 expectedError: ":ERROR_PARSING_EXTENSION:", 1993 }) 1994 testCases = append(testCases, testCase{ 1995 name: "Ticket-Forbidden-TLS13", 1996 config: Config{ 1997 MaxVersion: VersionTLS12, 1998 }, 1999 resumeConfig: &Config{ 2000 MaxVersion: VersionTLS13, 2001 Bugs: ProtocolBugs{ 2002 AdvertiseTicketExtension: true, 2003 }, 2004 }, 2005 resumeSession: true, 2006 shouldFail: true, 2007 expectedError: ":ERROR_PARSING_EXTENSION:", 2008 }) 2009 2010 // Test that illegal extensions in TLS 1.3 are declined by the server if 2011 // offered in ClientHello. The runner's server will fail if this occurs, 2012 // so we exercise the offering path. (EMS and Renegotiation Info are 2013 // implicit in every test.) 2014 testCases = append(testCases, testCase{ 2015 testType: serverTest, 2016 name: "NPN-Declined-TLS13", 2017 config: Config{ 2018 MaxVersion: VersionTLS13, 2019 NextProtos: []string{"bar"}, 2020 }, 2021 flags: []string{"-advertise-npn", "\x03foo\x03bar\x03baz"}, 2022 }) 2023 2024 // OpenSSL sends the status_request extension on resumption in TLS 1.2. Test that this is 2025 // tolerated. 2026 testCases = append(testCases, testCase{ 2027 name: "SendOCSPResponseOnResume-TLS12", 2028 config: Config{ 2029 MaxVersion: VersionTLS12, 2030 Credential: rsaCertificate.WithOCSP(testOCSPResponse), 2031 Bugs: ProtocolBugs{ 2032 SendOCSPResponseOnResume: []byte("bogus"), 2033 }, 2034 }, 2035 flags: []string{ 2036 "-enable-ocsp-stapling", 2037 "-expect-ocsp-response", 2038 base64FlagValue(testOCSPResponse), 2039 }, 2040 resumeSession: true, 2041 }) 2042 2043 testCases = append(testCases, testCase{ 2044 name: "SendUnsolicitedOCSPOnCertificate-TLS13", 2045 config: Config{ 2046 MaxVersion: VersionTLS13, 2047 Bugs: ProtocolBugs{ 2048 SendExtensionOnCertificate: testOCSPExtension, 2049 }, 2050 }, 2051 shouldFail: true, 2052 expectedError: ":UNEXPECTED_EXTENSION:", 2053 }) 2054 2055 testCases = append(testCases, testCase{ 2056 name: "SendUnsolicitedSCTOnCertificate-TLS13", 2057 config: Config{ 2058 MaxVersion: VersionTLS13, 2059 Bugs: ProtocolBugs{ 2060 SendExtensionOnCertificate: testSCTExtension, 2061 }, 2062 }, 2063 shouldFail: true, 2064 expectedError: ":UNEXPECTED_EXTENSION:", 2065 }) 2066 2067 // Test that extensions on client certificates are never accepted. 2068 testCases = append(testCases, testCase{ 2069 name: "SendExtensionOnClientCertificate-TLS13", 2070 testType: serverTest, 2071 config: Config{ 2072 MaxVersion: VersionTLS13, 2073 Credential: &rsaCertificate, 2074 Bugs: ProtocolBugs{ 2075 SendExtensionOnCertificate: testOCSPExtension, 2076 }, 2077 }, 2078 flags: []string{ 2079 "-enable-ocsp-stapling", 2080 "-require-any-client-certificate", 2081 }, 2082 shouldFail: true, 2083 expectedError: ":UNEXPECTED_EXTENSION:", 2084 }) 2085 2086 testCases = append(testCases, testCase{ 2087 name: "SendUnknownExtensionOnCertificate-TLS13", 2088 config: Config{ 2089 MaxVersion: VersionTLS13, 2090 Bugs: ProtocolBugs{ 2091 SendExtensionOnCertificate: []byte{0x00, 0x7f, 0, 0}, 2092 }, 2093 }, 2094 shouldFail: true, 2095 expectedError: ":UNEXPECTED_EXTENSION:", 2096 }) 2097 2098 // Test that extensions on intermediates are allowed but ignored. 2099 testCases = append(testCases, testCase{ 2100 name: "IgnoreExtensionsOnIntermediates-TLS13", 2101 config: Config{ 2102 MaxVersion: VersionTLS13, 2103 Credential: rsaChainCertificate.WithOCSP(testOCSPResponse).WithSCTList(testSCTList), 2104 Bugs: ProtocolBugs{ 2105 // Send different values on the intermediate. This tests 2106 // the intermediate's extensions do not override the 2107 // leaf's. 2108 SendOCSPOnIntermediates: testOCSPResponse2, 2109 SendSCTOnIntermediates: testSCTList2, 2110 }, 2111 }, 2112 flags: []string{ 2113 "-enable-ocsp-stapling", 2114 "-expect-ocsp-response", 2115 base64FlagValue(testOCSPResponse), 2116 "-enable-signed-cert-timestamps", 2117 "-expect-signed-cert-timestamps", 2118 base64FlagValue(testSCTList), 2119 }, 2120 resumeSession: true, 2121 }) 2122 2123 // Test that extensions are not sent on intermediates when configured 2124 // only for a leaf. 2125 testCases = append(testCases, testCase{ 2126 testType: serverTest, 2127 name: "SendNoExtensionsOnIntermediate-TLS13", 2128 config: Config{ 2129 MaxVersion: VersionTLS13, 2130 Bugs: ProtocolBugs{ 2131 ExpectNoExtensionsOnIntermediate: true, 2132 }, 2133 }, 2134 shimCertificate: rsaChainCertificate.WithOCSP(testOCSPResponse).WithSCTList(testSCTList), 2135 }) 2136 2137 // Test that extensions are not sent on client certificates. 2138 testCases = append(testCases, testCase{ 2139 name: "SendNoClientCertificateExtensions-TLS13", 2140 config: Config{ 2141 MaxVersion: VersionTLS13, 2142 ClientAuth: RequireAnyClientCert, 2143 }, 2144 shimCertificate: rsaChainCertificate.WithOCSP(testOCSPResponse).WithSCTList(testSCTList), 2145 }) 2146 2147 testCases = append(testCases, testCase{ 2148 name: "SendDuplicateExtensionsOnCerts-TLS13", 2149 config: Config{ 2150 MaxVersion: VersionTLS13, 2151 Credential: rsaCertificate.WithOCSP(testOCSPResponse).WithSCTList(testSCTList), 2152 Bugs: ProtocolBugs{ 2153 SendDuplicateCertExtensions: true, 2154 }, 2155 }, 2156 flags: []string{ 2157 "-enable-ocsp-stapling", 2158 "-enable-signed-cert-timestamps", 2159 }, 2160 resumeSession: true, 2161 shouldFail: true, 2162 expectedError: ":DUPLICATE_EXTENSION:", 2163 }) 2164 2165 testCases = append(testCases, testCase{ 2166 name: "SignedCertificateTimestampListInvalid-Server", 2167 testType: serverTest, 2168 shimCertificate: rsaCertificate.WithSCTList([]byte{0, 0}), 2169 shouldFail: true, 2170 expectedError: ":INVALID_SCT_LIST:", 2171 }) 2172} 2173 2174func addUnknownExtensionTests() { 2175 // Test an unknown extension from the server. 2176 testCases = append(testCases, testCase{ 2177 testType: clientTest, 2178 name: "UnknownExtension-Client", 2179 config: Config{ 2180 MaxVersion: VersionTLS12, 2181 Bugs: ProtocolBugs{ 2182 CustomExtension: "custom extension", 2183 }, 2184 }, 2185 shouldFail: true, 2186 expectedError: ":UNEXPECTED_EXTENSION:", 2187 expectedLocalError: "remote error: unsupported extension", 2188 }) 2189 testCases = append(testCases, testCase{ 2190 testType: clientTest, 2191 name: "UnknownExtension-Client-TLS13", 2192 config: Config{ 2193 MaxVersion: VersionTLS13, 2194 Bugs: ProtocolBugs{ 2195 CustomExtension: "custom extension", 2196 }, 2197 }, 2198 shouldFail: true, 2199 expectedError: ":UNEXPECTED_EXTENSION:", 2200 expectedLocalError: "remote error: unsupported extension", 2201 }) 2202 testCases = append(testCases, testCase{ 2203 testType: clientTest, 2204 name: "UnknownUnencryptedExtension-Client-TLS13", 2205 config: Config{ 2206 MaxVersion: VersionTLS13, 2207 Bugs: ProtocolBugs{ 2208 CustomUnencryptedExtension: "custom extension", 2209 }, 2210 }, 2211 shouldFail: true, 2212 expectedError: ":UNEXPECTED_EXTENSION:", 2213 // The shim must send an alert, but alerts at this point do not 2214 // get successfully decrypted by the runner. 2215 expectedLocalError: "local error: bad record MAC", 2216 }) 2217 testCases = append(testCases, testCase{ 2218 testType: clientTest, 2219 name: "UnexpectedUnencryptedExtension-Client-TLS13", 2220 config: Config{ 2221 MaxVersion: VersionTLS13, 2222 Bugs: ProtocolBugs{ 2223 SendUnencryptedALPN: "foo", 2224 }, 2225 }, 2226 flags: []string{ 2227 "-advertise-alpn", "\x03foo\x03bar", 2228 }, 2229 shouldFail: true, 2230 expectedError: ":UNEXPECTED_EXTENSION:", 2231 // The shim must send an alert, but alerts at this point do not 2232 // get successfully decrypted by the runner. 2233 expectedLocalError: "local error: bad record MAC", 2234 }) 2235 2236 // Test a known but unoffered extension from the server. 2237 testCases = append(testCases, testCase{ 2238 testType: clientTest, 2239 name: "UnofferedExtension-Client", 2240 config: Config{ 2241 MaxVersion: VersionTLS12, 2242 Bugs: ProtocolBugs{ 2243 SendALPN: "alpn", 2244 }, 2245 }, 2246 shouldFail: true, 2247 expectedError: ":UNEXPECTED_EXTENSION:", 2248 expectedLocalError: "remote error: unsupported extension", 2249 }) 2250 testCases = append(testCases, testCase{ 2251 testType: clientTest, 2252 name: "UnofferedExtension-Client-TLS13", 2253 config: Config{ 2254 MaxVersion: VersionTLS13, 2255 Bugs: ProtocolBugs{ 2256 SendALPN: "alpn", 2257 }, 2258 }, 2259 shouldFail: true, 2260 expectedError: ":UNEXPECTED_EXTENSION:", 2261 expectedLocalError: "remote error: unsupported extension", 2262 }) 2263} 2264 2265// Test that omitted and empty extensions blocks are tolerated. 2266func addOmitExtensionsTests() { 2267 // Check the ExpectOmitExtensions setting works. 2268 testCases = append(testCases, testCase{ 2269 testType: serverTest, 2270 name: "ExpectOmitExtensions", 2271 config: Config{ 2272 MinVersion: VersionTLS12, 2273 MaxVersion: VersionTLS12, 2274 Bugs: ProtocolBugs{ 2275 ExpectOmitExtensions: true, 2276 }, 2277 }, 2278 shouldFail: true, 2279 expectedLocalError: "tls: ServerHello did not omit extensions", 2280 }) 2281 2282 for _, ver := range tlsVersions { 2283 if ver.version > VersionTLS12 { 2284 continue 2285 } 2286 2287 testCases = append(testCases, testCase{ 2288 testType: serverTest, 2289 name: "OmitExtensions-ClientHello-" + ver.name, 2290 config: Config{ 2291 MinVersion: ver.version, 2292 MaxVersion: ver.version, 2293 SessionTicketsDisabled: true, 2294 Bugs: ProtocolBugs{ 2295 OmitExtensions: true, 2296 // With no client extensions, the ServerHello must not have 2297 // extensions. It should then omit the extensions field. 2298 ExpectOmitExtensions: true, 2299 }, 2300 }, 2301 }) 2302 2303 testCases = append(testCases, testCase{ 2304 testType: serverTest, 2305 name: "EmptyExtensions-ClientHello-" + ver.name, 2306 config: Config{ 2307 MinVersion: ver.version, 2308 MaxVersion: ver.version, 2309 SessionTicketsDisabled: true, 2310 Bugs: ProtocolBugs{ 2311 EmptyExtensions: true, 2312 // With no client extensions, the ServerHello must not have 2313 // extensions. It should then omit the extensions field. 2314 ExpectOmitExtensions: true, 2315 }, 2316 }, 2317 }) 2318 2319 testCases = append(testCases, testCase{ 2320 testType: clientTest, 2321 name: "OmitExtensions-ServerHello-" + ver.name, 2322 config: Config{ 2323 MinVersion: ver.version, 2324 MaxVersion: ver.version, 2325 SessionTicketsDisabled: true, 2326 Bugs: ProtocolBugs{ 2327 OmitExtensions: true, 2328 // Disable all ServerHello extensions so 2329 // OmitExtensions works. 2330 NoExtendedMasterSecret: true, 2331 NoRenegotiationInfo: true, 2332 NoOCSPStapling: true, 2333 NoSignedCertificateTimestamps: true, 2334 }, 2335 }, 2336 }) 2337 2338 testCases = append(testCases, testCase{ 2339 testType: clientTest, 2340 name: "EmptyExtensions-ServerHello-" + ver.name, 2341 config: Config{ 2342 MinVersion: ver.version, 2343 MaxVersion: ver.version, 2344 SessionTicketsDisabled: true, 2345 Bugs: ProtocolBugs{ 2346 EmptyExtensions: true, 2347 // Disable all ServerHello extensions so 2348 // EmptyExtensions works. 2349 NoExtendedMasterSecret: true, 2350 NoRenegotiationInfo: true, 2351 NoOCSPStapling: true, 2352 NoSignedCertificateTimestamps: true, 2353 }, 2354 }, 2355 }) 2356 } 2357} 2358