proxygen
fizz::tool Namespace Reference

Classes

struct  FizzCommandArgHandlerInfo
 
class  InputHandlerCallback
 
class  TerminalInputHandler
 

Typedefs

typedef std::function< void(const std::string &)> FizzCommandArgHandler
 
typedef std::map< std::string, FizzCommandArgHandlerInfoFizzArgHandlerMap
 

Functions

int fizzClientCommand (const std::vector< std::string > &args)
 
int fizzServerCommand (const std::vector< std::string > &args)
 
int parseArguments (std::vector< std::string > argv, FizzArgHandlerMap handlers, std::function< void()> usageFunc)
 
uint16_t portFromString (const std::string &portStr, bool serverSide)
 

Variables

const std::map< std::string, std::function< int(const std::vector< std::string > &)> > fizzUtilities
 

Typedef Documentation

typedef std::function<void(const std::string&)> fizz::tool::FizzCommandArgHandler

Definition at line 48 of file FizzCommandCommon.h.

Function Documentation

int fizz::tool::fizzClientCommand ( const std::vector< std::string > &  args)

Definition at line 230 of file FizzClientCommand.cpp.

References addr, fizz::Client, folly::Range< Iter >::empty(), folly::EventBase::loop(), fizz::CertUtils::makeSelfCert(), folly::gen::move, parseArguments(), portFromString(), folly::readFile(), sni, string, fizz::tls_1_3, fizz::tls_1_3_28, uint16_t, and verify().

