nss_bogo_shim.cc (39899B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 #include "config.h" 7 8 #include <algorithm> 9 #include <cstdlib> 10 #include <iostream> 11 #include <memory> 12 #include "nspr.h" 13 #include "nss.h" 14 #include "prio.h" 15 #include "prnetdb.h" 16 #include "secerr.h" 17 #include "ssl.h" 18 #include "ssl3prot.h" 19 #include "sslerr.h" 20 #include "sslproto.h" 21 #include "nss_scoped_ptrs.h" 22 #include "sslimpl.h" 23 #include "tls13ech.h" 24 #include "base64.h" 25 26 #include "nsskeys.h" 27 28 static const char* kVersionDisableFlags[] = {"no-ssl3", "no-tls1", "no-tls11", 29 "no-tls12", "no-tls13"}; 30 31 /* Default EarlyData dummy data determined by Bogo implementation. */ 32 const unsigned char kBogoDummyData[] = {'h', 'e', 'l', 'l', 'o'}; 33 34 bool exitCodeUnimplemented = false; 35 36 std::string FormatError(PRErrorCode code) { 37 return std::string(":") + PORT_ErrorToName(code) + ":" + ":" + 38 PORT_ErrorToString(code); 39 } 40 41 static void StringRemoveNewlines(std::string& str) { 42 str.erase(std::remove(str.begin(), str.end(), '\n'), str.cend()); 43 str.erase(std::remove(str.begin(), str.end(), '\r'), str.cend()); 44 } 45 46 class TestAgent { 47 public: 48 TestAgent(const Config& cfg) : cfg_(cfg) {} 49 50 ~TestAgent() {} 51 52 static std::unique_ptr<TestAgent> Create(const Config& cfg) { 53 std::unique_ptr<TestAgent> agent(new TestAgent(cfg)); 54 55 if (!agent->Init()) return nullptr; 56 57 return agent; 58 } 59 60 bool Init() { 61 if (!ConnectTcp()) { 62 return false; 63 } 64 65 if (!SetupKeys()) { 66 std::cerr << "Couldn't set up keys/certs\n"; 67 return false; 68 } 69 70 if (!SetupOptions()) { 71 std::cerr << "Couldn't configure socket\n"; 72 return false; 73 } 74 75 SECStatus rv = SSL_ResetHandshake(ssl_fd_.get(), cfg_.get<bool>("server")); 76 if (rv != SECSuccess) return false; 77 78 return true; 79 } 80 81 bool ConnectTcp() { 82 if (!(cfg_.get<bool>("ipv6") && OpenConnection("::1")) && 83 !OpenConnection("127.0.0.1")) { 84 return false; 85 } 86 87 ssl_fd_ = ScopedPRFileDesc(SSL_ImportFD(NULL, pr_fd_.get())); 88 if (!ssl_fd_) { 89 return false; 90 } 91 pr_fd_.release(); 92 93 return true; 94 } 95 96 bool OpenConnection(const char* ip) { 97 PRStatus prv; 98 PRNetAddr addr; 99 100 prv = PR_StringToNetAddr(ip, &addr); 101 102 if (prv != PR_SUCCESS) { 103 return false; 104 } 105 106 addr.inet.port = PR_htons(cfg_.get<int>("port")); 107 108 pr_fd_ = ScopedPRFileDesc(PR_OpenTCPSocket(addr.raw.family)); 109 if (!pr_fd_) return false; 110 111 prv = PR_Connect(pr_fd_.get(), &addr, PR_INTERVAL_NO_TIMEOUT); 112 if (prv != PR_SUCCESS) { 113 return false; 114 } 115 116 uint64_t shim_id = cfg_.get<int>("shim-id"); 117 uint8_t buf[8] = {0}; 118 for (size_t i = 0; i < 8; i++) { 119 buf[i] = shim_id & 0xff; 120 shim_id >>= 8; 121 } 122 int sent = PR_Write(pr_fd_.get(), buf, sizeof(buf)); 123 if (sent != sizeof(buf)) { 124 return false; 125 } 126 127 return true; 128 } 129 130 bool SetupKeys() { 131 SECStatus rv; 132 133 if (cfg_.get<std::string>("key-file") != "") { 134 key_ = ScopedSECKEYPrivateKey( 135 ReadPrivateKey(cfg_.get<std::string>("key-file"))); 136 if (!key_) return false; 137 } 138 if (cfg_.get<std::string>("cert-file") != "") { 139 cert_ = ScopedCERTCertificate( 140 ReadCertificate(cfg_.get<std::string>("cert-file"))); 141 if (!cert_) return false; 142 } 143 144 // Needed because certs are not entirely valid. 145 rv = SSL_AuthCertificateHook(ssl_fd_.get(), AuthCertificateHook, this); 146 if (rv != SECSuccess) return false; 147 148 if (cfg_.get<bool>("server")) { 149 // Server 150 rv = SSL_ConfigServerCert(ssl_fd_.get(), cert_.get(), key_.get(), nullptr, 151 0); 152 if (rv != SECSuccess) { 153 std::cerr << "Couldn't configure server cert\n"; 154 return false; 155 } 156 157 } else if (key_ && cert_) { 158 // Client. 159 rv = 160 SSL_GetClientAuthDataHook(ssl_fd_.get(), GetClientAuthDataHook, this); 161 if (rv != SECSuccess) return false; 162 } 163 164 return true; 165 } 166 167 static bool ConvertFromWireVersion(SSLProtocolVariant variant, 168 int wire_version, uint16_t* lib_version) { 169 // These default values are used when {min,max}-version isn't given. 170 if (wire_version == 0 || wire_version == 0xffff) { 171 *lib_version = static_cast<uint16_t>(wire_version); 172 return true; 173 } 174 175 #ifdef TLS_1_3_DRAFT_VERSION 176 if (wire_version == (0x7f00 | TLS_1_3_DRAFT_VERSION)) { 177 // N.B. SSL_LIBRARY_VERSION_DTLS_1_3_WIRE == SSL_LIBRARY_VERSION_TLS_1_3 178 wire_version = SSL_LIBRARY_VERSION_TLS_1_3; 179 } 180 #endif 181 182 if (variant == ssl_variant_datagram) { 183 switch (wire_version) { 184 case SSL_LIBRARY_VERSION_DTLS_1_0_WIRE: 185 *lib_version = SSL_LIBRARY_VERSION_DTLS_1_0; 186 break; 187 case SSL_LIBRARY_VERSION_DTLS_1_2_WIRE: 188 *lib_version = SSL_LIBRARY_VERSION_DTLS_1_2; 189 break; 190 case SSL_LIBRARY_VERSION_DTLS_1_3_WIRE: 191 *lib_version = SSL_LIBRARY_VERSION_DTLS_1_3; 192 break; 193 default: 194 std::cerr << "Unrecognized DTLS version " << wire_version << ".\n"; 195 return false; 196 } 197 } else { 198 if (wire_version < SSL_LIBRARY_VERSION_3_0 || 199 wire_version > SSL_LIBRARY_VERSION_TLS_1_3) { 200 std::cerr << "Unrecognized TLS version " << wire_version << ".\n"; 201 return false; 202 } 203 *lib_version = static_cast<uint16_t>(wire_version); 204 } 205 return true; 206 } 207 208 bool GetVersionRange(SSLVersionRange* range_out, SSLProtocolVariant variant) { 209 SSLVersionRange supported; 210 if (SSL_VersionRangeGetSupported(variant, &supported) != SECSuccess) { 211 return false; 212 } 213 214 uint16_t min_allowed; 215 uint16_t max_allowed; 216 if (!ConvertFromWireVersion(variant, cfg_.get<int>("min-version"), 217 &min_allowed)) { 218 return false; 219 } 220 if (!ConvertFromWireVersion(variant, cfg_.get<int>("max-version"), 221 &max_allowed)) { 222 return false; 223 } 224 225 min_allowed = std::max(min_allowed, supported.min); 226 max_allowed = std::min(max_allowed, supported.max); 227 228 bool found_min = false; 229 bool found_max = false; 230 // Ignore -no-ssl3, because SSLv3 is never supported. 231 for (size_t i = 1; i < PR_ARRAY_SIZE(kVersionDisableFlags); ++i) { 232 auto version = 233 static_cast<uint16_t>(SSL_LIBRARY_VERSION_TLS_1_0 + (i - 1)); 234 if (variant == ssl_variant_datagram) { 235 // In DTLS mode, the -no-tlsN flags refer to DTLS versions, 236 // but NSS wants the corresponding TLS versions. 237 if (version == SSL_LIBRARY_VERSION_TLS_1_1) { 238 // DTLS 1.1 doesn't exist. 239 continue; 240 } 241 if (version == SSL_LIBRARY_VERSION_TLS_1_0) { 242 version = SSL_LIBRARY_VERSION_DTLS_1_0; 243 } 244 } 245 246 if (version < min_allowed) { 247 continue; 248 } 249 if (version > max_allowed) { 250 break; 251 } 252 253 const bool allowed = !cfg_.get<bool>(kVersionDisableFlags[i]); 254 255 if (!found_min && allowed) { 256 found_min = true; 257 range_out->min = version; 258 } 259 if (found_min && !found_max) { 260 if (allowed) { 261 range_out->max = version; 262 } else { 263 found_max = true; 264 } 265 } 266 if (found_max && allowed) { 267 std::cerr << "Discontiguous version range.\n"; 268 return false; 269 } 270 } 271 272 if (!found_min) { 273 std::cerr << "All versions disabled.\n"; 274 } 275 return found_min; 276 } 277 278 bool SetupOptions() { 279 SECStatus rv = 280 SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_TLS13_COMPAT_MODE, PR_TRUE); 281 if (rv != SECSuccess) return false; 282 283 rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_SESSION_TICKETS, PR_TRUE); 284 if (rv != SECSuccess) return false; 285 286 SSLVersionRange vrange; 287 if (!GetVersionRange(&vrange, ssl_variant_stream)) return false; 288 289 rv = SSL_VersionRangeSet(ssl_fd_.get(), &vrange); 290 if (rv != SECSuccess) return false; 291 292 SSLVersionRange verify_vrange; 293 rv = SSL_VersionRangeGet(ssl_fd_.get(), &verify_vrange); 294 if (rv != SECSuccess) return false; 295 if (vrange.min != verify_vrange.min || vrange.max != verify_vrange.max) 296 return false; 297 298 rv = SSL_OptionSet(ssl_fd_.get(), SSL_NO_CACHE, false); 299 if (rv != SECSuccess) return false; 300 301 auto alpn = cfg_.get<std::string>("advertise-alpn"); 302 if (!alpn.empty()) { 303 assert(!cfg_.get<bool>("server")); 304 305 rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_ALPN, PR_TRUE); 306 if (rv != SECSuccess) return false; 307 308 rv = SSL_SetNextProtoNego( 309 ssl_fd_.get(), reinterpret_cast<const unsigned char*>(alpn.c_str()), 310 alpn.size()); 311 if (rv != SECSuccess) return false; 312 } 313 314 // Set supported signature schemes. 315 auto sign_prefs = cfg_.get<std::vector<int>>("signing-prefs"); 316 auto verify_prefs = cfg_.get<std::vector<int>>("verify-prefs"); 317 if (sign_prefs.empty()) { 318 sign_prefs = verify_prefs; 319 } else if (!verify_prefs.empty()) { 320 return false; // Both shouldn't be set. 321 } 322 if (!sign_prefs.empty()) { 323 std::vector<SSLSignatureScheme> sig_schemes; 324 std::transform( 325 sign_prefs.begin(), sign_prefs.end(), std::back_inserter(sig_schemes), 326 [](int scheme) { return static_cast<SSLSignatureScheme>(scheme); }); 327 328 rv = SSL_SignatureSchemePrefSet( 329 ssl_fd_.get(), sig_schemes.data(), 330 static_cast<unsigned int>(sig_schemes.size())); 331 if (rv != SECSuccess) return false; 332 } 333 334 if (cfg_.get<bool>("fallback-scsv")) { 335 rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_FALLBACK_SCSV, PR_TRUE); 336 if (rv != SECSuccess) return false; 337 } 338 339 if (cfg_.get<bool>("false-start")) { 340 rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_FALSE_START, PR_TRUE); 341 if (rv != SECSuccess) return false; 342 } 343 344 if (cfg_.get<bool>("enable-ocsp-stapling")) { 345 rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_OCSP_STAPLING, PR_TRUE); 346 if (rv != SECSuccess) return false; 347 } 348 349 bool requireClientCert = cfg_.get<bool>("require-any-client-certificate"); 350 if (requireClientCert || cfg_.get<bool>("verify-peer")) { 351 assert(cfg_.get<bool>("server")); 352 353 rv = SSL_OptionSet(ssl_fd_.get(), SSL_REQUEST_CERTIFICATE, PR_TRUE); 354 if (rv != SECSuccess) return false; 355 356 rv = SSL_OptionSet( 357 ssl_fd_.get(), SSL_REQUIRE_CERTIFICATE, 358 requireClientCert ? SSL_REQUIRE_ALWAYS : SSL_REQUIRE_NO_ERROR); 359 if (rv != SECSuccess) return false; 360 } 361 362 if (!cfg_.get<bool>("server")) { 363 auto hostname = cfg_.get<std::string>("host-name"); 364 if (!hostname.empty()) { 365 rv = SSL_SetURL(ssl_fd_.get(), hostname.c_str()); 366 } else { 367 // Needed to make resumption work. 368 rv = SSL_SetURL(ssl_fd_.get(), "server"); 369 } 370 if (rv != SECSuccess) return false; 371 372 // Setup ECH configs on client if provided 373 auto echConfigList = cfg_.get<std::string>("ech-config-list"); 374 if (!echConfigList.empty()) { 375 unsigned int binLen; 376 auto bin = ATOB_AsciiToData(echConfigList.c_str(), &binLen); 377 rv = SSLExp_SetClientEchConfigs(ssl_fd_.get(), bin, binLen); 378 if (rv != SECSuccess) return false; 379 free(bin); 380 } 381 382 if (cfg_.get<bool>("enable-grease")) { 383 rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_GREASE, PR_TRUE); 384 if (rv != SECSuccess) return false; 385 } 386 387 if (cfg_.get<bool>("permute-extensions")) { 388 rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_CH_EXTENSION_PERMUTATION, 389 PR_TRUE); 390 if (rv != SECSuccess) return false; 391 } 392 393 } else { 394 // GREASE - BoGo expects servers to enable GREASE by default 395 rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_GREASE, PR_TRUE); 396 if (rv != SECSuccess) return false; 397 } 398 399 rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_EXTENDED_MASTER_SECRET, 400 PR_TRUE); 401 if (rv != SECSuccess) return false; 402 403 if (cfg_.get<bool>("server")) { 404 // BoGo expects servers to enable ECH (backend) by default 405 rv = SSLExp_EnableTls13BackendEch(ssl_fd_.get(), true); 406 if (rv != SECSuccess) return false; 407 } 408 409 if (cfg_.get<bool>("enable-ech-grease")) { 410 rv = SSLExp_EnableTls13GreaseEch(ssl_fd_.get(), true); 411 if (rv != SECSuccess) return false; 412 } 413 414 if (cfg_.get<bool>("enable-early-data")) { 415 rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_0RTT_DATA, PR_TRUE); 416 if (rv != SECSuccess) return false; 417 } 418 419 if (!ConfigureGroups()) return false; 420 421 if (!ConfigureCiphers()) return false; 422 423 return true; 424 } 425 426 bool ConfigureGroups() { 427 auto curves = cfg_.get<std::vector<int>>("curves"); 428 if (curves.size() > 0) { 429 std::vector<SSLNamedGroup> groups; 430 std::transform( 431 curves.begin(), curves.end(), std::back_inserter(groups), 432 [](int curve) { return static_cast<SSLNamedGroup>(curve); }); 433 SECStatus rv = 434 SSL_NamedGroupConfig(ssl_fd_.get(), &groups[0], groups.size()); 435 if (rv != SECSuccess) { 436 return false; 437 } 438 // Xyber768 is disabled by policy by default, so if it's requested 439 // we need to update the policy flags as well. 440 for (auto group : groups) { 441 if (group == ssl_grp_kem_xyber768d00) { 442 NSS_SetAlgorithmPolicy(SEC_OID_XYBER768D00, NSS_USE_ALG_IN_SSL_KX, 0); 443 } 444 } 445 } 446 447 return true; 448 } 449 450 bool ConfigureCiphers() { 451 auto cipherList = cfg_.get<std::string>("nss-cipher"); 452 453 if (cipherList.empty()) { 454 return EnableNonExportCiphers(); 455 } 456 457 for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) { 458 SSLCipherSuiteInfo csinfo; 459 std::string::size_type n; 460 SECStatus rv = SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i], &csinfo, 461 sizeof(csinfo)); 462 if (rv != SECSuccess) { 463 return false; 464 } 465 466 // Check if cipherList contains the name of the Cipher Suite and 467 // enable/disable accordingly. 468 n = cipherList.find(csinfo.cipherSuiteName, 0); 469 if (std::string::npos == n) { 470 rv = SSL_CipherPrefSet(ssl_fd_.get(), SSL_ImplementedCiphers[i], 471 PR_FALSE); 472 } else { 473 rv = SSL_CipherPrefSet(ssl_fd_.get(), SSL_ImplementedCiphers[i], 474 PR_TRUE); 475 } 476 if (rv != SECSuccess) { 477 return false; 478 } 479 } 480 return true; 481 } 482 483 bool EnableNonExportCiphers() { 484 for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) { 485 SSLCipherSuiteInfo csinfo; 486 487 SECStatus rv = SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i], &csinfo, 488 sizeof(csinfo)); 489 if (rv != SECSuccess) { 490 return false; 491 } 492 493 rv = SSL_CipherPrefSet(ssl_fd_.get(), SSL_ImplementedCiphers[i], PR_TRUE); 494 if (rv != SECSuccess) { 495 return false; 496 } 497 } 498 return true; 499 } 500 501 // Dummy auth certificate hook. 502 static SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd, 503 PRBool checksig, PRBool isServer) { 504 return SECSuccess; 505 } 506 507 static SECStatus GetClientAuthDataHook(void* self, PRFileDesc* fd, 508 CERTDistNames* caNames, 509 CERTCertificate** cert, 510 SECKEYPrivateKey** privKey) { 511 TestAgent* a = static_cast<TestAgent*>(self); 512 *cert = CERT_DupCertificate(a->cert_.get()); 513 *privKey = SECKEY_CopyPrivateKey(a->key_.get()); 514 return SECSuccess; 515 } 516 517 SECStatus Handshake() { return SSL_ForceHandshake(ssl_fd_.get()); } 518 519 // Implement a trivial echo client/server. Read bytes from the other side, 520 // flip all the bits, and send them back. 521 SECStatus ReadWrite() { 522 for (;;) { 523 uint8_t block[512]; 524 int32_t rv = PR_Read(ssl_fd_.get(), block, sizeof(block)); 525 if (rv < 0) { 526 std::cerr << "Failure reading\n"; 527 return SECFailure; 528 } 529 if (rv == 0) return SECSuccess; 530 531 int32_t len = rv; 532 for (int32_t i = 0; i < len; ++i) { 533 block[i] ^= 0xff; 534 } 535 536 rv = PR_Write(ssl_fd_.get(), block, len); 537 if (rv != len) { 538 std::cerr << "Write failure\n"; 539 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 540 return SECFailure; 541 } 542 } 543 } 544 545 // Write bytes to the other side then read them back and check 546 // that they were correctly XORed as in ReadWrite. 547 SECStatus WriteRead() { 548 static const uint8_t ch = 'E'; 549 550 // We do 600-byte blocks to provide mis-alignment of the 551 // reader and writer. 552 uint8_t block[600]; 553 memset(block, ch, sizeof(block)); 554 int32_t rv = PR_Write(ssl_fd_.get(), block, sizeof(block)); 555 if (rv != sizeof(block)) { 556 std::cerr << "Write failure\n"; 557 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 558 return SECFailure; 559 } 560 561 size_t left = sizeof(block); 562 while (left) { 563 rv = PR_Read(ssl_fd_.get(), block, left); 564 if (rv < 0) { 565 std::cerr << "Failure reading\n"; 566 return SECFailure; 567 } 568 if (rv == 0) { 569 PORT_SetError(SEC_ERROR_INPUT_LEN); 570 return SECFailure; 571 } 572 573 int32_t len = rv; 574 for (int32_t i = 0; i < len; ++i) { 575 if (block[i] != (ch ^ 0xff)) { 576 PORT_SetError(SEC_ERROR_BAD_DATA); 577 return SECFailure; 578 } 579 } 580 left -= len; 581 } 582 return SECSuccess; 583 } 584 585 SECStatus CheckALPN(std::string expectedALPN) { 586 SECStatus rv; 587 SSLNextProtoState state; 588 char chosen[256]; 589 unsigned int chosen_len; 590 591 rv = SSL_GetNextProto(ssl_fd_.get(), &state, 592 reinterpret_cast<unsigned char*>(chosen), &chosen_len, 593 sizeof(chosen)); 594 if (rv != SECSuccess) { 595 PRErrorCode err = PR_GetError(); 596 std::cerr << "SSL_GetNextProto failed with error=" << FormatError(err) 597 << std::endl; 598 return SECFailure; 599 } 600 601 assert(chosen_len <= sizeof(chosen)); 602 if (std::string(chosen, chosen_len) != expectedALPN) { 603 std::cerr << "Expexted ALPN (" << expectedALPN << ") != Choosen ALPN (" 604 << std::string(chosen, chosen_len) << ")" << std::endl; 605 return SECFailure; 606 } 607 608 return SECSuccess; 609 } 610 611 SECStatus AdvertiseALPN(std::string alpn) { 612 return SSL_SetNextProtoNego( 613 ssl_fd_.get(), reinterpret_cast<const unsigned char*>(alpn.c_str()), 614 alpn.size()); 615 } 616 617 /* Certificate Encoding/Decoding Shrinking functions 618 * See 619 * https://boringssl.googlesource.com/boringssl/+/master/ssl/test/runner/runner.go#16168 620 */ 621 static SECStatus certCompressionShrinkEncode(const SECItem* input, 622 SECItem* output) { 623 if (input == NULL || input->data == NULL) { 624 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); 625 return SECFailure; 626 } 627 628 if (input->len < 2) { 629 std::cerr << "Certificate is too short. " << std::endl; 630 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); 631 return SECFailure; 632 } 633 634 SECITEM_AllocItem(NULL, output, input->len - 2); 635 if (output == NULL || output->data == NULL) { 636 return SECFailure; 637 } 638 639 /* The shrinking encoding primitive expects the first two bytes of a 640 * certificate to be equal to 0. */ 641 if (input->data[0] != 0 || input->data[1] != 0) { 642 std::cerr << "Cannot compress certificate message." << std::endl; 643 return SECFailure; 644 } 645 646 for (size_t i = 0; i < output->len; i++) { 647 output->data[i] = input->data[i + 2]; 648 } 649 return SECSuccess; 650 } 651 652 static SECStatus certCompressionShrinkDecode(const SECItem* input, 653 unsigned char* output, 654 size_t outputLen, 655 size_t* usedLen) { 656 if (input == NULL || input->data == NULL) { 657 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); 658 return SECFailure; 659 } 660 661 if (output == NULL || outputLen != input->len + 2) { 662 return SECFailure; 663 } 664 665 output[0] = 0; 666 output[1] = 0; 667 for (size_t i = 0; i < input->len; i++) { 668 output[i + 2] = input->data[i]; 669 } 670 671 *usedLen = outputLen; 672 return SECSuccess; 673 } 674 675 /* Certificate Encoding/Decoding Expanding functions 676 * See 677 * https://boringssl.googlesource.com/boringssl/+/master/ssl/test/runner/runner.go#16186 678 */ 679 static SECStatus certCompressionExpandEncode(const SECItem* input, 680 SECItem* output) { 681 if (input == NULL || input->data == NULL) { 682 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); 683 return SECFailure; 684 } 685 686 SECITEM_AllocItem(NULL, output, input->len + 4); 687 688 if (output == NULL || output->data == NULL) { 689 return SECFailure; 690 } 691 692 output->data[0] = 1; 693 output->data[1] = 2; 694 output->data[2] = 3; 695 output->data[3] = 4; 696 for (size_t i = 0; i < input->len; i++) { 697 output->data[i + 4] = input->data[i]; 698 } 699 700 return SECSuccess; 701 } 702 703 static SECStatus certCompressionExpandDecode(const SECItem* input, 704 unsigned char* output, 705 size_t outputLen, 706 size_t* usedLen) { 707 if (input == NULL || input->data == NULL) { 708 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); 709 return SECFailure; 710 } 711 712 if (input->len < 4) { 713 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); 714 std::cerr << "Certificate is too short. " << std::endl; 715 return SECFailure; 716 } 717 718 if (output == NULL || outputLen != input->len - 4) { 719 return SECFailure; 720 } 721 722 /* See the corresponding compression function. */ 723 if (input->data[0] != 1 || input->data[1] != 2 || input->data[2] != 3 || 724 input->data[3] != 4) { 725 std::cerr << "Cannot decompress certificate message." << std::endl; 726 return SECFailure; 727 } 728 729 for (size_t i = 0; i < outputLen; i++) { 730 output[i] = input->data[i + 4]; 731 } 732 733 *usedLen = outputLen; 734 return SECSuccess; 735 } 736 737 /* Certificate Encoding/Decoding Random functions 738 * See 739 * https://boringssl.googlesource.com/boringssl/+/master/ssl/test/runner/runner.go#16201 740 */ 741 static SECStatus certCompressionRandomEncode(const SECItem* input, 742 SECItem* output) { 743 if (input == NULL || input->data == NULL) { 744 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); 745 return SECFailure; 746 } 747 748 SECITEM_AllocItem(NULL, output, input->len + 1); 749 750 if (output == NULL || output->data == NULL) { 751 return SECFailure; 752 } 753 754 SECStatus rv = PK11_GenerateRandom(output->data, 1); 755 756 if (rv != SECSuccess) { 757 std::cerr << "Failed to generate randomness. " << std::endl; 758 return SECFailure; 759 } 760 761 for (size_t i = 0; i < input->len; i++) { 762 output->data[i + 1] = input->data[i]; 763 } 764 return SECSuccess; 765 } 766 767 static SECStatus certCompressionRandomDecode(const SECItem* input, 768 unsigned char* output, 769 size_t outputLen, 770 size_t* usedLen) { 771 if (input == NULL || input->data == NULL) { 772 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); 773 return SECFailure; 774 } 775 776 if (input->len < 1) { 777 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); 778 std::cerr << "Certificate is too short. " << std::endl; 779 return SECFailure; 780 } 781 782 if (output == NULL || outputLen != input->len - 1) { 783 return SECFailure; 784 } 785 786 for (size_t i = 0; i < outputLen; i++) { 787 output[i] = input->data[i + 1]; 788 } 789 790 *usedLen = outputLen; 791 return SECSuccess; 792 } 793 794 SECStatus DoExchange(bool resuming) { 795 SECStatus rv; 796 int earlyDataSent = 0; 797 std::string str; 798 sslSocket* ss = ssl_FindSocket(ssl_fd_.get()); 799 if (!ss) { 800 return SECFailure; 801 } 802 if (cfg_.get<bool>("install-cert-compression-algs")) { 803 SSLCertificateCompressionAlgorithm t = { 804 (SSLCertificateCompressionAlgorithmID)0xff01, 805 "shrinkingCompressionAlg", certCompressionShrinkEncode, 806 certCompressionShrinkDecode}; 807 808 SSLCertificateCompressionAlgorithm t1 = { 809 (SSLCertificateCompressionAlgorithmID)0xff02, 810 "expandingCompressionAlg", certCompressionExpandEncode, 811 certCompressionExpandDecode}; 812 813 SSLCertificateCompressionAlgorithm t2 = { 814 (SSLCertificateCompressionAlgorithmID)0xff03, "randomCompressionAlg", 815 certCompressionRandomEncode, certCompressionRandomDecode}; 816 817 SSLExp_SetCertificateCompressionAlgorithm(ssl_fd_.get(), t); 818 SSLExp_SetCertificateCompressionAlgorithm(ssl_fd_.get(), t1); 819 SSLExp_SetCertificateCompressionAlgorithm(ssl_fd_.get(), t2); 820 } 821 822 /* Apply resumption SSL options (if any). */ 823 if (resuming) { 824 /* Client options */ 825 if (!cfg_.get<bool>("server")) { 826 auto resumeEchConfigList = 827 cfg_.get<std::string>("on-resume-ech-config-list"); 828 if (!resumeEchConfigList.empty()) { 829 unsigned int binLen; 830 auto bin = ATOB_AsciiToData(resumeEchConfigList.c_str(), &binLen); 831 rv = SSLExp_SetClientEchConfigs(ssl_fd_.get(), bin, binLen); 832 if (rv != SECSuccess) { 833 PRErrorCode err = PR_GetError(); 834 std::cerr << "Setting up resumption ECH configs failed with error=" 835 << err << FormatError(err) << std::endl; 836 } 837 free(bin); 838 } 839 840 str = cfg_.get<std::string>("on-resume-advertise-alpn"); 841 if (!str.empty()) { 842 if (AdvertiseALPN(str) != SECSuccess) { 843 PRErrorCode err = PR_GetError(); 844 std::cerr << "Setting up resumption ALPN failed with error=" << err 845 << FormatError(err) << std::endl; 846 } 847 } 848 } 849 850 } else { /* Explicitly not on resume (on initial) */ 851 /* Client options */ 852 if (!cfg_.get<bool>("server")) { 853 str = cfg_.get<std::string>("on-initial-advertise-alpn"); 854 if (!str.empty()) { 855 if (AdvertiseALPN(str) != SECSuccess) { 856 PRErrorCode err = PR_GetError(); 857 std::cerr << "Setting up initial ALPN failed with error=" << err 858 << FormatError(err) << std::endl; 859 } 860 } 861 } 862 } 863 864 /* If client send ClientHello. */ 865 if (!cfg_.get<bool>("server")) { 866 ssl_Get1stHandshakeLock(ss); 867 rv = ssl_BeginClientHandshake(ss); 868 ssl_Release1stHandshakeLock(ss); 869 if (rv != SECSuccess) { 870 PRErrorCode err = PR_GetError(); 871 std::cerr << "Handshake failed with error=" << err << FormatError(err) 872 << std::endl; 873 return SECFailure; 874 } 875 876 /* If the client is resuming. */ 877 if (ss->statelessResume) { 878 SSLPreliminaryChannelInfo pinfo; 879 rv = SSL_GetPreliminaryChannelInfo(ssl_fd_.get(), &pinfo, 880 sizeof(SSLPreliminaryChannelInfo)); 881 if (rv != SECSuccess) { 882 PRErrorCode err = PR_GetError(); 883 std::cerr << "SSL_GetPreliminaryChannelInfo failed with " << err 884 << std::endl; 885 return SECFailure; 886 } 887 888 /* Check that the used ticket supports early data. */ 889 if (cfg_.get<bool>("expect-ticket-supports-early-data")) { 890 if (!pinfo.ticketSupportsEarlyData) { 891 std::cerr << "Expected ticket to support EarlyData" << std::endl; 892 return SECFailure; 893 } 894 } 895 896 /* If the client should send EarlyData. */ 897 if (cfg_.get<bool>("on-resume-shim-writes-first")) { 898 earlyDataSent = 899 ssl_SecureWrite(ss, kBogoDummyData, sizeof(kBogoDummyData)); 900 if (earlyDataSent < 0) { 901 std::cerr << "Sending of EarlyData failed" << std::endl; 902 return SECFailure; 903 } 904 } 905 906 if (cfg_.get<bool>("expect-no-offer-early-data")) { 907 if (earlyDataSent) { 908 std::cerr << "Unexpectedly offered EarlyData" << std::endl; 909 return SECFailure; 910 } 911 } 912 } 913 } 914 915 /* As server start, as client continue handshake. */ 916 rv = Handshake(); 917 918 /* Retry config evaluation must be done before error handling since 919 * handshake failure is intended on ech_required tests. */ 920 if (cfg_.get<bool>("expect-no-ech-retry-configs")) { 921 if (ss->xtnData.ech && ss->xtnData.ech->retryConfigsValid) { 922 std::cerr << "Unexpectedly received ECH retry configs" << std::endl; 923 return SECFailure; 924 } 925 } 926 927 /* If given, verify received retry configs before error handling. */ 928 std::string expectedRCs64 = 929 cfg_.get<std::string>("expect-ech-retry-configs"); 930 if (!expectedRCs64.empty()) { 931 SECItem receivedRCs; 932 933 /* Get received RetryConfigs. */ 934 if (SSLExp_GetEchRetryConfigs(ssl_fd_.get(), &receivedRCs) != 935 SECSuccess) { 936 std::cerr << "Failed to get ECH retry configs." << std::endl; 937 return SECFailure; 938 } 939 940 /* (Re-)Encode received configs to compare with expected ASCII string. */ 941 std::string receivedRCs64( 942 BTOA_DataToAscii(receivedRCs.data, receivedRCs.len)); 943 /* Remove newlines (for unknown reasons) added during b64 encoding. */ 944 StringRemoveNewlines(receivedRCs64); 945 946 if (receivedRCs64 != expectedRCs64) { 947 std::cerr << "Received ECH retry configs did not match expected retry " 948 "configs." 949 << std::endl; 950 return SECFailure; 951 } 952 } 953 954 /* Check if handshake succeeded. */ 955 if (rv != SECSuccess) { 956 PRErrorCode err = PR_GetError(); 957 std::cerr << "Handshake failed with error=" << err << FormatError(err) 958 << std::endl; 959 return SECFailure; 960 } 961 962 /* If parts of data was sent as EarlyData make sure to send possibly 963 * unsent rest. This is required to pass bogo resumption tests. */ 964 if (earlyDataSent && earlyDataSent < int(sizeof(kBogoDummyData))) { 965 int toSend = sizeof(kBogoDummyData) - earlyDataSent; 966 earlyDataSent = 967 ssl_SecureWrite(ss, &kBogoDummyData[earlyDataSent], toSend); 968 if (earlyDataSent != toSend) { 969 std::cerr 970 << "Could not send rest of EarlyData after handshake completion" 971 << std::endl; 972 return SECFailure; 973 } 974 } 975 976 if (cfg_.get<bool>("write-then-read")) { 977 rv = WriteRead(); 978 if (rv != SECSuccess) { 979 PRErrorCode err = PR_GetError(); 980 std::cerr << "WriteRead failed with error=" << FormatError(err) 981 << std::endl; 982 return SECFailure; 983 } 984 } else { 985 rv = ReadWrite(); 986 if (rv != SECSuccess) { 987 PRErrorCode err = PR_GetError(); 988 std::cerr << "ReadWrite failed with error=" << FormatError(err) 989 << std::endl; 990 return SECFailure; 991 } 992 } 993 994 SSLChannelInfo info; 995 rv = SSL_GetChannelInfo(ssl_fd_.get(), &info, sizeof(info)); 996 if (rv != SECSuccess) { 997 PRErrorCode err = PR_GetError(); 998 std::cerr << "SSL_GetChannelInfo failed with error=" << FormatError(err) 999 << std::endl; 1000 return SECFailure; 1001 } 1002 1003 auto sig_alg = cfg_.get<int>("expect-peer-signature-algorithm"); 1004 if (sig_alg) { 1005 auto expected = static_cast<SSLSignatureScheme>(sig_alg); 1006 if (info.signatureScheme != expected) { 1007 std::cerr << "Unexpected signature scheme" << std::endl; 1008 return SECFailure; 1009 } 1010 } 1011 1012 auto curve_id = cfg_.get<int>("expect-curve-id"); 1013 if (curve_id) { 1014 auto expected = static_cast<SSLNamedGroup>(curve_id); 1015 if (info.keaGroup != expected && !(info.keaGroup == ssl_grp_none && 1016 info.originalKeaGroup == expected)) { 1017 std::cerr << "Unexpected named group" << std::endl; 1018 return SECFailure; 1019 } 1020 } 1021 1022 if (cfg_.get<bool>("expect-ech-accept")) { 1023 if (!info.echAccepted) { 1024 std::cerr << "Expected ECH" << std::endl; 1025 return SECFailure; 1026 } 1027 } 1028 1029 if (cfg_.get<bool>("expect-hrr")) { 1030 if (!ss->ssl3.hs.helloRetry) { 1031 std::cerr << "Expected HRR" << std::endl; 1032 return SECFailure; 1033 } 1034 } 1035 1036 str = cfg_.get<std::string>("expect-alpn"); 1037 if (!str.empty()) { 1038 if (CheckALPN(str) != SECSuccess) { 1039 std::cerr << "Unexpected ALPN" << std::endl; 1040 return SECFailure; 1041 } 1042 } 1043 1044 /* if resumed */ 1045 if (info.resumed) { 1046 if (cfg_.get<bool>("expect-session-miss")) { 1047 std::cerr << "Expected reject Resume" << std::endl; 1048 return SECFailure; 1049 } 1050 1051 if (cfg_.get<bool>("on-resume-expect-ech-accept")) { 1052 if (!info.echAccepted) { 1053 std::cerr << "Expected ECH on Resume" << std::endl; 1054 return SECFailure; 1055 } 1056 } 1057 1058 if (cfg_.get<bool>("on-resume-expect-reject-early-data")) { 1059 if (info.earlyDataAccepted) { 1060 std::cerr << "Expected reject EarlyData" << std::endl; 1061 return SECFailure; 1062 } 1063 } 1064 if (cfg_.get<bool>("on-resume-expect-accept-early-data")) { 1065 if (!info.earlyDataAccepted) { 1066 std::cerr << "Expected accept EarlyData" << std::endl; 1067 return SECFailure; 1068 } 1069 } 1070 1071 /* On successfully resumed connection. */ 1072 if (info.earlyDataAccepted) { 1073 str = cfg_.get<std::string>("on-resume-expect-alpn"); 1074 if (!str.empty()) { 1075 if (CheckALPN(str) != SECSuccess) { 1076 std::cerr << "Unexpected ALPN on Resume" << std::endl; 1077 return SECFailure; 1078 } 1079 } else { /* No real resume but new handshake on EarlyData rejection. */ 1080 /* On Retry... */ 1081 str = cfg_.get<std::string>("on-retry-expect-alpn"); 1082 if (!str.empty()) { 1083 if (CheckALPN(str) != SECSuccess) { 1084 std::cerr << "Unexpected ALPN on HRR" << std::endl; 1085 return SECFailure; 1086 } 1087 } 1088 } 1089 } 1090 1091 } else { /* Explicitly not on resume */ 1092 if (cfg_.get<bool>("on-initial-expect-ech-accept")) { 1093 if (!info.echAccepted) { 1094 std::cerr << "Expected ECH accept on initial connection" << std::endl; 1095 return SECFailure; 1096 } 1097 } 1098 1099 str = cfg_.get<std::string>("on-initial-expect-alpn"); 1100 if (!str.empty()) { 1101 if (CheckALPN(str) != SECSuccess) { 1102 std::cerr << "Unexpected ALPN on Initial" << std::endl; 1103 return SECFailure; 1104 } 1105 } 1106 } 1107 1108 return SECSuccess; 1109 } 1110 1111 private: 1112 const Config& cfg_; 1113 ScopedPRFileDesc pr_fd_; 1114 ScopedPRFileDesc ssl_fd_; 1115 ScopedCERTCertificate cert_; 1116 ScopedSECKEYPrivateKey key_; 1117 }; 1118 1119 std::unique_ptr<const Config> ReadConfig(int argc, char** argv) { 1120 std::unique_ptr<Config> cfg(new Config()); 1121 1122 cfg->AddEntry<int>("port", 0); 1123 cfg->AddEntry<bool>("ipv6", false); 1124 cfg->AddEntry<int>("shim-id", 0); 1125 cfg->AddEntry<bool>("server", false); 1126 cfg->AddEntry<int>("resume-count", 0); 1127 cfg->AddEntry<std::string>("key-file", ""); 1128 cfg->AddEntry<std::string>("cert-file", ""); 1129 cfg->AddEntry<int>("min-version", 0); 1130 cfg->AddEntry<int>("max-version", 0xffff); 1131 for (auto flag : kVersionDisableFlags) { 1132 cfg->AddEntry<bool>(flag, false); 1133 } 1134 cfg->AddEntry<bool>("fallback-scsv", false); 1135 cfg->AddEntry<bool>("false-start", false); 1136 cfg->AddEntry<bool>("enable-ocsp-stapling", false); 1137 cfg->AddEntry<bool>("write-then-read", false); 1138 cfg->AddEntry<bool>("require-any-client-certificate", false); 1139 cfg->AddEntry<bool>("verify-peer", false); 1140 cfg->AddEntry<bool>("is-handshaker-supported", false); 1141 cfg->AddEntry<std::string>("handshaker-path", ""); // Ignore this 1142 cfg->AddEntry<std::string>("advertise-alpn", ""); 1143 cfg->AddEntry<std::string>("on-initial-advertise-alpn", ""); 1144 cfg->AddEntry<std::string>("on-resume-advertise-alpn", ""); 1145 cfg->AddEntry<std::string>("expect-alpn", ""); 1146 cfg->AddEntry<std::string>("on-initial-expect-alpn", ""); 1147 cfg->AddEntry<std::string>("on-resume-expect-alpn", ""); 1148 cfg->AddEntry<std::string>("on-retry-expect-alpn", ""); 1149 cfg->AddEntry<std::vector<int>>("signing-prefs", std::vector<int>()); 1150 cfg->AddEntry<std::vector<int>>("verify-prefs", std::vector<int>()); 1151 cfg->AddEntry<int>("expect-peer-signature-algorithm", 0); 1152 cfg->AddEntry<std::string>("nss-cipher", ""); 1153 cfg->AddEntry<std::string>("host-name", ""); 1154 cfg->AddEntry<std::string>("ech-config-list", ""); 1155 cfg->AddEntry<std::string>("on-resume-ech-config-list", ""); 1156 cfg->AddEntry<bool>("expect-ech-accept", false); 1157 cfg->AddEntry<bool>("expect-hrr", false); 1158 cfg->AddEntry<bool>("enable-ech-grease", false); 1159 cfg->AddEntry<bool>("enable-early-data", false); 1160 cfg->AddEntry<bool>("enable-grease", false); 1161 cfg->AddEntry<bool>("permute-extensions", false); 1162 cfg->AddEntry<bool>("on-resume-expect-reject-early-data", false); 1163 cfg->AddEntry<bool>("on-resume-expect-accept-early-data", false); 1164 cfg->AddEntry<bool>("expect-ticket-supports-early-data", false); 1165 cfg->AddEntry<bool>("on-resume-shim-writes-first", 1166 false); // Always means 0Rtt write 1167 cfg->AddEntry<bool>("shim-writes-first", 1168 false); // Unimplemented since not required so far 1169 cfg->AddEntry<bool>("expect-session-miss", false); 1170 cfg->AddEntry<std::string>("expect-ech-retry-configs", ""); 1171 cfg->AddEntry<bool>("expect-no-ech-retry-configs", false); 1172 cfg->AddEntry<bool>("on-initial-expect-ech-accept", false); 1173 cfg->AddEntry<bool>("on-resume-expect-ech-accept", false); 1174 cfg->AddEntry<bool>("expect-no-offer-early-data", false); 1175 /* NSS does not support earlydata rejection reason logging => Ignore. */ 1176 cfg->AddEntry<std::string>("on-resume-expect-early-data-reason", "none"); 1177 cfg->AddEntry<std::string>("on-retry-expect-early-data-reason", "none"); 1178 cfg->AddEntry<std::vector<int>>("curves", std::vector<int>()); 1179 cfg->AddEntry<int>("expect-curve-id", 0); 1180 cfg->AddEntry<bool>("install-cert-compression-algs", false); 1181 1182 auto rv = cfg->ParseArgs(argc, argv); 1183 switch (rv) { 1184 case Config::kOK: 1185 break; 1186 case Config::kUnknownFlag: 1187 exitCodeUnimplemented = true; 1188 default: 1189 return nullptr; 1190 } 1191 1192 // Needed to change to std::unique_ptr<const Config> 1193 return std::move(cfg); 1194 } 1195 1196 bool RunCycle(std::unique_ptr<const Config>& cfg, bool resuming = false) { 1197 std::unique_ptr<TestAgent> agent(TestAgent::Create(*cfg)); 1198 return agent && agent->DoExchange(resuming) == SECSuccess; 1199 } 1200 1201 int GetExitCode(bool success) { 1202 if (exitCodeUnimplemented) { 1203 return 89; 1204 } 1205 1206 if (success) { 1207 return 0; 1208 } 1209 1210 return 1; 1211 } 1212 1213 int main(int argc, char** argv) { 1214 std::unique_ptr<const Config> cfg = ReadConfig(argc, argv); 1215 if (!cfg) { 1216 return GetExitCode(false); 1217 } 1218 1219 if (cfg->get<bool>("is-handshaker-supported")) { 1220 std::cout << "No\n"; 1221 return 0; 1222 } 1223 1224 if (cfg->get<bool>("server")) { 1225 if (SSL_ConfigServerSessionIDCache(1024, 0, 0, ".") != SECSuccess) { 1226 std::cerr << "Couldn't configure session cache\n"; 1227 return 1; 1228 } 1229 } 1230 1231 if (NSS_NoDB_Init(nullptr) != SECSuccess) { 1232 return 1; 1233 } 1234 1235 // Run a single test cycle. 1236 bool success = RunCycle(cfg); 1237 1238 int resume_count = cfg->get<int>("resume-count"); 1239 while (success && resume_count-- > 0) { 1240 std::cout << "Resuming" << std::endl; 1241 success = RunCycle(cfg, true); 1242 } 1243 1244 SSL_ClearSessionCache(); 1245 1246 if (cfg->get<bool>("server")) { 1247 SSL_ShutdownServerSessionIDCache(); 1248 } 1249 1250 if (NSS_Shutdown() != SECSuccess) { 1251 success = false; 1252 } 1253 1254 return GetExitCode(success); 1255 }