TLSServer.cpp (21544B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "TLSServer.h" 6 7 #include <stdio.h> 8 #include <string> 9 #include <thread> 10 #include <vector> 11 #include <fstream> 12 #include <iostream> 13 #ifdef XP_WIN 14 # include <windows.h> 15 #else 16 # include <unistd.h> 17 #endif 18 19 #include <utility> 20 21 #include "base64.h" 22 #include "certdb.h" 23 #include "mozilla/Sprintf.h" 24 #include "nspr.h" 25 #include "nss.h" 26 #include "plarenas.h" 27 #include "prenv.h" 28 #include "prerror.h" 29 #include "prnetdb.h" 30 #include "prtime.h" 31 #include "ssl.h" 32 #include "sslexp.h" 33 #include "sslproto.h" 34 35 namespace mozilla { 36 namespace test { 37 38 static const uint16_t LISTEN_PORT = 8443; 39 40 SSLAntiReplayContext* antiReplay = nullptr; 41 42 DebugLevel gDebugLevel = DEBUG_ERRORS; 43 uint16_t gCallbackPort = 0; 44 45 static const char kPEMBegin[] = "-----BEGIN "; 46 static const char kPEMEnd[] = "-----END "; 47 const char DEFAULT_CERT_NICKNAME[] = "default-ee"; 48 49 struct Connection { 50 PRFileDesc* mSocket; 51 char mByte; 52 53 explicit Connection(PRFileDesc* aSocket); 54 ~Connection(); 55 }; 56 57 Connection::Connection(PRFileDesc* aSocket) : mSocket(aSocket), mByte(0) {} 58 59 Connection::~Connection() { 60 if (mSocket) { 61 PR_Close(mSocket); 62 } 63 } 64 65 void PrintPRError(const char* aPrefix) { 66 const char* err = PR_ErrorToName(PR_GetError()); 67 if (err) { 68 if (gDebugLevel >= DEBUG_ERRORS) { 69 fprintf(stderr, "%s: %s\n", aPrefix, err); 70 } 71 } else { 72 if (gDebugLevel >= DEBUG_ERRORS) { 73 fprintf(stderr, "%s\n", aPrefix); 74 } 75 } 76 } 77 78 // This decodes a PEM file into `item`. The line endings need to be 79 // UNIX-style, or there will be cross-platform issues. 80 static bool DecodePEMFile(const std::string& filename, SECItem* item) { 81 std::ifstream in(filename); 82 if (in.bad()) { 83 return false; 84 } 85 86 char buf[1024]; 87 in.getline(buf, sizeof(buf)); 88 if (in.bad()) { 89 return false; 90 } 91 92 if (strncmp(buf, kPEMBegin, std::string::traits_type::length(kPEMBegin)) != 93 0) { 94 return false; 95 } 96 97 std::string value; 98 for (;;) { 99 in.getline(buf, sizeof(buf)); 100 if (in.bad()) { 101 return false; 102 } 103 104 if (strncmp(buf, kPEMEnd, std::string::traits_type::length(kPEMEnd)) == 0) { 105 break; 106 } 107 108 value += buf; 109 } 110 111 unsigned int binLength; 112 UniquePORTString bin(BitwiseCast<char*, unsigned char*>( 113 ATOB_AsciiToData(value.c_str(), &binLength))); 114 if (!bin || binLength == 0) { 115 PrintPRError("ATOB_AsciiToData failed"); 116 return false; 117 } 118 119 if (SECITEM_AllocItem(nullptr, item, binLength) == nullptr) { 120 return false; 121 } 122 123 PORT_Memcpy(item->data, bin.get(), binLength); 124 return true; 125 } 126 127 static SECStatus AddKeyFromFile(const std::string& path, 128 const std::string& filename) { 129 ScopedAutoSECItem item; 130 131 std::string file = path + "/" + filename; 132 if (!DecodePEMFile(file, &item)) { 133 return SECFailure; 134 } 135 136 UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); 137 if (!slot) { 138 PrintPRError("PK11_GetInternalKeySlot failed"); 139 return SECFailure; 140 } 141 142 if (PK11_NeedUserInit(slot.get())) { 143 if (PK11_InitPin(slot.get(), nullptr, nullptr) != SECSuccess) { 144 PrintPRError("PK11_InitPin failed"); 145 return SECFailure; 146 } 147 } 148 149 SECKEYPrivateKey* privateKey = nullptr; 150 SECItem nick = {siBuffer, 151 BitwiseCast<unsigned char*, const char*>(filename.data()), 152 static_cast<unsigned int>(filename.size())}; 153 if (PK11_ImportDERPrivateKeyInfoAndReturnKey( 154 slot.get(), &item, &nick, nullptr, true, false, KU_ALL, &privateKey, 155 nullptr) != SECSuccess) { 156 PrintPRError("PK11_ImportDERPrivateKeyInfoAndReturnKey failed"); 157 return SECFailure; 158 } 159 160 SECKEY_DestroyPrivateKey(privateKey); 161 return SECSuccess; 162 } 163 164 static SECStatus AddCertificateFromFile(const std::string& path, 165 const std::string& filename) { 166 ScopedAutoSECItem item; 167 168 std::string file = path + "/" + filename; 169 if (!DecodePEMFile(file, &item)) { 170 return SECFailure; 171 } 172 173 UniqueCERTCertificate cert(CERT_NewTempCertificate( 174 CERT_GetDefaultCertDB(), &item, nullptr, false, true)); 175 if (!cert) { 176 PrintPRError("CERT_NewTempCertificate failed"); 177 return SECFailure; 178 } 179 180 UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); 181 if (!slot) { 182 PrintPRError("PK11_GetInternalKeySlot failed"); 183 return SECFailure; 184 } 185 // The nickname is the filename without '.pem'. 186 std::string nickname = filename.substr(0, filename.length() - 4); 187 SECStatus rv = PK11_ImportCert(slot.get(), cert.get(), CK_INVALID_HANDLE, 188 nickname.c_str(), false); 189 if (rv != SECSuccess) { 190 PrintPRError("PK11_ImportCert failed"); 191 return rv; 192 } 193 194 // By convention, the file `test-ca.pem` is a trust anchor. 195 if (!filename.compare("test-ca.pem")) { 196 if (PK11_NeedUserInit(slot.get())) { 197 rv = PK11_InitPin(slot.get(), nullptr, nullptr); 198 if (rv != SECSuccess) { 199 PrintPRError("PK11_InitPin failed"); 200 return rv; 201 } 202 } 203 rv = PK11_CheckUserPassword(slot.get(), ""); 204 if (rv != SECSuccess) { 205 PrintPRError("PK11_CheckUserPassword failed"); 206 return rv; 207 } 208 CERTCertTrust trust{ 209 CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA, 210 0, 0}; 211 rv = CERT_ChangeCertTrust(nullptr, cert.get(), &trust); 212 if (rv != SECSuccess) { 213 PrintPRError("CERT_ChangeCertTrust failed"); 214 return rv; 215 } 216 } 217 218 return SECSuccess; 219 } 220 221 SECStatus LoadCertificatesAndKeys(const char* basePath) { 222 // The NSS cert DB path could have been specified as "sql:path". Trim off 223 // the leading "sql:" if so. 224 if (strncmp(basePath, "sql:", 4) == 0) { 225 basePath = basePath + 4; 226 } 227 228 UniquePRDir fdDir(PR_OpenDir(basePath)); 229 if (!fdDir) { 230 PrintPRError("PR_OpenDir failed"); 231 return SECFailure; 232 } 233 // On the B2G ICS emulator, operations taken in AddCertificateFromFile 234 // appear to interact poorly with readdir (more specifically, something is 235 // causing readdir to never return null - it indefinitely loops through every 236 // file in the directory, which causes timeouts). Rather than waste more time 237 // chasing this down, loading certificates and keys happens in two phases: 238 // filename collection and then loading. (This is probably a good 239 // idea anyway because readdir isn't reentrant. Something could change later 240 // such that it gets called as a result of calling AddCertificateFromFile or 241 // AddKeyFromFile.) 242 std::vector<std::string> certificates; 243 std::vector<std::string> keys; 244 for (PRDirEntry* dirEntry = PR_ReadDir(fdDir.get(), PR_SKIP_BOTH); dirEntry; 245 dirEntry = PR_ReadDir(fdDir.get(), PR_SKIP_BOTH)) { 246 size_t nameLength = strlen(dirEntry->name); 247 if (nameLength > 4) { 248 if (strncmp(dirEntry->name + nameLength - 4, ".pem", 4) == 0) { 249 certificates.push_back(dirEntry->name); 250 } else if (strncmp(dirEntry->name + nameLength - 4, ".key", 4) == 0) { 251 keys.push_back(dirEntry->name); 252 } 253 } 254 } 255 SECStatus rv; 256 for (std::string& certificate : certificates) { 257 rv = AddCertificateFromFile(basePath, certificate.c_str()); 258 if (rv != SECSuccess) { 259 return rv; 260 } 261 } 262 for (std::string& key : keys) { 263 rv = AddKeyFromFile(basePath, key.c_str()); 264 if (rv != SECSuccess) { 265 return rv; 266 } 267 } 268 return SECSuccess; 269 } 270 271 SECStatus InitializeNSS(const char* nssCertDBDir) { 272 // Try initializing an existing DB. 273 if (NSS_Init(nssCertDBDir) == SECSuccess) { 274 return SECSuccess; 275 } 276 277 // Create a new DB if there is none... 278 SECStatus rv = NSS_Initialize(nssCertDBDir, nullptr, nullptr, nullptr, 0); 279 if (rv != SECSuccess) { 280 return rv; 281 } 282 283 // ...and load all certificates into it. 284 return LoadCertificatesAndKeys(nssCertDBDir); 285 } 286 287 nsresult SendAll(PRFileDesc* aSocket, const char* aData, size_t aDataLen) { 288 if (gDebugLevel >= DEBUG_VERBOSE) { 289 fprintf(stderr, "sending '%s'\n", aData); 290 } 291 292 while (aDataLen > 0) { 293 int32_t bytesSent = 294 PR_Send(aSocket, aData, aDataLen, 0, PR_INTERVAL_NO_TIMEOUT); 295 if (bytesSent == -1) { 296 PrintPRError("PR_Send failed"); 297 return NS_ERROR_FAILURE; 298 } 299 300 aDataLen -= bytesSent; 301 aData += bytesSent; 302 } 303 304 return NS_OK; 305 } 306 307 nsresult ReplyToRequest(Connection* aConn) { 308 // For debugging purposes, SendAll can print out what it's sending. 309 // So, any strings we give to it to send need to be null-terminated. 310 char buf[2] = {aConn->mByte, 0}; 311 return SendAll(aConn->mSocket, buf, 1); 312 } 313 314 nsresult SetupTLS(Connection* aConn, PRFileDesc* aModelSocket) { 315 PRFileDesc* sslSocket = SSL_ImportFD(aModelSocket, aConn->mSocket); 316 if (!sslSocket) { 317 PrintPRError("SSL_ImportFD failed"); 318 return NS_ERROR_FAILURE; 319 } 320 aConn->mSocket = sslSocket; 321 322 /* anti-replay must be configured to accept 0RTT */ 323 if (antiReplay) { 324 SECStatus rv = SSL_SetAntiReplayContext(sslSocket, antiReplay); 325 if (rv != SECSuccess) { 326 PrintPRError("error configuring anti-replay "); 327 return NS_ERROR_FAILURE; 328 } 329 } 330 331 SSL_OptionSet(sslSocket, SSL_SECURITY, true); 332 SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_CLIENT, false); 333 SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_SERVER, true); 334 // Unconditionally enabling 0RTT makes test_session_resumption.js fail 335 SSL_OptionSet(sslSocket, SSL_ENABLE_0RTT_DATA, 336 !!PR_GetEnv("MOZ_TLS_SERVER_0RTT")); 337 338 SSL_ResetHandshake(sslSocket, /* asServer */ 1); 339 340 return NS_OK; 341 } 342 343 nsresult ReadRequest(Connection* aConn) { 344 int32_t bytesRead = 345 PR_Recv(aConn->mSocket, &aConn->mByte, 1, 0, PR_INTERVAL_NO_TIMEOUT); 346 if (bytesRead < 0) { 347 PrintPRError("PR_Recv failed"); 348 return NS_ERROR_FAILURE; 349 } else if (bytesRead == 0) { 350 PR_SetError(PR_IO_ERROR, 0); 351 PrintPRError("PR_Recv EOF in ReadRequest"); 352 return NS_ERROR_FAILURE; 353 } else { 354 if (gDebugLevel >= DEBUG_VERBOSE) { 355 fprintf(stderr, "read '0x%hhx'\n", aConn->mByte); 356 } 357 } 358 return NS_OK; 359 } 360 361 void HandleConnection(PRFileDesc* aSocket, 362 const UniquePRFileDesc& aModelSocket) { 363 Connection conn(aSocket); 364 nsresult rv = SetupTLS(&conn, aModelSocket.get()); 365 if (NS_FAILED(rv)) { 366 PR_SetError(PR_INVALID_STATE_ERROR, 0); 367 PrintPRError("PR_Recv failed"); 368 exit(1); 369 } 370 371 // TODO: On tests that are expected to fail (e.g. due to a revoked 372 // certificate), the client will close the connection wtihout sending us the 373 // request byte. In those cases, we should keep going. But, in the cases 374 // where the connection is supposed to suceed, we should verify that we 375 // successfully receive the request and send the response. 376 rv = ReadRequest(&conn); 377 if (NS_SUCCEEDED(rv)) { 378 rv = ReplyToRequest(&conn); 379 } 380 } 381 382 // returns 0 on success, non-zero on error 383 int DoCallback() { 384 UniquePRFileDesc socket(PR_NewTCPSocket()); 385 if (!socket) { 386 PrintPRError("PR_NewTCPSocket failed"); 387 return 1; 388 } 389 390 PRNetAddr addr; 391 PR_InitializeNetAddr(PR_IpAddrLoopback, gCallbackPort, &addr); 392 if (PR_Connect(socket.get(), &addr, PR_INTERVAL_NO_TIMEOUT) != PR_SUCCESS) { 393 PrintPRError("PR_Connect failed"); 394 return 1; 395 } 396 397 const char* request = "GET / HTTP/1.0\r\n\r\n"; 398 SendAll(socket.get(), request, strlen(request)); 399 char buf[4096]; 400 memset(buf, 0, sizeof(buf)); 401 int32_t bytesRead = 402 PR_Recv(socket.get(), buf, sizeof(buf) - 1, 0, PR_INTERVAL_NO_TIMEOUT); 403 if (bytesRead < 0) { 404 PrintPRError("PR_Recv failed 1"); 405 return 1; 406 } 407 if (bytesRead == 0) { 408 fprintf(stderr, "PR_Recv eof 1\n"); 409 return 1; 410 } 411 fprintf(stderr, "%s\n", buf); 412 return 0; 413 } 414 415 SECStatus ConfigSecureServerWithNamedCert( 416 PRFileDesc* fd, const char* certName, 417 /*optional*/ UniqueCERTCertificate* certOut, 418 /*optional*/ SSLKEAType* keaOut, 419 /*optional*/ SSLExtraServerCertData* extraData) { 420 UniqueCERTCertificate cert(PK11_FindCertFromNickname(certName, nullptr)); 421 if (!cert) { 422 PrintPRError("PK11_FindCertFromNickname failed"); 423 return SECFailure; 424 } 425 // If an intermediate certificate issued the server certificate (rather than 426 // directly by a trust anchor), we want to send it along in the handshake so 427 // we don't encounter unknown issuer errors when that's not what we're 428 // testing. 429 UniqueCERTCertificateList certList; 430 UniqueCERTCertificate issuerCert( 431 CERT_FindCertByName(CERT_GetDefaultCertDB(), &cert->derIssuer)); 432 // If we can't find the issuer cert, continue without it. 433 if (issuerCert) { 434 // Sadly, CERTCertificateList does not have a CERT_NewCertificateList 435 // utility function, so we must create it ourselves. This consists 436 // of creating an arena, allocating space for the CERTCertificateList, 437 // and then transferring ownership of the arena to that list. 438 UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); 439 if (!arena) { 440 PrintPRError("PORT_NewArena failed"); 441 return SECFailure; 442 } 443 certList.reset(static_cast<CERTCertificateList*>( 444 PORT_ArenaAlloc(arena.get(), sizeof(CERTCertificateList)))); 445 if (!certList) { 446 PrintPRError("PORT_ArenaAlloc failed"); 447 return SECFailure; 448 } 449 certList->arena = arena.release(); 450 // We also have to manually copy the certificates we care about to the 451 // list, because there aren't any utility functions for that either. 452 certList->certs = static_cast<SECItem*>( 453 PORT_ArenaAlloc(certList->arena, 2 * sizeof(SECItem))); 454 if (SECITEM_CopyItem(certList->arena, certList->certs, &cert->derCert) != 455 SECSuccess) { 456 PrintPRError("SECITEM_CopyItem failed"); 457 return SECFailure; 458 } 459 if (SECITEM_CopyItem(certList->arena, certList->certs + 1, 460 &issuerCert->derCert) != SECSuccess) { 461 PrintPRError("SECITEM_CopyItem failed"); 462 return SECFailure; 463 } 464 certList->len = 2; 465 } 466 467 UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); 468 if (!slot) { 469 PrintPRError("PK11_GetInternalKeySlot failed"); 470 return SECFailure; 471 } 472 UniqueSECKEYPrivateKey key( 473 PK11_FindKeyByDERCert(slot.get(), cert.get(), nullptr)); 474 if (!key) { 475 PrintPRError("PK11_FindKeyByDERCert failed"); 476 return SECFailure; 477 } 478 479 if (extraData) { 480 SSLExtraServerCertData dataCopy = {ssl_auth_null, nullptr, nullptr, 481 nullptr, nullptr, nullptr}; 482 memcpy(&dataCopy, extraData, sizeof(dataCopy)); 483 dataCopy.certChain = certList.get(); 484 485 if (SSL_ConfigServerCert(fd, cert.get(), key.get(), &dataCopy, 486 sizeof(dataCopy)) != SECSuccess) { 487 PrintPRError("SSL_ConfigServerCert failed"); 488 return SECFailure; 489 } 490 491 } else { 492 // This is the deprecated setup mechanism, to be cleaned up in Bug 1569222 493 SSLKEAType certKEA = NSS_FindCertKEAType(cert.get()); 494 if (SSL_ConfigSecureServerWithCertChain(fd, cert.get(), certList.get(), 495 key.get(), certKEA) != SECSuccess) { 496 PrintPRError("SSL_ConfigSecureServer failed"); 497 return SECFailure; 498 } 499 500 if (keaOut) { 501 *keaOut = certKEA; 502 } 503 } 504 505 if (certOut) { 506 *certOut = std::move(cert); 507 } 508 509 SSL_OptionSet(fd, SSL_NO_CACHE, false); 510 SSL_OptionSet(fd, SSL_ENABLE_SESSION_TICKETS, true); 511 // Unconditionally enabling 0RTT makes test_session_resumption.js fail 512 SSL_OptionSet(fd, SSL_ENABLE_0RTT_DATA, !!PR_GetEnv("MOZ_TLS_SERVER_0RTT")); 513 514 return SECSuccess; 515 } 516 517 #ifdef XP_WIN 518 using PidType = DWORD; 519 constexpr bool IsValidPid(long long pid) { 520 // Excluding `(DWORD)-1` because it is not a valid process ID. 521 // See https://devblogs.microsoft.com/oldnewthing/20040223-00/?p=40503 522 return pid > 0 && pid < std::numeric_limits<PidType>::max(); 523 } 524 #else 525 using PidType = pid_t; 526 constexpr bool IsValidPid(long long pid) { 527 return pid > 0 && pid <= std::numeric_limits<PidType>::max(); 528 } 529 #endif 530 531 PidType ConvertPid(const char* pidStr) { 532 long long pid = strtoll(pidStr, nullptr, 10); 533 if (!IsValidPid(pid)) { 534 return 0; 535 } 536 return static_cast<PidType>(pid); 537 } 538 539 int StartServer(int argc, char* argv[], SSLSNISocketConfig sniSocketConfig, 540 void* sniSocketConfigArg, ServerConfigFunc configFunc) { 541 if (argc != 3) { 542 fprintf(stderr, "usage: %s <NSS DB directory> <ppid>\n", argv[0]); 543 return 1; 544 } 545 const char* nssCertDBDir = argv[1]; 546 PidType ppid = ConvertPid(argv[2]); 547 548 const char* debugLevel = PR_GetEnv("MOZ_TLS_SERVER_DEBUG_LEVEL"); 549 if (debugLevel) { 550 int level = atoi(debugLevel); 551 switch (level) { 552 case DEBUG_ERRORS: 553 gDebugLevel = DEBUG_ERRORS; 554 break; 555 case DEBUG_WARNINGS: 556 gDebugLevel = DEBUG_WARNINGS; 557 break; 558 case DEBUG_VERBOSE: 559 gDebugLevel = DEBUG_VERBOSE; 560 break; 561 default: 562 PrintPRError("invalid MOZ_TLS_SERVER_DEBUG_LEVEL"); 563 return 1; 564 } 565 } 566 567 const char* callbackPort = PR_GetEnv("MOZ_TLS_SERVER_CALLBACK_PORT"); 568 if (callbackPort) { 569 gCallbackPort = atoi(callbackPort); 570 } 571 572 if (InitializeNSS(nssCertDBDir) != SECSuccess) { 573 PR_fprintf(PR_STDERR, "InitializeNSS failed"); 574 return 1; 575 } 576 577 if (NSS_SetDomesticPolicy() != SECSuccess) { 578 PrintPRError("NSS_SetDomesticPolicy failed"); 579 return 1; 580 } 581 582 /* Disabling NSS_KEY_SIZE_POLICY as we operate with short keys. */ 583 NSS_OptionSet(NSS_KEY_SIZE_POLICY_FLAGS, 0); 584 585 if (SSL_ConfigServerSessionIDCache(0, 0, 0, nullptr) != SECSuccess) { 586 PrintPRError("SSL_ConfigServerSessionIDCache failed"); 587 return 1; 588 } 589 590 UniquePRFileDesc serverSocket(PR_NewTCPSocket()); 591 if (!serverSocket) { 592 PrintPRError("PR_NewTCPSocket failed"); 593 return 1; 594 } 595 596 PRSocketOptionData socketOption; 597 socketOption.option = PR_SockOpt_Reuseaddr; 598 socketOption.value.reuse_addr = true; 599 PR_SetSocketOption(serverSocket.get(), &socketOption); 600 601 PRNetAddr serverAddr; 602 PR_InitializeNetAddr(PR_IpAddrLoopback, LISTEN_PORT, &serverAddr); 603 if (PR_Bind(serverSocket.get(), &serverAddr) != PR_SUCCESS) { 604 PrintPRError("PR_Bind failed"); 605 return 1; 606 } 607 608 if (PR_Listen(serverSocket.get(), 1) != PR_SUCCESS) { 609 PrintPRError("PR_Listen failed"); 610 return 1; 611 } 612 613 UniquePRFileDesc rawModelSocket(PR_NewTCPSocket()); 614 if (!rawModelSocket) { 615 PrintPRError("PR_NewTCPSocket failed for rawModelSocket"); 616 return 1; 617 } 618 619 UniquePRFileDesc modelSocket(SSL_ImportFD(nullptr, rawModelSocket.release())); 620 if (!modelSocket) { 621 PrintPRError("SSL_ImportFD of rawModelSocket failed"); 622 return 1; 623 } 624 625 SSLVersionRange range = {0, 0}; 626 if (SSL_VersionRangeGet(modelSocket.get(), &range) != SECSuccess) { 627 PrintPRError("SSL_VersionRangeGet failed"); 628 return 1; 629 } 630 631 if (range.max < SSL_LIBRARY_VERSION_TLS_1_3) { 632 range.max = SSL_LIBRARY_VERSION_TLS_1_3; 633 if (SSL_VersionRangeSet(modelSocket.get(), &range) != SECSuccess) { 634 PrintPRError("SSL_VersionRangeSet failed"); 635 return 1; 636 } 637 } 638 639 if (PR_GetEnv("MOZ_TLS_SERVER_0RTT")) { 640 if (SSL_CreateAntiReplayContext(PR_Now(), 1L * PR_USEC_PER_SEC, 7, 14, 641 &antiReplay) != SECSuccess) { 642 PrintPRError("Unable to create anti-replay context for 0-RTT."); 643 return 1; 644 } 645 } 646 647 if (SSL_SNISocketConfigHook(modelSocket.get(), sniSocketConfig, 648 sniSocketConfigArg) != SECSuccess) { 649 PrintPRError("SSL_SNISocketConfigHook failed"); 650 return 1; 651 } 652 653 // We have to configure the server with a certificate, but it's not one 654 // we're actually going to end up using. In the SNI callback, we pick 655 // the right certificate for the connection. 656 // 657 // Provide an empty |extra_data| to force config via SSL_ConfigServerCert. 658 // This is a temporary mechanism to work around inconsistent setting of 659 // |authType| in the deprecated API (preventing the default cert from 660 // being removed in favor of the SNI-selected cert). This may be removed 661 // after Bug 1569222 removes the deprecated mechanism. 662 SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr, 663 nullptr, nullptr, nullptr}; 664 if (ConfigSecureServerWithNamedCert(modelSocket.get(), DEFAULT_CERT_NICKNAME, 665 nullptr, nullptr, 666 &extra_data) != SECSuccess) { 667 return 1; 668 } 669 670 // Call back to implementation-defined configuration func, if provided. 671 if (configFunc) { 672 if (((configFunc)(modelSocket.get())) != SECSuccess) { 673 PrintPRError("configFunc failed"); 674 return 1; 675 } 676 } 677 678 if (gCallbackPort != 0) { 679 if (DoCallback()) { 680 return 1; 681 } 682 } 683 684 std::thread([ppid] { 685 if (!ppid) { 686 if (gDebugLevel >= DEBUG_ERRORS) { 687 fprintf(stderr, "invalid ppid\n"); 688 } 689 return; 690 } 691 #ifdef XP_WIN 692 HANDLE parent = OpenProcess(SYNCHRONIZE, false, ppid); 693 if (!parent) { 694 if (gDebugLevel >= DEBUG_ERRORS) { 695 fprintf(stderr, "OpenProcess failed\n"); 696 } 697 return; 698 } 699 WaitForSingleObject(parent, INFINITE); 700 CloseHandle(parent); 701 #else 702 while (getppid() == ppid) { 703 sleep(1); 704 } 705 #endif 706 if (gDebugLevel >= DEBUG_ERRORS) { 707 fprintf(stderr, "Parent process crashed\n"); 708 } 709 exit(1); 710 }).detach(); 711 712 while (true) { 713 PRNetAddr clientAddr; 714 PRFileDesc* clientSocket = 715 PR_Accept(serverSocket.get(), &clientAddr, PR_INTERVAL_NO_TIMEOUT); 716 HandleConnection(clientSocket, modelSocket); 717 } 718 } 719 720 } // namespace test 721 } // namespace mozilla