26 using namespace folly;
35 <<
"Usage: s_server args\n" 37 <<
"Supported arguments:\n" 38 <<
" -accept port (set port to accept connections on. Default: 8443)\n" 39 <<
" -ciphers c1,... (comma-separated custom list of ciphers to use in order of preference)\n" 40 <<
" -cert cert (PEM format server certificate. Default: none, generates a self-signed cert)\n" 41 <<
" -key key (PEM format private key for server certificate. Default: none)\n" 42 <<
" -pass password (private key password. Default: none)\n" 43 <<
" -requestcert (request an optional client certificate from clients. Default: false)\n" 44 <<
" -requirecert (require a client certificate from clients. Default: false)\n" 45 <<
" -capaths d1:... (colon-separated paths to directories of CA certs used for verification)\n" 46 <<
" -cafile file (path to bundle of CA certs used for verification)\n" 47 <<
" -early (enables sending early data during resumption. Default: false)\n" 48 <<
" -alpn alpn1,... (comma-separated list of ALPNs to support. Default: none)\n" 49 <<
" -fallback (enables falling back to OpenSSL for pre-1.3 connections. Default: false)\n" 50 <<
" -loop (don't exit after client disconnect. Default: false)\n" 51 <<
" -quiet (hide informational logging. Default: false)\n";
57 explicit FizzServerAcceptor(
59 std::shared_ptr<FizzServerContext> serverCtx,
62 std::shared_ptr<SSLContext> sslCtx);
63 void connectionAccepted(
67 void acceptError(
const std::exception& ex) noexcept
override;
73 std::shared_ptr<FizzServerContext>
ctx_;
76 std::unique_ptr<AsyncFizzServer::HandshakeCallback>
cb_;
83 public InputHandlerCallback {
85 explicit FizzExampleServer(
86 std::shared_ptr<AsyncFizzServer> transport,
87 FizzServerAcceptor* acceptor,
88 std::shared_ptr<SSLContext> sslCtx)
93 printHandshakeSuccess();
96 void fizzHandshakeError(
99 LOG(ERROR) <<
"Handshake error: " << ex.
what();
103 void fizzHandshakeAttemptFallback(
104 std::unique_ptr<IOBuf> clientHello)
override {
106 LOG(
INFO) <<
"Fallback attempt";
108 auto evb =
socket->getEventBase();
109 auto fd =
socket->detachFd();
118 LOG(
INFO) <<
"Fallback SSL Handshake success";
121 printFallbackSuccess();
127 LOG(ERROR) <<
"Fallback SSL Handshake error: " << ex.what();
131 void getReadBuffer(
void** bufReturn,
size_t* lenReturn)
override {
136 void readDataAvailable(
size_t len)
noexcept override {
140 bool isBufferMovable()
noexcept override {
144 void readBufferAvailable(std::unique_ptr<IOBuf> buf)
noexcept override {
154 LOG(ERROR) <<
"Read error: " << ex.what();
158 bool connected()
const override {
162 void write(std::unique_ptr<IOBuf> msg)
override {
170 void close()
override {
175 void printHandshakeSuccess() {
179 LOG(
INFO) <<
"Handshake succeeded.";
182 LOG(
INFO) <<
" Named Group: " 184 LOG(
INFO) <<
" Signature Scheme: " 187 LOG(
INFO) <<
" PSK Mode: " 191 LOG(
INFO) <<
" Server identity: " 193 LOG(
INFO) <<
" Client Identity: " 195 LOG(
INFO) <<
" ALPN: " <<
state.alpn().value_or(
"(none)");
198 void printFallbackSuccess() {
202 LOG(
INFO) <<
"Handshake succeeded.";
203 LOG(
INFO) <<
" TLS Version: " << SSL_get_version(ssl);
204 LOG(
INFO) <<
" Cipher: " <<
sslSocket_->getNegotiatedCipherName();
205 LOG(
INFO) <<
" Signature Algorithm: " 207 LOG(
INFO) <<
" Server identity: " 209 LOG(
INFO) <<
" Client Identity: " 224 std::shared_ptr<SSLContext>
sslCtx_;
229 FizzServerAcceptor::FizzServerAcceptor(
231 std::shared_ptr<FizzServerContext> serverCtx,
234 std::shared_ptr<SSLContext> sslCtx)
241 LOG(
INFO) <<
"Started listening on " <<
socket_->getAddress();
244 void FizzServerAcceptor::connectionAccepted(
247 LOG(
INFO) <<
"Connection accepted from " << clientAddr;
252 auto serverCb = std::make_unique<FizzExampleServer>(transport,
this,
sslCtx_);
255 transport->accept(cb_.get());
258 void FizzServerAcceptor::acceptError(
const std::exception& ex)
noexcept {
259 LOG(ERROR) <<
"Failed to accept connection: " << ex.what();
265 void FizzServerAcceptor::done() {
287 std::vector<std::string> alpns;
289 bool fallback =
false;
293 {
"-accept", {
true, [&port](
const std::string& arg) {
296 {
"-ciphers", {
true, [&ciphers](
const std::string& arg) {
297 std::vector<CipherSuite> newCiphers;
298 auto remainder = arg;
300 for (
auto commaPos = remainder.find(
',');
301 commaPos != std::string::npos;
302 commaPos = remainder.find(
',')) {
303 auto cipher = parse<CipherSuite>(remainder.substr(0, commaPos));
304 remainder = remainder.substr(commaPos+1);
305 newCiphers.push_back(
cipher);
308 newCiphers.push_back(parse<CipherSuite>(remainder));
311 catch (
const std::exception& e) {
312 LOG(ERROR) <<
"Error parsing cipher suites: " << e.what();
315 {
"-cert", {
true, [&certPath](
const std::string& arg) { certPath = arg; }}},
316 {
"-key", {
true, [&keyPath](
const std::string& arg) { keyPath = arg; }}},
317 {
"-pass", {
true, [&keyPass](
const std::string& arg) { keyPass = arg; }}},
318 {
"-requestcert", {
false, [&clientAuthMode](
const std::string&) {
321 {
"-requirecert", {
false, [&clientAuthMode](
const std::string&) {
324 {
"-capaths", {
true, [&caPaths](
const std::string& arg) { caPaths = arg; }}},
325 {
"-cafile", {
true, [&caFile](
const std::string& arg) { caFile = arg; }}},
326 {
"-early", {
false, [&early](
const std::string&) { early =
true; }}},
327 {
"-alpn", {
true, [&alpns](
const std::string& arg) {
329 auto remainder = arg;
330 for (
auto commaPos = remainder.find(
',');
331 commaPos != std::string::npos;
332 commaPos = remainder.find(
',')) {
333 alpns.push_back(remainder.substr(0, commaPos));
334 remainder = remainder.substr(commaPos+1);
337 alpns.push_back(remainder);
341 FLAGS_minloglevel = google::GLOG_ERROR;
343 {
"-fallback", {
false, [&fallback](
const std::string&) {
354 }
catch (
const std::exception& e) {
355 LOG(ERROR) <<
"Error: " << e.what();
360 if (certPath.empty() != keyPath.empty()) {
361 LOG(ERROR) <<
"-cert and -key are both required when specified";
366 std::shared_ptr<const CertificateVerifier> verifier;
371 if (!caPaths.empty() || !caFile.empty()) {
372 storePtr.reset(X509_STORE_new());
373 auto caFilePtr = caFile.empty() ?
nullptr : caFile.c_str();
374 auto caPathPtr = caPaths.empty() ?
nullptr : caPaths.c_str();
376 if (X509_STORE_load_locations(storePtr.get(), caFilePtr, caPathPtr) ==
378 LOG(ERROR) <<
"Failed to load CA certificates";
383 verifier = std::make_shared<const DefaultCertificateVerifier>(
387 auto serverContext = std::make_shared<FizzServerContext>();
389 serverContext->setSupportedCiphers({*ciphers});
391 serverContext->setClientAuthMode(clientAuthMode);
392 serverContext->setClientCertVerifier(verifier);
399 ticketCipher->setTicketSecrets({{
range(ticketSeed)}});
400 serverContext->setTicketCipher(ticketCipher);
402 auto certManager = std::make_unique<CertManager>();
403 if (!certPath.empty()) {
406 if (!
readFile(certPath.c_str(), certData)) {
407 LOG(ERROR) <<
"Failed to read certificate";
409 }
else if (!
readFile(keyPath.c_str(), keyData)) {
410 LOG(ERROR) <<
"Failed to read private key";
413 std::unique_ptr<SelfCert> cert;
414 if (!keyPass.empty()) {
419 certManager->addCert(
std::move(cert),
true);
422 std::vector<folly::ssl::X509UniquePtr> certChain;
423 certChain.push_back(
std::move(certData.cert));
424 auto cert = std::make_unique<SelfCertImpl<KeyType::P256>>(
426 certManager->addCert(
std::move(cert),
true);
428 serverContext->setCertManager(
std::move(certManager));
431 serverContext->setEarlyDataSettings(
433 {std::chrono::seconds(-10), std::chrono::seconds(10)},
434 std::make_shared<SlidingBloomReplayCache>(240, 140000, 0.0005, &evb));
437 std::shared_ptr<SSLContext> sslContext;
439 if (certPath.empty()) {
440 LOG(ERROR) <<
"Fallback mode requires explicit certificates";
443 sslContext = std::make_shared<SSLContext>();
444 sslContext->loadCertKeyPairFromFiles(certPath.c_str(), keyPath.c_str());
445 SSL_CTX_set_ecdh_auto(sslContext->getSSLCtx(), 1);
447 serverContext->setVersionFallbackEnabled(fallback);
449 if (!alpns.empty()) {
450 serverContext->setSupportedAlpns(
std::move(alpns));
453 serverContext->setSupportedVersions(
455 FizzServerAcceptor acceptor(port, serverContext, loop, &evb, sslContext);
std::unique_ptr< TerminalInputHandler > inputHandler_
folly::fbstring what() const
folly::StringPiece toString(StateEnum state)
bool readFile(int fd, Container &out, size_t num_bytes=std::numeric_limits< size_t >::max())
void write(const T &in, folly::io::Appender &appender)
static std::unique_ptr< SelfCert > makeSelfCert(std::string certData, std::string keyData, const std::vector< std::shared_ptr< CertificateCompressor >> &compressors={})
std::array< char, 8192 > readBuf_
std::shared_ptr< AsyncFizzServer > transport_
constexpr detail::Map< Move > move
—— Concurrent Priority Queue Implementation ——
requires E e noexcept(noexcept(s.error(std::move(e))))
std::shared_ptr< FizzServerContext > ctx_
void setReadCB(ReadCallback *callback) override
Gen range(Value begin, Value end)
void setReadCB(ReadCallback *callback) override
std::unique_ptr< AsyncSSLSocket, Destructor > UniquePtr
FizzServerAcceptor * acceptor_
std::unique_ptr< AsyncFizzServer::HandshakeCallback > cb_
AsyncSSLSocket::UniquePtr sslSocket_
AsyncServerSocket::UniquePtr socket_
std::unique_ptr< X509_STORE, X509StoreDeleter > X509StoreUniquePtr
NetworkSocket socket(int af, int type, int protocol)
std::shared_ptr< const Cert > serverCert
std::unique_ptr< AsyncServerSocket, Destructor > UniquePtr
std::unique_ptr< AsyncFizzServerT, folly::DelayedDestruction::Destructor > UniquePtr
CertAndKey createCert(std::string cn, bool ca, CertAndKey *issuer)
std::shared_ptr< const Cert > clientCert
AsyncFizzServerT< ServerStateMachine > AsyncFizzServer
Range< const char * > StringPiece
int close(NetworkSocket s)
std::unique_ptr< AsyncSocket, Destructor > UniquePtr
std::shared_ptr< SSLContext > sslCtx_