230  {
231  std::string host = "localhost";
232  uint16_t port = 4433;
233  bool verify = false;
234  std::string certPath;
235  std::string keyPath;
236  std::string keyPass;
237  std::string caPath;
238  std::string caFile;
239  bool reconnect = false;
240  std::string customSNI;
241  std::vector<std::string> alpns;
242  bool early = false;
243 
244  // clang-format off
245  FizzArgHandlerMap handlers = {
246  {"-host", {true, [&host](const std::string& arg) { host = arg; }}},
247  {"-port", {true, [&port](const std::string& arg) {
248  port = portFromString(arg, false);
249  }}},
250  {"-connect", {true, [&host, &port](const std::string& arg) {
251  size_t colonIdx = arg.find(':');
252  if (colonIdx == std::string::npos) {
253  throw std::runtime_error("-connect requires a host:port pair.");
254  }
255  host = arg.substr(0, colonIdx);
256  port = portFromString(arg.substr(colonIdx+1), false);
257  }}},
258  {"-verify", {false, [&verify](const std::string&) { verify = true; }}},
259  {"-cert", {true, [&certPath](const std::string& arg) { certPath = arg; }}},
260  {"-key", {true, [&keyPath](const std::string& arg) { keyPath = arg; }}},
261  {"-pass", {true, [&keyPass](const std::string& arg) { keyPass = arg; }}},
262  {"-capath", {true, [&caPath](const std::string& arg) { caPath = arg; }}},
263  {"-cafile", {true, [&caFile](const std::string& arg) { caFile = arg; }}},
264  {"-reconnect", {false, [&reconnect](const std::string&) {
265  reconnect = true;
266  }}},
267  {"-servername", {true, [&customSNI](const std::string& arg) {
268  customSNI = arg;
269  }}},
270  {"-alpn", {true, [&alpns](const std::string& arg) {
271  alpns.clear();
272  auto remainder = arg;
273  for (auto commaPos = remainder.find(',');
274  commaPos != std::string::npos;
275  commaPos = remainder.find(',')) {
276  alpns.push_back(remainder.substr(0, commaPos));
277  remainder = remainder.substr(commaPos+1);
278  }
279 
280  alpns.push_back(remainder);
281  }}},
282  {"-early", {false, [&early](const std::string&) { early = true; }}},
283  {"-quiet", {false, [](const std::string&) {
284  FLAGS_minloglevel = google::GLOG_ERROR;
285  }}}
286  };
287  // clang-format on
288 
289  try {
290  if (parseArguments(args, handlers, printUsage)) {
291  // Parsing failed, return
292  return 1;
293  }
294  } catch (const std::exception& e) {
295  LOG(ERROR) << "Error: " << e.what();
296  return 1;
297  }
298 
299  // Sanity check input.
300  if (certPath.empty() != keyPath.empty()) {
301  LOG(ERROR) << "-cert and -key are both required when specified";
302  return 1;
303  }
304 
305  EventBase evb;
306  std::shared_ptr<const CertificateVerifier> verifier;
307  auto clientContext = std::make_shared<FizzClientContext>();
308 
309  if (!alpns.empty()) {
310  clientContext->setSupportedAlpns(std::move(alpns));
311  }
312 
313  clientContext->setSupportedVersions(
314  {ProtocolVersion::tls_1_3, ProtocolVersion::tls_1_3_28});
315  clientContext->setSendEarlyData(early);
316 
317  if (verify) {
318  // Initialize CA store first, if given.
320  if (!caPath.empty() || !caFile.empty()) {
321  storePtr.reset(X509_STORE_new());
322  auto caFilePtr = caFile.empty() ? nullptr : caFile.c_str();
323  auto caPathPtr = caPath.empty() ? nullptr : caPath.c_str();
324 
325  if (X509_STORE_load_locations(storePtr.get(), caFilePtr, caPathPtr) ==
326  0) {
327  LOG(ERROR) << "Failed to load CA certificates";
328  return 1;
329  }
330  }
331 
332  verifier = std::make_shared<const DefaultCertificateVerifier>(
333  VerificationContext::Client, std::move(storePtr));
334  }
335 
336  if (!certPath.empty()) {
337  std::string certData;
338  std::string keyData;
339  if (!readFile(certPath.c_str(), certData)) {
340  LOG(ERROR) << "Failed to read certificate";
341  return 1;
342  } else if (!readFile(keyPath.c_str(), keyData)) {
343  LOG(ERROR) << "Failed to read private key";
344  return 1;
345  }
346 
347  std::unique_ptr<SelfCert> cert;
348  if (!keyPass.empty()) {
349  cert = CertUtils::makeSelfCert(certData, keyData, keyPass);
350  } else {
351  cert = CertUtils::makeSelfCert(certData, keyData);
352  }
353  clientContext->setClientCertificate(std::move(cert));
354  }
355 
356  try {
357  SocketAddress addr(host, port, true);
358  auto sni = customSNI.empty() ? host : customSNI;
359  Connection conn(&evb, clientContext, sni, verifier, reconnect);
360  Connection resumptionConn(&evb, clientContext, sni, verifier, false);
361  Connection* inputTarget = &conn;
362  if (reconnect) {
363  auto pskCache = std::make_shared<ResumptionPskCache>(
364  &evb, [&conn, &resumptionConn, addr]() {
365  conn.close();
366  resumptionConn.connect(addr);
367  });
368  clientContext->setPskCache(pskCache);
369  inputTarget = &resumptionConn;
370  }
371  TerminalInputHandler input(&evb, inputTarget);
372  conn.connect(addr);
373  evb.loop();
374  } catch (const std::exception& e) {
375  LOG(ERROR) << "Error: " << e.what();
376  return 1;
377  }
378 
379  return 0;
380 }
bool readFile(int fd, Container &out, size_t num_bytes=std::numeric_limits< size_t >::max())
Definition: FileUtil.h:125
void verify(int extras)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
int parseArguments(std::vector< std::string > argv, FizzArgHandlerMap handlers, std::function< void()> usageFunc)
constexpr bool empty() const
Definition: Range.h:443
uint16_t portFromString(const std::string &portStr, bool serverSide)
std::unique_ptr< X509_STORE, X509StoreDeleter > X509StoreUniquePtr
StringPiece sni
const char * string
Definition: Conv.cpp:212
std::map< std::string, FizzCommandArgHandlerInfo > FizzArgHandlerMap
ThreadPoolListHook * addr
int fizz::tool::fizzServerCommand ( const std::vector< std::string > &  args)

Definition at line 277 of file FizzServerCommand.cpp.

References cipher, fizz::test::createCert(), loop(), folly::EventBase::loop(), fizz::CertUtils::makeSelfCert(), folly::gen::move, fizz::server::None, fizz::server::Optional, parseArguments(), portFromString(), folly::gen::range(), folly::readFile(), fizz::server::Required, fizz::Server, string, fizz::tls_1_3, fizz::tls_1_3_28, and uint16_t.

