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 17func addVersionNegotiationTests() { 18 for _, protocol := range []protocol{tls, dtls, quic} { 19 for _, shimVers := range allVersions(protocol) { 20 // Assemble flags to disable all newer versions on the shim. 21 var flags []string 22 for _, vers := range allVersions(protocol) { 23 if vers.version > shimVers.version { 24 flags = append(flags, vers.excludeFlag) 25 } 26 } 27 28 flags2 := []string{"-max-version", shimVers.shimFlag(protocol)} 29 30 // Test configuring the runner's maximum version. 31 for _, runnerVers := range allVersions(protocol) { 32 expectedVersion := shimVers.version 33 if runnerVers.version < shimVers.version { 34 expectedVersion = runnerVers.version 35 } 36 37 suffix := shimVers.name + "-" + runnerVers.name 38 suffix += "-" + protocol.String() 39 40 // Determine the expected initial record-layer versions. 41 clientVers := shimVers.version 42 if clientVers > VersionTLS10 { 43 clientVers = VersionTLS10 44 } 45 clientVers = recordVersionToWire(clientVers, protocol) 46 serverVers := expectedVersion 47 if expectedVersion >= VersionTLS13 { 48 serverVers = VersionTLS12 49 } 50 serverVers = recordVersionToWire(serverVers, protocol) 51 52 testCases = append(testCases, testCase{ 53 protocol: protocol, 54 testType: clientTest, 55 name: "VersionNegotiation-Client-" + suffix, 56 config: Config{ 57 MaxVersion: runnerVers.version, 58 Bugs: ProtocolBugs{ 59 ExpectInitialRecordVersion: clientVers, 60 }, 61 }, 62 flags: flags, 63 expectations: connectionExpectations{ 64 version: expectedVersion, 65 }, 66 // The version name check does not recognize the 67 // |excludeFlag| construction in |flags|. 68 skipVersionNameCheck: true, 69 }) 70 testCases = append(testCases, testCase{ 71 protocol: protocol, 72 testType: clientTest, 73 name: "VersionNegotiation-Client2-" + suffix, 74 config: Config{ 75 MaxVersion: runnerVers.version, 76 Bugs: ProtocolBugs{ 77 ExpectInitialRecordVersion: clientVers, 78 }, 79 }, 80 flags: flags2, 81 expectations: connectionExpectations{ 82 version: expectedVersion, 83 }, 84 }) 85 86 testCases = append(testCases, testCase{ 87 protocol: protocol, 88 testType: serverTest, 89 name: "VersionNegotiation-Server-" + suffix, 90 config: Config{ 91 MaxVersion: runnerVers.version, 92 Bugs: ProtocolBugs{ 93 ExpectInitialRecordVersion: serverVers, 94 }, 95 }, 96 flags: flags, 97 expectations: connectionExpectations{ 98 version: expectedVersion, 99 }, 100 // The version name check does not recognize the 101 // |excludeFlag| construction in |flags|. 102 skipVersionNameCheck: true, 103 }) 104 testCases = append(testCases, testCase{ 105 protocol: protocol, 106 testType: serverTest, 107 name: "VersionNegotiation-Server2-" + suffix, 108 config: Config{ 109 MaxVersion: runnerVers.version, 110 Bugs: ProtocolBugs{ 111 ExpectInitialRecordVersion: serverVers, 112 }, 113 }, 114 flags: flags2, 115 expectations: connectionExpectations{ 116 version: expectedVersion, 117 }, 118 }) 119 } 120 } 121 } 122 123 // Test the version extension at all versions. 124 for _, protocol := range []protocol{tls, dtls, quic} { 125 for _, vers := range allVersions(protocol) { 126 suffix := vers.name + "-" + protocol.String() 127 128 testCases = append(testCases, testCase{ 129 protocol: protocol, 130 testType: serverTest, 131 name: "VersionNegotiationExtension-" + suffix, 132 config: Config{ 133 Bugs: ProtocolBugs{ 134 SendSupportedVersions: []uint16{0x1111, vers.wire(protocol), 0x2222}, 135 IgnoreTLS13DowngradeRandom: true, 136 }, 137 }, 138 expectations: connectionExpectations{ 139 version: vers.version, 140 }, 141 }) 142 } 143 } 144 145 // If all versions are unknown, negotiation fails. 146 testCases = append(testCases, testCase{ 147 testType: serverTest, 148 name: "NoSupportedVersions", 149 config: Config{ 150 Bugs: ProtocolBugs{ 151 SendSupportedVersions: []uint16{0x1111}, 152 }, 153 }, 154 shouldFail: true, 155 expectedError: ":UNSUPPORTED_PROTOCOL:", 156 }) 157 testCases = append(testCases, testCase{ 158 protocol: dtls, 159 testType: serverTest, 160 name: "NoSupportedVersions-DTLS", 161 config: Config{ 162 Bugs: ProtocolBugs{ 163 SendSupportedVersions: []uint16{0x1111}, 164 }, 165 }, 166 shouldFail: true, 167 expectedError: ":UNSUPPORTED_PROTOCOL:", 168 }) 169 170 testCases = append(testCases, testCase{ 171 testType: serverTest, 172 name: "ClientHelloVersionTooHigh", 173 config: Config{ 174 MaxVersion: VersionTLS13, 175 Bugs: ProtocolBugs{ 176 SendClientVersion: 0x0304, 177 OmitSupportedVersions: true, 178 IgnoreTLS13DowngradeRandom: true, 179 }, 180 }, 181 expectations: connectionExpectations{ 182 version: VersionTLS12, 183 }, 184 }) 185 186 testCases = append(testCases, testCase{ 187 testType: serverTest, 188 name: "ConflictingVersionNegotiation", 189 config: Config{ 190 Bugs: ProtocolBugs{ 191 SendClientVersion: VersionTLS12, 192 SendSupportedVersions: []uint16{VersionTLS11}, 193 IgnoreTLS13DowngradeRandom: true, 194 }, 195 }, 196 // The extension takes precedence over the ClientHello version. 197 expectations: connectionExpectations{ 198 version: VersionTLS11, 199 }, 200 }) 201 202 testCases = append(testCases, testCase{ 203 testType: serverTest, 204 name: "ConflictingVersionNegotiation-2", 205 config: Config{ 206 Bugs: ProtocolBugs{ 207 SendClientVersion: VersionTLS11, 208 SendSupportedVersions: []uint16{VersionTLS12}, 209 IgnoreTLS13DowngradeRandom: true, 210 }, 211 }, 212 // The extension takes precedence over the ClientHello version. 213 expectations: connectionExpectations{ 214 version: VersionTLS12, 215 }, 216 }) 217 218 // Test that TLS 1.2 isn't negotiated by the supported_versions extension in 219 // the ServerHello. 220 testCases = append(testCases, testCase{ 221 testType: clientTest, 222 name: "SupportedVersionSelection-TLS12", 223 config: Config{ 224 MaxVersion: VersionTLS12, 225 Bugs: ProtocolBugs{ 226 SendServerSupportedVersionExtension: VersionTLS12, 227 }, 228 }, 229 shouldFail: true, 230 expectedError: ":UNEXPECTED_EXTENSION:", 231 }) 232 233 // Test that the maximum version is selected regardless of the 234 // client-sent order. 235 testCases = append(testCases, testCase{ 236 testType: serverTest, 237 name: "IgnoreClientVersionOrder", 238 config: Config{ 239 Bugs: ProtocolBugs{ 240 SendSupportedVersions: []uint16{VersionTLS12, VersionTLS13}, 241 }, 242 }, 243 expectations: connectionExpectations{ 244 version: VersionTLS13, 245 }, 246 }) 247 248 // Test for version tolerance. 249 testCases = append(testCases, testCase{ 250 testType: serverTest, 251 name: "MinorVersionTolerance", 252 config: Config{ 253 Bugs: ProtocolBugs{ 254 SendClientVersion: 0x03ff, 255 OmitSupportedVersions: true, 256 IgnoreTLS13DowngradeRandom: true, 257 }, 258 }, 259 expectations: connectionExpectations{ 260 version: VersionTLS12, 261 }, 262 }) 263 testCases = append(testCases, testCase{ 264 testType: serverTest, 265 name: "MajorVersionTolerance", 266 config: Config{ 267 Bugs: ProtocolBugs{ 268 SendClientVersion: 0x0400, 269 OmitSupportedVersions: true, 270 IgnoreTLS13DowngradeRandom: true, 271 }, 272 }, 273 // TLS 1.3 must be negotiated with the supported_versions 274 // extension, not ClientHello.version. 275 expectations: connectionExpectations{ 276 version: VersionTLS12, 277 }, 278 }) 279 testCases = append(testCases, testCase{ 280 testType: serverTest, 281 name: "VersionTolerance-TLS13", 282 config: Config{ 283 Bugs: ProtocolBugs{ 284 // Although TLS 1.3 does not use 285 // ClientHello.version, it still tolerates high 286 // values there. 287 SendClientVersion: 0x0400, 288 }, 289 }, 290 expectations: connectionExpectations{ 291 version: VersionTLS13, 292 }, 293 }) 294 295 testCases = append(testCases, testCase{ 296 protocol: dtls, 297 testType: serverTest, 298 name: "MinorVersionTolerance-DTLS", 299 config: Config{ 300 Bugs: ProtocolBugs{ 301 SendClientVersion: 0xfe00, 302 OmitSupportedVersions: true, 303 IgnoreTLS13DowngradeRandom: true, 304 }, 305 }, 306 expectations: connectionExpectations{ 307 version: VersionTLS12, 308 }, 309 }) 310 testCases = append(testCases, testCase{ 311 protocol: dtls, 312 testType: serverTest, 313 name: "MajorVersionTolerance-DTLS", 314 config: Config{ 315 Bugs: ProtocolBugs{ 316 SendClientVersion: 0xfdff, 317 OmitSupportedVersions: true, 318 IgnoreTLS13DowngradeRandom: true, 319 }, 320 }, 321 expectations: connectionExpectations{ 322 version: VersionTLS12, 323 }, 324 }) 325 326 // Test that versions below 3.0 are rejected. 327 testCases = append(testCases, testCase{ 328 testType: serverTest, 329 name: "VersionTooLow", 330 config: Config{ 331 Bugs: ProtocolBugs{ 332 SendClientVersion: 0x0200, 333 OmitSupportedVersions: true, 334 }, 335 }, 336 shouldFail: true, 337 expectedError: ":UNSUPPORTED_PROTOCOL:", 338 }) 339 testCases = append(testCases, testCase{ 340 protocol: dtls, 341 testType: serverTest, 342 name: "VersionTooLow-DTLS", 343 config: Config{ 344 Bugs: ProtocolBugs{ 345 SendClientVersion: 0xffff, 346 OmitSupportedVersions: true, 347 }, 348 }, 349 shouldFail: true, 350 expectedError: ":UNSUPPORTED_PROTOCOL:", 351 }) 352 353 testCases = append(testCases, testCase{ 354 name: "ServerBogusVersion", 355 config: Config{ 356 Bugs: ProtocolBugs{ 357 SendServerHelloVersion: 0x1234, 358 }, 359 }, 360 shouldFail: true, 361 expectedError: ":UNSUPPORTED_PROTOCOL:", 362 }) 363 364 // Test TLS 1.3's downgrade signal. 365 for _, protocol := range []protocol{tls, dtls} { 366 for _, vers := range allVersions(protocol) { 367 if vers.version >= VersionTLS13 { 368 continue 369 } 370 clientShimError := "tls: downgrade from TLS 1.3 detected" 371 if vers.version < VersionTLS12 { 372 clientShimError = "tls: downgrade from TLS 1.2 detected" 373 } 374 // for _, test := range downgradeTests { 375 // The client should enforce the downgrade sentinel. 376 testCases = append(testCases, testCase{ 377 protocol: protocol, 378 name: "Downgrade-" + vers.name + "-Client-" + protocol.String(), 379 config: Config{ 380 Bugs: ProtocolBugs{ 381 NegotiateVersion: vers.wire(protocol), 382 }, 383 }, 384 expectations: connectionExpectations{ 385 version: vers.version, 386 }, 387 shouldFail: true, 388 expectedError: ":TLS13_DOWNGRADE:", 389 expectedLocalError: "remote error: illegal parameter", 390 }) 391 392 // The server should emit the downgrade signal. 393 testCases = append(testCases, testCase{ 394 protocol: protocol, 395 testType: serverTest, 396 name: "Downgrade-" + vers.name + "-Server-" + protocol.String(), 397 config: Config{ 398 Bugs: ProtocolBugs{ 399 SendSupportedVersions: []uint16{vers.wire(protocol)}, 400 }, 401 }, 402 expectations: connectionExpectations{ 403 version: vers.version, 404 }, 405 shouldFail: true, 406 expectedLocalError: clientShimError, 407 }) 408 } 409 } 410 411 // SSL 3.0 support has been removed. Test that the shim does not 412 // support it. 413 testCases = append(testCases, testCase{ 414 name: "NoSSL3-Client", 415 config: Config{ 416 MinVersion: VersionSSL30, 417 MaxVersion: VersionSSL30, 418 }, 419 shouldFail: true, 420 expectedLocalError: "tls: client did not offer any supported protocol versions", 421 }) 422 testCases = append(testCases, testCase{ 423 name: "NoSSL3-Client-Unsolicited", 424 config: Config{ 425 MinVersion: VersionSSL30, 426 MaxVersion: VersionSSL30, 427 Bugs: ProtocolBugs{ 428 // The above test asserts the client does not 429 // offer SSL 3.0 in the supported_versions 430 // list. Additionally assert that it rejects an 431 // unsolicited SSL 3.0 ServerHello. 432 NegotiateVersion: VersionSSL30, 433 }, 434 }, 435 shouldFail: true, 436 expectedError: ":UNSUPPORTED_PROTOCOL:", 437 expectedLocalError: "remote error: protocol version not supported", 438 }) 439 testCases = append(testCases, testCase{ 440 testType: serverTest, 441 name: "NoSSL3-Server", 442 config: Config{ 443 MinVersion: VersionSSL30, 444 MaxVersion: VersionSSL30, 445 }, 446 shouldFail: true, 447 expectedError: ":UNSUPPORTED_PROTOCOL:", 448 expectedLocalError: "remote error: protocol version not supported", 449 }) 450} 451 452func addMinimumVersionTests() { 453 for _, protocol := range []protocol{tls, dtls, quic} { 454 for _, shimVers := range allVersions(protocol) { 455 // Assemble flags to disable all older versions on the shim. 456 var flags []string 457 for _, vers := range allVersions(protocol) { 458 if vers.version < shimVers.version { 459 flags = append(flags, vers.excludeFlag) 460 } 461 } 462 463 flags2 := []string{"-min-version", shimVers.shimFlag(protocol)} 464 465 for _, runnerVers := range allVersions(protocol) { 466 suffix := shimVers.name + "-" + runnerVers.name 467 suffix += "-" + protocol.String() 468 469 var expectedVersion uint16 470 var shouldFail bool 471 var expectedError, expectedLocalError string 472 if runnerVers.version >= shimVers.version { 473 expectedVersion = runnerVers.version 474 } else { 475 shouldFail = true 476 expectedError = ":UNSUPPORTED_PROTOCOL:" 477 expectedLocalError = "remote error: protocol version not supported" 478 } 479 480 testCases = append(testCases, testCase{ 481 protocol: protocol, 482 testType: clientTest, 483 name: "MinimumVersion-Client-" + suffix, 484 config: Config{ 485 MaxVersion: runnerVers.version, 486 Bugs: ProtocolBugs{ 487 // Ensure the server does not decline to 488 // select a version (versions extension) or 489 // cipher (some ciphers depend on versions). 490 NegotiateVersion: runnerVers.wire(protocol), 491 IgnorePeerCipherPreferences: shouldFail, 492 }, 493 }, 494 flags: flags, 495 expectations: connectionExpectations{ 496 version: expectedVersion, 497 }, 498 shouldFail: shouldFail, 499 expectedError: expectedError, 500 expectedLocalError: expectedLocalError, 501 // The version name check does not recognize the 502 // |excludeFlag| construction in |flags|. 503 skipVersionNameCheck: true, 504 }) 505 testCases = append(testCases, testCase{ 506 protocol: protocol, 507 testType: clientTest, 508 name: "MinimumVersion-Client2-" + suffix, 509 config: Config{ 510 MaxVersion: runnerVers.version, 511 Bugs: ProtocolBugs{ 512 // Ensure the server does not decline to 513 // select a version (versions extension) or 514 // cipher (some ciphers depend on versions). 515 NegotiateVersion: runnerVers.wire(protocol), 516 IgnorePeerCipherPreferences: shouldFail, 517 }, 518 }, 519 flags: flags2, 520 expectations: connectionExpectations{ 521 version: expectedVersion, 522 }, 523 shouldFail: shouldFail, 524 expectedError: expectedError, 525 expectedLocalError: expectedLocalError, 526 }) 527 528 testCases = append(testCases, testCase{ 529 protocol: protocol, 530 testType: serverTest, 531 name: "MinimumVersion-Server-" + suffix, 532 config: Config{ 533 MaxVersion: runnerVers.version, 534 }, 535 flags: flags, 536 expectations: connectionExpectations{ 537 version: expectedVersion, 538 }, 539 shouldFail: shouldFail, 540 expectedError: expectedError, 541 expectedLocalError: expectedLocalError, 542 // The version name check does not recognize the 543 // |excludeFlag| construction in |flags|. 544 skipVersionNameCheck: true, 545 }) 546 testCases = append(testCases, testCase{ 547 protocol: protocol, 548 testType: serverTest, 549 name: "MinimumVersion-Server2-" + suffix, 550 config: Config{ 551 MaxVersion: runnerVers.version, 552 }, 553 flags: flags2, 554 expectations: connectionExpectations{ 555 version: expectedVersion, 556 }, 557 shouldFail: shouldFail, 558 expectedError: expectedError, 559 expectedLocalError: expectedLocalError, 560 }) 561 } 562 } 563 } 564} 565 566func addRecordVersionTests() { 567 for _, ver := range tlsVersions { 568 // Test that the record version is enforced. 569 testCases = append(testCases, testCase{ 570 name: "CheckRecordVersion-" + ver.name, 571 config: Config{ 572 MinVersion: ver.version, 573 MaxVersion: ver.version, 574 Bugs: ProtocolBugs{ 575 SendRecordVersion: 0x03ff, 576 }, 577 }, 578 shouldFail: true, 579 expectedError: ":WRONG_VERSION_NUMBER:", 580 }) 581 582 // Test that the ClientHello may use any record version, for 583 // compatibility reasons. 584 testCases = append(testCases, testCase{ 585 testType: serverTest, 586 name: "LooseInitialRecordVersion-" + ver.name, 587 config: Config{ 588 MinVersion: ver.version, 589 MaxVersion: ver.version, 590 Bugs: ProtocolBugs{ 591 SendInitialRecordVersion: 0x03ff, 592 }, 593 }, 594 }) 595 596 // Test that garbage ClientHello record versions are rejected. 597 testCases = append(testCases, testCase{ 598 testType: serverTest, 599 name: "GarbageInitialRecordVersion-" + ver.name, 600 config: Config{ 601 MinVersion: ver.version, 602 MaxVersion: ver.version, 603 Bugs: ProtocolBugs{ 604 SendInitialRecordVersion: 0xffff, 605 }, 606 }, 607 shouldFail: true, 608 expectedError: ":WRONG_VERSION_NUMBER:", 609 }) 610 } 611} 612