1 /* 2 * Copyright (c) 2018-present, Facebook, Inc. 3 * All rights reserved. 4 * 5 * This source code is licensed under the BSD-style license found in the 6 * LICENSE file in the root directory of this source tree. 7 */ 8 #pragma once 9 10 #include <fizz/crypto/aead/AESGCM128.h> 11 #include <fizz/crypto/aead/OpenSSLEVPCipher.h> 12 #include <fizz/protocol/DefaultCertificateVerifier.h> 13 #include <fizz/protocol/test/Utilities.h> 14 #include <fizz/server/AsyncFizzServer.h> 15 #include <fizz/server/TicketTypes.h> 16 #include <folly/io/async/AsyncServerSocket.h> 17 18 namespace fizz { 19 namespace server { 20 namespace test { 21 22 class FizzTestServer : public folly::AsyncServerSocket::AcceptCallback { 23 public: 24 class CallbackFactory { 25 public: 26 virtual ~CallbackFactory() = default; 27 virtual AsyncFizzServer::HandshakeCallback* getCallback( 28 std::shared_ptr<AsyncFizzServer> server) = 0; 29 }; 30 31 FizzTestServer( 32 folly::EventBase& evb, 33 CallbackFactory* factory, 34 int port = 0, 35 std::string ip = "") factory_(factory)36 : factory_(factory), evb_(evb) { 37 auto certData = 38 fizz::test::createCert("fizz-test-selfsign", false, nullptr); 39 std::vector<folly::ssl::X509UniquePtr> certChain; 40 certChain.push_back(std::move(certData.cert)); 41 auto fizzCert = std::make_unique<SelfCertImpl<KeyType::P256>>( 42 std::move(certData.key), std::move(certChain)); 43 auto certManager = std::make_unique<CertManager>(); 44 certManager->addCert(std::move(fizzCert), true); 45 ctx_ = std::make_shared<FizzServerContext>(); 46 ctx_->setCertManager(std::move(certManager)); 47 48 socket_ = folly::AsyncServerSocket::UniquePtr( 49 new folly::AsyncServerSocket(&evb_)); 50 if (ip.empty()) { 51 socket_->bind(port); 52 } else { 53 socket_->bind( 54 folly::SocketAddress(ip, port, false /* allowNameLookup */)); 55 } 56 socket_->listen(100); 57 socket_->addAcceptCallback(this, &evb_); 58 socket_->startAccepting(); 59 } 60 setFizzContext(std::shared_ptr<FizzServerContext> ctx)61 void setFizzContext(std::shared_ptr<FizzServerContext> ctx) { 62 ctx_ = ctx; 63 } 64 acceptError(folly::exception_wrapper ex)65 void acceptError(folly::exception_wrapper ex) noexcept override { 66 LOG(ERROR) << "Accept error: " << ex; 67 } 68 connectionAccepted(folly::NetworkSocket fdNetworkSocket,const folly::SocketAddress &,AcceptInfo)69 void connectionAccepted( 70 folly::NetworkSocket fdNetworkSocket, 71 const folly::SocketAddress& /* clientAddr */, 72 AcceptInfo /* info */) noexcept override { 73 auto sock = new folly::AsyncSocket(&evb_, fdNetworkSocket); 74 std::shared_ptr<AsyncFizzServer> transport = AsyncFizzServer::UniquePtr( 75 new AsyncFizzServer(folly::AsyncSocket::UniquePtr(sock), ctx_)); 76 auto callback = factory_->getCallback(transport); 77 if (startHandshakeOnAccept_) { 78 transport->accept(callback); 79 } 80 } 81 setStartHandshakeOnAccept(bool enable)82 void setStartHandshakeOnAccept(bool enable) { 83 startHandshakeOnAccept_ = enable; 84 } 85 setResumption(bool enable)86 void setResumption(bool enable) { 87 if (enable) { 88 auto ticketCipher = std::make_shared< 89 Aead128GCMTicketCipher<TicketCodec<CertificateStorage::X509>>>( 90 std::make_shared<OpenSSLFactory>(), std::make_shared<CertManager>()); 91 auto ticketSeed = RandomGenerator<32>().generateRandom(); 92 ticketCipher->setTicketSecrets({{folly::range(ticketSeed)}}); 93 ctx_->setTicketCipher(ticketCipher); 94 } else { 95 ctx_->setTicketCipher(nullptr); 96 } 97 } 98 setCertificate(std::unique_ptr<SelfCert> cert)99 void setCertificate(std::unique_ptr<SelfCert> cert) { 100 auto certManager = std::make_unique<CertManager>(); 101 certManager->addCert(std::move(cert), true); 102 ctx_->setCertManager(std::move(certManager)); 103 } 104 105 void enableClientAuthWithChain( 106 std::string path, 107 ClientAuthMode mode = ClientAuthMode::Optional) { 108 ctx_->setClientAuthMode(mode); 109 std::string certData; 110 CHECK(folly::readFile(path.c_str(), certData)); 111 auto certRange = folly::ByteRange(folly::StringPiece(certData)); 112 113 auto clientAuthCerts = 114 folly::ssl::OpenSSLCertUtils::readCertsFromBuffer(certRange); 115 ERR_clear_error(); 116 folly::ssl::X509StoreUniquePtr store(X509_STORE_new()); 117 for (auto& caCert : clientAuthCerts) { 118 if (X509_STORE_add_cert(store.get(), caCert.get()) != 1) { 119 auto err = ERR_get_error(); 120 CHECK( 121 ERR_GET_LIB(err) == ERR_LIB_X509 && 122 ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) 123 << "Could not insert CA certificate into store: " 124 << std::string(ERR_error_string(err, nullptr)); 125 } 126 } 127 128 auto verifier = std::make_shared<DefaultCertificateVerifier>( 129 VerificationContext::Server, std::move(store)); 130 ctx_->setClientCertVerifier(std::move(verifier)); 131 } 132 disableClientAuth()133 void disableClientAuth() { 134 ctx_->setClientAuthMode(ClientAuthMode::None); 135 ctx_->setClientCertVerifier(nullptr); 136 } 137 setAcceptEarlyData(bool enable)138 void setAcceptEarlyData(bool enable) { 139 if (enable) { 140 ctx_->setEarlyDataSettings( 141 true, 142 {std::chrono::seconds(-10), std::chrono::seconds(10)}, 143 std::make_shared<AllowAllReplayReplayCache>()); 144 } else { 145 ctx_->setEarlyDataSettings(false, ClockSkewTolerance(), nullptr); 146 } 147 } 148 stopAccepting()149 void stopAccepting() { 150 socket_.reset(); 151 } 152 getAddress()153 folly::SocketAddress getAddress() { 154 folly::SocketAddress addr; 155 socket_->getAddress(&addr); 156 return addr; 157 } 158 getFizzContext()159 std::shared_ptr<FizzServerContext> getFizzContext() { 160 return ctx_; 161 } 162 163 private: 164 folly::AsyncServerSocket::UniquePtr socket_; 165 std::shared_ptr<FizzServerContext> ctx_; 166 CallbackFactory* factory_; 167 folly::EventBase& evb_; 168 bool startHandshakeOnAccept_{true}; 169 }; 170 171 } // namespace test 172 } // namespace server 173 } // namespace fizz 174