277  {
278  uint16_t port = 8443;
280  std::string certPath;
281  std::string keyPath;
282  std::string keyPass;
283  ClientAuthMode clientAuthMode = ClientAuthMode::None;
284  std::string caPaths;
285  std::string caFile;
286  bool early = false;
287  std::vector<std::string> alpns;
288  bool loop = false;
289  bool fallback = false;
290 
291  // clang-format off
292  FizzArgHandlerMap handlers = {
293  {"-accept", {true, [&port](const std::string& arg) {
294  port = portFromString(arg, true);
295  }}},
296  {"-ciphers", {true, [&ciphers](const std::string& arg) {
297  std::vector<CipherSuite> newCiphers;
298  auto remainder = arg;
299  try {
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);
306  }
307 
308  newCiphers.push_back(parse<CipherSuite>(remainder));
309  ciphers = std::move(newCiphers);
310  }
311  catch (const std::exception& e) {
312  LOG(ERROR) << "Error parsing cipher suites: " << e.what();
313  }
314  }}},
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&) {
319  clientAuthMode = ClientAuthMode::Optional;
320  }}},
321  {"-requirecert", {false, [&clientAuthMode](const std::string&) {
322  clientAuthMode = ClientAuthMode::Required;
323  }}},
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) {
328  alpns.clear();
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);
335  }
336 
337  alpns.push_back(remainder);
338  }}},
339  {"-loop", {false, [&loop](const std::string&) { loop = true; }}},
340  {"-quiet", {false, [](const std::string&) {
341  FLAGS_minloglevel = google::GLOG_ERROR;
342  }}},
343  {"-fallback", {false, [&fallback](const std::string&) {
344  fallback = true;
345  }}}
346  };
347  // clang-format on
348 
349  try {
350  if (parseArguments(args, handlers, printUsage)) {
351  // Parsing failed, return
352  return 1;
353  }
354  } catch (const std::exception& e) {
355  LOG(ERROR) << "Error: " << e.what();
356  return 1;
357  }
358 
359  // Sanity check input.
360  if (certPath.empty() != keyPath.empty()) {
361  LOG(ERROR) << "-cert and -key are both required when specified";
362  return 1;
363  }
364 
365  EventBase evb;
366  std::shared_ptr<const CertificateVerifier> verifier;
367 
368  if (clientAuthMode != ClientAuthMode::None) {
369  // Initialize CA store first, if given.
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();
375 
376  if (X509_STORE_load_locations(storePtr.get(), caFilePtr, caPathPtr) ==
377  0) {
378  LOG(ERROR) << "Failed to load CA certificates";
379  return 1;
380  }
381  }
382 
383  verifier = std::make_shared<const DefaultCertificateVerifier>(
384  VerificationContext::Server, std::move(storePtr));
385  }
386 
387  auto serverContext = std::make_shared<FizzServerContext>();
388  if (ciphers) {
389  serverContext->setSupportedCiphers({*ciphers});
390  }
391  serverContext->setClientAuthMode(clientAuthMode);
392  serverContext->setClientCertVerifier(verifier);
393 
394  auto ticketCipher = std::make_shared<AeadTicketCipher<
395  OpenSSLEVPCipher<AESGCM128>,
397  HkdfImpl<Sha256>>>();
398  auto ticketSeed = RandomGenerator<32>().generateRandom();
399  ticketCipher->setTicketSecrets({{range(ticketSeed)}});
400  serverContext->setTicketCipher(ticketCipher);
401 
402  auto certManager = std::make_unique<CertManager>();
403  if (!certPath.empty()) {
404  std::string certData;
405  std::string keyData;
406  if (!readFile(certPath.c_str(), certData)) {
407  LOG(ERROR) << "Failed to read certificate";
408  return 1;
409  } else if (!readFile(keyPath.c_str(), keyData)) {
410  LOG(ERROR) << "Failed to read private key";
411  return 1;
412  }
413  std::unique_ptr<SelfCert> cert;
414  if (!keyPass.empty()) {
415  cert = CertUtils::makeSelfCert(certData, keyData, keyPass);
416  } else {
417  cert = CertUtils::makeSelfCert(certData, keyData);
418  }
419  certManager->addCert(std::move(cert), true);
420  } else {
421  auto certData = fizz::test::createCert("fizz-self-signed", false, nullptr);
422  std::vector<folly::ssl::X509UniquePtr> certChain;
423  certChain.push_back(std::move(certData.cert));
424  auto cert = std::make_unique<SelfCertImpl<KeyType::P256>>(
425  std::move(certData.key), std::move(certChain));
426  certManager->addCert(std::move(cert), true);
427  }
428  serverContext->setCertManager(std::move(certManager));
429 
430  if (early) {
431  serverContext->setEarlyDataSettings(
432  true,
433  {std::chrono::seconds(-10), std::chrono::seconds(10)},
434  std::make_shared<SlidingBloomReplayCache>(240, 140000, 0.0005, &evb));
435  }
436 
437  std::shared_ptr<SSLContext> sslContext;
438  if (fallback) {
439  if (certPath.empty()) {
440  LOG(ERROR) << "Fallback mode requires explicit certificates";
441  return 1;
442  }
443  sslContext = std::make_shared<SSLContext>();
444  sslContext->loadCertKeyPairFromFiles(certPath.c_str(), keyPath.c_str());
445  SSL_CTX_set_ecdh_auto(sslContext->getSSLCtx(), 1);
446  }
447  serverContext->setVersionFallbackEnabled(fallback);
448 
449  if (!alpns.empty()) {
450  serverContext->setSupportedAlpns(std::move(alpns));
451  }
452 
453  serverContext->setSupportedVersions(
454  {ProtocolVersion::tls_1_3, ProtocolVersion::tls_1_3_28});
455  FizzServerAcceptor acceptor(port, serverContext, loop, &evb, sslContext);
456  evb.loop();
457  return 0;
458 }
bool readFile(int fd, Container &out, size_t num_bytes=std::numeric_limits< size_t >::max())
Definition: FileUtil.h:125
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
int parseArguments(std::vector< std::string > argv, FizzArgHandlerMap handlers, std::function< void()> usageFunc)
CipherSuite cipher
Gen range(Value begin, Value end)
Definition: Base.h:467
uint16_t portFromString(const std::string &portStr, bool serverSide)
std::unique_ptr< X509_STORE, X509StoreDeleter > X509StoreUniquePtr
void loop(int iters)
CertAndKey createCert(std::string cn, bool ca, CertAndKey *issuer)
Definition: Utilities.h:35
const char * string
Definition: Conv.cpp:212
std::map< std::string, FizzCommandArgHandlerInfo > FizzArgHandlerMap
int fizz::tool::parseArguments ( std::vector< std::string argv,
FizzArgHandlerMap  handlers,
std::function< void()>  usageFunc 
)

