void SSLContextManager::SslContexts::addSSLContextConfig()

in wangle/ssl/SSLContextManager.cpp [536:651]


void SSLContextManager::SslContexts::addSSLContextConfig(
    const SSLContextConfig& ctxConfig,
    const SSLCacheOptions& cacheOptions,
    const TLSTicketKeySeeds* ticketSeeds,
    const folly::SocketAddress& vipAddress,
    const std::shared_ptr<SSLCacheProvider>& externalCache,
    const SSLContextManager* mgr,
    std::shared_ptr<ServerSSLContext>& newDefault) {
  auto sslCtx = std::make_shared<ServerSSLContext>(ctxConfig.sslVersion);

  std::string commonName;
  bool loaded;
  if (ctxConfig.offloadDisabled) {
    loaded = mgr->loadCertKeyPairsInSSLContext(sslCtx, ctxConfig, commonName);
  } else {
    loaded = mgr->loadCertKeyPairsInSSLContextExternal(
        sslCtx, ctxConfig, commonName);
  }

  if (!loaded) {
    // No compatible contexts were loaded.
    VLOG(3) << "Context with CN=" << commonName
            << " loaded no certs, skipping...";
    return;
  }

  mgr->overrideConfiguration(sslCtx, ctxConfig);

  // Let the server pick the highest performing cipher from among the client's
  // choices.
  //
  // Let's use a unique private key for all DH key exchanges.
  //
  // Because some old implementations choke on empty fragments, most SSL
  // applications disable them (it's part of SSL_OP_ALL).  This
  // will improve performance and decrease write buffer fragmentation.
  sslCtx->setOptions(
      SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_DH_USE |
      SSL_OP_SINGLE_ECDH_USE | SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);

  // Important that we do this *after* checking the TLS1.1 ciphers above,
  // since we test their validity by actually setting them.
  sslCtx->ciphers(ctxConfig.sslCiphers);
#if FOLLY_OPENSSL_PREREQ(1, 1, 1)
  sslCtx->setCiphersuitesOrThrow(ctxConfig.sslCiphersuites);
#endif

  if (ctxConfig.sigAlgs) {
    sslCtx->setSigAlgsOrThrow(*ctxConfig.sigAlgs);
  }

  // Use a fix DH param
  DH* dh = get_dh2048();
  SSL_CTX_set_tmp_dh(sslCtx->getSSLCtx(), dh);
  DH_free(dh);

  const string& curve = ctxConfig.eccCurveName;
  if (!curve.empty()) {
    set_key_from_curve(sslCtx->getSSLCtx(), curve);
  }

  if ((ctxConfig.clientCAFile.empty() && ctxConfig.clientCAFiles.empty()) &&
      ctxConfig.clientVerification !=
          SSLContext::VerifyClientCertificate::DO_NOT_REQUEST) {
    LOG(FATAL) << "You can't verify certs without the client ca file";
  }

  sslCtx->setVerificationOption(ctxConfig.clientVerification);
  if (mgr->clientCertVerifyCallback_ != nullptr) {
    mgr->clientCertVerifyCallback_->attachSSLContext(sslCtx);
    // See header for ClientCertVerifyCallback to understand why this is done
    sslCtx->setVerificationOption(
        SSLContext::VerifyClientCertificate::DO_NOT_REQUEST);
  }

  // Loads in certs from CA file(s), then sets SSL context with them.
  std::vector<std::string> clientCAFiles{};
  if (ctxConfig.clientCAFiles.size() > 0) {
    clientCAFiles = ctxConfig.clientCAFiles;
  } else if (!ctxConfig.clientCAFile.empty()) {
    clientCAFiles.push_back(ctxConfig.clientCAFile);
  }
  loadCAFiles(sslCtx, clientCAFiles);
  setSupportedClientCANames(sslCtx, clientCAFiles);

  sslCtx->setAlpnAllowMismatch(ctxConfig.alpnAllowMismatch);

  // we always want to setup the session id context
  // to make session resumption work (tickets or session cache)
  std::string sessionIdContext = commonName;
  if (ctxConfig.sessionContext && !ctxConfig.sessionContext->empty()) {
    sessionIdContext = *ctxConfig.sessionContext;
  }
  VLOG(3) << "For vip " << mgr->vipName_ << ", setting sid_ctx "
          << sessionIdContext;
  sslCtx->setSessionCacheContext(sessionIdContext);

  sslCtx->setupSessionCache(
      ctxConfig, cacheOptions, externalCache, sessionIdContext, mgr->stats_);
  configureTicketResumption(sslCtx, ticketSeeds, ctxConfig, mgr->stats_);

  VLOG(3) << "On VipID=" << vipAddress.describe() << " context=" << sslCtx;

  // finalize sslCtx setup by the individual features supported by openssl
  ctxSetupByOpensslFeature(
      sslCtx, ctxConfig, mgr->clientHelloTLSExtStats_, newDefault);

  try {
    insert(sslCtx, ctxConfig.isDefault);
  } catch (const std::exception& ex) {
    string msg = folly::to<string>(
        "Error adding certificate : ", folly::exceptionStr(ex));
    LOG(ERROR) << msg;
    throw std::runtime_error(msg);
  }
}