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