Definition at line 17 of file FizzCommandCommon.cpp.

References string.

Referenced by fizzClientCommand(), and fizzServerCommand().

20  {
21  for (size_t idx = 2; idx < argv.size(); idx++) {
22  auto& argument = argv[idx];
23  auto handlerIter = handlers.find(argument);
24 
25  if (handlerIter != handlers.end()) {
26  auto& handlerInfo = handlerIter->second;
27  std::string variable;
28  if (handlerInfo.hasVariable) {
29  if (idx + 1 >= argv.size()) {
30  std::cerr << "Argument " << argument << " requires an parameter."
31  << std::endl;
32  usageFunc();
33  return 1;
34  } else {
35  idx++;
36  variable = argv[idx];
37  }
38  }
39  handlerInfo.handler(variable);
40  } else {
41  std::cerr << "Unknown argument: " << argument << std::endl;
42  usageFunc();
43  return 1;
44  }
45  }
46  return 0;
47 }
const char * string
Definition: Conv.cpp:212
uint16_t fizz::tool::portFromString ( const std::string portStr,
bool  serverSide 
)
inline

Definition at line 27 of file FizzCommandCommon.h.

References max, and uint16_t.

Referenced by fizzClientCommand(), and fizzServerCommand().

27  {
28  unsigned long converted = 0;
29  try {
30  converted = std::stoul(portStr);
31  } catch (const std::exception&) {
32  throw std::runtime_error(
33  "Couldn't convert " + portStr + " to port number.");
34  }
35  if (converted <= std::numeric_limits<uint16_t>::max()) {
36  if (converted == 0 && !serverSide) {
37  throw std::runtime_error("Port 0 is not valid for client ports.");
38  }
39  return static_cast<uint16_t>(converted);
40  } else {
41  throw std::runtime_error(
42  "Couldn't convert " + portStr + " to port number.");
43  }
44 }
LogLevel max
Definition: LogLevel.cpp:31

Variable Documentation

const std::map<std::string, std::function<int(const std::vector<std::string>&)> > fizz::tool::fizzUtilities
Initial value:
= {{"client", &fizzClientCommand},
{"s_client", &fizzClientCommand},
{"server", &fizzServerCommand},
{"s_server", &fizzServerCommand}}
int fizzServerCommand(const std::vector< std::string > &args)
int fizzClientCommand(const std::vector< std::string > &args)

Definition at line 23 of file Commands.h.

Referenced by main(), and showUsage().