39 ctx_ = SSL_CTX_new(SSLv23_method());
40 if (
ctx_ ==
nullptr) {
41 throw std::runtime_error(
"SSL_CTX_new: " + getErrors());
47 opt = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
50 opt = SSL_OP_NO_SSLv2;
53 opt = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 |
60 int newOpt = SSL_CTX_set_options(
ctx_, opt);
61 DCHECK((newOpt & opt) == opt);
63 SSL_CTX_set_mode(
ctx_, SSL_MODE_AUTO_RETRY);
65 checkPeerName_ =
false;
67 SSL_CTX_set_options(
ctx_, SSL_OP_NO_COMPRESSION);
69 sslAcceptRunner_ = std::make_unique<SSLAcceptRunner>();
71 #if FOLLY_OPENSSL_HAS_SNI 72 SSL_CTX_set_tlsext_servername_callback(
ctx_, baseServerNameOpenSSLCallback);
73 SSL_CTX_set_tlsext_servername_arg(
ctx_,
this);
78 if (
ctx_ !=
nullptr) {
83 #if FOLLY_OPENSSL_HAS_ALPN 84 deleteNextProtocolsStrings();
89 setCiphersOrThrow(ciphers);
93 const std::vector<std::string>& ecCurves) {
94 if (ecCurves.size() == 0) {
97 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL 99 join(
":", ecCurves, ecCurvesList);
100 int rc = SSL_CTX_set1_curves_list(
ctx_, ecCurvesList.c_str());
102 throw std::runtime_error(
"SSL_CTX_set1_curves_list " + getErrors());
108 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL && !defined(OPENSSL_NO_ECDH) 109 EC_KEY* ecdh =
nullptr;
119 nid = OBJ_sn2nid(curveName.c_str());
121 LOG(
FATAL) <<
"Unknown curve name:" << curveName.c_str();
123 ecdh = EC_KEY_new_by_curve_name(nid);
124 if (ecdh ==
nullptr) {
125 LOG(
FATAL) <<
"Unable to create curve:" << curveName.c_str();
128 SSL_CTX_set_tmp_ecdh(
ctx_, ecdh);
131 throw std::runtime_error(
"Elliptic curve encryption not allowed");
137 if (!x509VerifyParam) {
140 if (SSL_CTX_set1_param(
ctx_, x509VerifyParam.get()) != 1) {
141 throw std::runtime_error(
"SSL_CTX_set1_param " + getErrors());
146 int rc = SSL_CTX_set_cipher_list(
ctx_, ciphers.c_str());
148 throw std::runtime_error(
"SSL_CTX_set_cipher_list: " + getErrors());
150 providedCiphersString_ = ciphers;
155 CHECK(verifyPeer != SSLVerifyPeerEnum::USE_CTX);
156 verifyPeer_ = verifyPeer;
161 CHECK(verifyPeer != SSLVerifyPeerEnum::USE_CTX);
162 int mode = SSL_VERIFY_NONE;
163 switch (verifyPeer) {
167 case SSLVerifyPeerEnum::VERIFY:
168 mode = SSL_VERIFY_PEER;
171 case SSLVerifyPeerEnum::VERIFY_REQ_CLIENT_CERT:
172 mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
175 case SSLVerifyPeerEnum::NO_VERIFY:
176 mode = SSL_VERIFY_NONE;
186 return getVerificationMode(verifyPeer_);
195 mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
196 SSL_VERIFY_CLIENT_ONCE;
197 checkPeerName_ = checkPeerName;
198 peerFixedName_ = peerName;
200 mode = SSL_VERIFY_NONE;
201 checkPeerName_ =
false;
202 peerFixedName_.
clear();
204 SSL_CTX_set_verify(
ctx_, mode,
nullptr);
208 if (path ==
nullptr || format ==
nullptr) {
209 throw std::invalid_argument(
210 "loadCertificateChain: either <path> or <format> is nullptr");
212 if (strcmp(format,
"PEM") == 0) {
213 if (SSL_CTX_use_certificate_chain_file(
ctx_, path) != 1) {
214 int errnoCopy = errno;
215 std::string reason(
"SSL_CTX_use_certificate_chain_file: ");
218 reason.append(getErrors(errnoCopy));
219 throw std::runtime_error(reason);
222 throw std::runtime_error(
223 "Unsupported certificate format: " +
std::string(format));
228 if (cert.
data() ==
nullptr) {
229 throw std::invalid_argument(
"loadCertificate: <cert> is nullptr");
233 if (bio ==
nullptr) {
234 throw std::runtime_error(
"BIO_new: " + getErrors());
237 int written = BIO_write(bio.get(), cert.
data(), int(cert.
size()));
238 if (written <= 0 || static_cast<unsigned>(written) != cert.
size()) {
239 throw std::runtime_error(
"BIO_write: " + getErrors());
243 PEM_read_bio_X509(bio.get(),
nullptr,
nullptr,
nullptr));
244 if (x509 ==
nullptr) {
245 throw std::runtime_error(
"PEM_read_bio_X509: " + getErrors());
248 if (SSL_CTX_use_certificate(
ctx_, x509.get()) == 0) {
249 throw std::runtime_error(
"SSL_CTX_use_certificate: " + getErrors());
254 if (path ==
nullptr || format ==
nullptr) {
255 throw std::invalid_argument(
256 "loadPrivateKey: either <path> or <format> is nullptr");
258 if (strcmp(format,
"PEM") == 0) {
259 if (SSL_CTX_use_PrivateKey_file(
ctx_, path, SSL_FILETYPE_PEM) == 0) {
260 throw std::runtime_error(
"SSL_CTX_use_PrivateKey_file: " + getErrors());
263 throw std::runtime_error(
264 "Unsupported private key format: " +
std::string(format));
269 if (pkey.
data() ==
nullptr) {
270 throw std::invalid_argument(
"loadPrivateKey: <pkey> is nullptr");
274 if (bio ==
nullptr) {
275 throw std::runtime_error(
"BIO_new: " + getErrors());
278 int written = BIO_write(bio.get(), pkey.
data(), int(pkey.
size()));
279 if (written <= 0 || static_cast<unsigned>(written) != pkey.
size()) {
280 throw std::runtime_error(
"BIO_write: " + getErrors());
284 PEM_read_bio_PrivateKey(bio.get(),
nullptr,
nullptr,
nullptr));
285 if (key ==
nullptr) {
286 throw std::runtime_error(
"PEM_read_bio_PrivateKey: " + getErrors());
289 if (SSL_CTX_use_PrivateKey(
ctx_, key.get()) == 0) {
290 throw std::runtime_error(
"SSL_CTX_use_PrivateKey: " + getErrors());
297 loadCertificateFromBufferPEM(cert);
298 loadPrivateKeyFromBufferPEM(pkey);
299 if (!isCertKeyPairValid()) {
300 throw std::runtime_error(
"SSL certificate and private key do not match");
305 const char* certPath,
307 const char* certFormat,
308 const char* keyFormat) {
309 loadCertificate(certPath, certFormat);
310 loadPrivateKey(keyPath, keyFormat);
311 if (!isCertKeyPairValid()) {
312 throw std::runtime_error(
"SSL certificate and private key do not match");
317 return SSL_CTX_check_private_key(
ctx_) == 1;
321 if (path ==
nullptr) {
322 throw std::invalid_argument(
"loadTrustedCertificates: <path> is nullptr");
324 if (SSL_CTX_load_verify_locations(
ctx_, path,
nullptr) == 0) {
325 throw std::runtime_error(
"SSL_CTX_load_verify_locations: " + getErrors());
331 SSL_CTX_set_cert_store(
ctx_, store);
335 auto clientCAs = SSL_load_client_CA_file(path);
336 if (clientCAs ==
nullptr) {
337 LOG(ERROR) <<
"Unable to load ca file: " << path <<
" " << getErrors();
340 SSL_CTX_set_client_CA_list(
ctx_, clientCAs);
344 std::shared_ptr<PasswordCollector> collector) {
345 if (collector ==
nullptr) {
346 LOG(ERROR) <<
"passwordCollector: ignore invalid password collector";
349 collector_ = collector;
351 SSL_CTX_set_default_passwd_cb_userdata(
ctx_,
this);
354 #if FOLLY_OPENSSL_HAS_SNI 356 void SSLContext::setServerNameCallback(
const ServerNameCallback& cb) {
360 void SSLContext::addClientHelloCallback(
const ClientHelloCallback& cb) {
361 clientHelloCbs_.push_back(cb);
364 int SSLContext::baseServerNameOpenSSLCallback(SSL* ssl,
int* al,
void*
data) {
367 if (context ==
nullptr) {
368 return SSL_TLSEXT_ERR_NOACK;
371 for (
auto& cb : context->clientHelloCbs_) {
381 if (!context->serverNameCb_) {
382 return SSL_TLSEXT_ERR_NOACK;
385 ServerNameCallbackResult ret = context->serverNameCb_(ssl);
387 case SERVER_NAME_FOUND:
388 return SSL_TLSEXT_ERR_OK;
389 case SERVER_NAME_NOT_FOUND:
390 return SSL_TLSEXT_ERR_NOACK;
391 case SERVER_NAME_NOT_FOUND_ALERT_FATAL:
392 *al = TLS1_AD_UNRECOGNIZED_NAME;
393 return SSL_TLSEXT_ERR_ALERT_FATAL;
398 return SSL_TLSEXT_ERR_NOACK;
400 #endif // FOLLY_OPENSSL_HAS_SNI 402 #if FOLLY_OPENSSL_HAS_ALPN 403 int SSLContext::alpnSelectCallback(
405 const unsigned char** out,
406 unsigned char* outlen,
407 const unsigned char* in,
412 if (context->advertisedNextProtocols_.empty()) {
416 auto i = context->pickNextProtocols();
417 const auto& item = context->advertisedNextProtocols_[
i];
418 if (SSL_select_next_proto(
419 (
unsigned char**)out,
424 inlen) != OPENSSL_NPN_NEGOTIATED) {
425 return SSL_TLSEXT_ERR_NOACK;
428 return SSL_TLSEXT_ERR_OK;
431 bool SSLContext::setAdvertisedNextProtocols(
432 const std::list<std::string>& protocols) {
433 return setRandomizedAdvertisedNextProtocols({{1, protocols}});
436 bool SSLContext::setRandomizedAdvertisedNextProtocols(
437 const std::list<NextProtocolsItem>& items) {
438 unsetNextProtocols();
439 if (items.size() == 0) {
442 int total_weight = 0;
443 for (
const auto& item : items) {
444 if (item.protocols.size() == 0) {
447 AdvertisedNextProtocolsItem advertised_item;
448 advertised_item.length = 0;
449 for (
const auto& proto : item.protocols) {
450 ++advertised_item.length;
451 auto protoLength = proto.length();
452 if (protoLength >= 256) {
453 deleteNextProtocolsStrings();
456 advertised_item.length += unsigned(protoLength);
458 advertised_item.protocols =
new unsigned char[advertised_item.length];
459 if (!advertised_item.protocols) {
460 throw std::runtime_error(
"alloc failure");
462 unsigned char* dst = advertised_item.protocols;
463 for (
auto& proto : item.protocols) {
465 *dst++ = (
unsigned char)protoLength;
466 memcpy(dst, proto.data(), protoLength);
469 total_weight += item.weight;
470 advertisedNextProtocols_.push_back(advertised_item);
471 advertisedNextProtocolWeights_.push_back(item.weight);
473 if (total_weight == 0) {
474 deleteNextProtocolsStrings();
477 nextProtocolDistribution_ = std::discrete_distribution<>(
478 advertisedNextProtocolWeights_.begin(),
479 advertisedNextProtocolWeights_.end());
480 SSL_CTX_set_alpn_select_cb(
ctx_, alpnSelectCallback,
this);
484 if (SSL_CTX_set_alpn_protos(
486 advertisedNextProtocols_[0].protocols,
487 advertisedNextProtocols_[0].length) != 0) {
493 void SSLContext::deleteNextProtocolsStrings() {
494 for (
auto protocols : advertisedNextProtocols_) {
495 delete[] protocols.protocols;
497 advertisedNextProtocols_.clear();
498 advertisedNextProtocolWeights_.clear();
501 void SSLContext::unsetNextProtocols() {
502 deleteNextProtocolsStrings();
503 SSL_CTX_set_alpn_select_cb(
ctx_,
nullptr,
nullptr);
504 SSL_CTX_set_alpn_protos(
ctx_,
nullptr, 0);
510 size_t SSLContext::pickNextProtocols() {
511 CHECK(!advertisedNextProtocols_.empty()) <<
"Failed to pickNextProtocols";
513 return size_t(nextProtocolDistribution_(rng));
516 #endif // FOLLY_OPENSSL_HAS_ALPN 519 SSL* ssl = SSL_new(
ctx_);
520 if (ssl ==
nullptr) {
521 throw std::runtime_error(
"SSL_new: " + getErrors());
527 SSL_CTX_set_session_id_context(
529 reinterpret_cast<const unsigned char*>(context.data()),
530 std::min<unsigned int>(
531 static_cast<unsigned int>(context.length()), SSL_MAX_SID_CTX_LENGTH));
546 while (i < size && host[j] !=
'\0') {
547 if (toupper(pattern[i]) == toupper(host[j])) {
552 if (pattern[i] ==
'*') {
553 while (host[j] !=
'.' && host[j] !=
'\0') {
561 if (i == size && host[j] ==
'\0') {
575 auto const length =
std::min(userPassword.size(), size_t(size));
576 std::memcpy(password, userPassword.data(), length);
580 #if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH) 581 void SSLContext::enableFalseStart() {
582 SSL_CTX_set_mode(
ctx_, SSL_MODE_HANDSHAKE_CUTTHROUGH);
591 long newOpt = SSL_CTX_set_options(
ctx_, options);
592 if ((newOpt & options) != options) {
593 throw std::runtime_error(
"SSL_CTX_set_options failed");
599 unsigned long errorCode;
603 while ((errorCode = ERR_get_error()) != 0) {
604 if (!errors.empty()) {
607 const char* reason = ERR_reason_error_string(errorCode);
608 if (reason ==
nullptr) {
609 snprintf(message,
sizeof(message) - 1,
"SSL error # %08lX", errorCode);
614 if (errors.empty()) {
615 errors =
"error code: " + folly::to<std::string>(errnoCopy);
static std::string getErrors()
virtual void loadCertificateFromBufferPEM(folly::StringPiece cert)
virtual void loadCertKeyPairFromBufferPEM(folly::StringPiece cert, folly::StringPiece pkey)
virtual std::shared_ptr< PasswordCollector > passwordCollector()
virtual int getVerificationMode()
std::unique_ptr< X509, X509Deleter > X509UniquePtr
std::unique_ptr< BIO, BioDeleter > BioUniquePtr
virtual void setVerificationOption(const SSLVerifyPeerEnum &verifyPeer)
virtual bool isCertKeyPairValid() const
constexpr size_type size() const
static bool matchName(const char *host, const char *pattern, int size)
std::unique_ptr< EVP_PKEY, EvpPkeyDeleter > EvpPkeyUniquePtr
virtual void loadClientCAList(const char *path)
static void initializeOpenSSL()
—— Concurrent Priority Queue Implementation ——
void setOptions(long options)
std::shared_ptr< FizzServerContext > ctx_
virtual void setCiphersOrThrow(const std::string &ciphers)
void setX509VerifyParam(const ssl::X509VerifyParam &x509VerifyParam)
virtual void loadCertKeyPairFromFiles(const char *certPath, const char *keyPath, const char *certFormat="PEM", const char *keyFormat="PEM")
folly::Optional< PskKeyExchangeMode > mode
constexpr auto size(C const &c) -> decltype(c.size())
virtual void loadPrivateKeyFromBufferPEM(folly::StringPiece pkey)
virtual std::string describe() const =0
constexpr Iter data() const
constexpr auto data(C &c) -> decltype(c.data())
virtual void ciphers(const std::string &ciphers)
virtual void loadPrivateKey(const char *path, const char *format="PEM")
virtual void loadCertificate(const char *path, const char *format="PEM")
SSLContext(SSLVersion version=TLSv1)
virtual void authenticate(bool checkPeerCert, bool checkPeerName, const std::string &peerName=std::string())
virtual void loadTrustedCertificates(const char *path)
void setServerECCurve(const std::string &curveName)
void setSessionCacheContext(const std::string &context)
void setClientECCurvesList(const std::vector< std::string > &ecCurves)
void join(const Delim &delimiter, Iterator begin, Iterator end, String &output)
static int passwordCallback(char *password, int size, int, void *data)
static int passwordCallback(char *password, int size, int, void *data)
Formatter< false, Args... > format(StringPiece fmt, Args &&...args)
virtual void passwordCollector(std::shared_ptr< PasswordCollector > collector)
std::unique_ptr< X509_VERIFY_PARAM, X509VerifyParamDeleter > X509VerifyParam
std::ostream & operator<<(std::ostream &out, dynamic const &d)