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);
}
}