2 * Copyright 2016 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "SSLContext.h"
19 #include <openssl/err.h>
20 #include <openssl/rand.h>
21 #include <openssl/ssl.h>
22 #include <openssl/x509v3.h>
24 #include <folly/Format.h>
25 #include <folly/Memory.h>
26 #include <folly/Random.h>
27 #include <folly/SpinLock.h>
29 // ---------------------------------------------------------------------
30 // SSLContext implementation
31 // ---------------------------------------------------------------------
33 struct CRYPTO_dynlock_value {
39 // For OpenSSL portability API
40 using namespace folly::ssl;
42 bool SSLContext::initialized_ = false;
46 std::mutex& initMutex() {
51 } // anonymous namespace
53 #ifdef OPENSSL_NPN_NEGOTIATED
54 int SSLContext::sNextProtocolsExDataIndex_ = -1;
57 // SSLContext implementation
58 SSLContext::SSLContext(SSLVersion version) {
60 std::lock_guard<std::mutex> g(initMutex());
61 initializeOpenSSLLocked();
64 ctx_ = SSL_CTX_new(SSLv23_method());
65 if (ctx_ == nullptr) {
66 throw std::runtime_error("SSL_CTX_new: " + getErrors());
72 opt = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
75 opt = SSL_OP_NO_SSLv2;
81 int newOpt = SSL_CTX_set_options(ctx_, opt);
82 DCHECK((newOpt & opt) == opt);
84 SSL_CTX_set_mode(ctx_, SSL_MODE_AUTO_RETRY);
86 checkPeerName_ = false;
88 SSL_CTX_set_options(ctx_, SSL_OP_NO_COMPRESSION);
90 #if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT)
91 SSL_CTX_set_tlsext_servername_callback(ctx_, baseServerNameOpenSSLCallback);
92 SSL_CTX_set_tlsext_servername_arg(ctx_, this);
96 SSLContext::~SSLContext() {
97 if (ctx_ != nullptr) {
102 #ifdef OPENSSL_NPN_NEGOTIATED
103 deleteNextProtocolsStrings();
107 void SSLContext::ciphers(const std::string& ciphers) {
108 providedCiphersString_ = ciphers;
109 setCiphersOrThrow(ciphers);
112 void SSLContext::setCipherList(const std::vector<std::string>& ciphers) {
113 if (ciphers.size() == 0) {
116 std::string opensslCipherList;
117 join(":", ciphers, opensslCipherList);
118 setCiphersOrThrow(opensslCipherList);
121 void SSLContext::setSignatureAlgorithms(
122 const std::vector<std::string>& sigalgs) {
123 if (sigalgs.size() == 0) {
126 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL
127 std::string opensslSigAlgsList;
128 join(":", sigalgs, opensslSigAlgsList);
129 int rc = SSL_CTX_set1_sigalgs_list(ctx_, opensslSigAlgsList.c_str());
131 throw std::runtime_error("SSL_CTX_set1_sigalgs_list " + getErrors());
136 void SSLContext::setClientECCurvesList(
137 const std::vector<std::string>& ecCurves) {
138 if (ecCurves.size() == 0) {
141 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL
142 std::string ecCurvesList;
143 join(":", ecCurves, ecCurvesList);
144 int rc = SSL_CTX_set1_curves_list(ctx_, ecCurvesList.c_str());
146 throw std::runtime_error("SSL_CTX_set1_curves_list " + getErrors());
151 void SSLContext::setServerECCurve(const std::string& curveName) {
152 bool validCall = false;
153 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
154 #ifndef OPENSSL_NO_ECDH
159 throw std::runtime_error("Elliptic curve encryption not allowed");
162 EC_KEY* ecdh = nullptr;
166 * Elliptic-Curve Diffie-Hellman parameters are either "named curves"
167 * from RFC 4492 section 5.1.1, or explicitly described curves over
168 * binary fields. OpenSSL only supports the "named curves", which provide
169 * maximum interoperability.
172 nid = OBJ_sn2nid(curveName.c_str());
174 LOG(FATAL) << "Unknown curve name:" << curveName.c_str();
176 ecdh = EC_KEY_new_by_curve_name(nid);
177 if (ecdh == nullptr) {
178 LOG(FATAL) << "Unable to create curve:" << curveName.c_str();
181 SSL_CTX_set_tmp_ecdh(ctx_, ecdh);
185 void SSLContext::setX509VerifyParam(
186 const ssl::X509VerifyParam& x509VerifyParam) {
187 if (!x509VerifyParam) {
190 if (SSL_CTX_set1_param(ctx_, x509VerifyParam.get()) != 1) {
191 throw std::runtime_error("SSL_CTX_set1_param " + getErrors());
195 void SSLContext::setCiphersOrThrow(const std::string& ciphers) {
196 int rc = SSL_CTX_set_cipher_list(ctx_, ciphers.c_str());
198 throw std::runtime_error("SSL_CTX_set_cipher_list: " + getErrors());
202 void SSLContext::setVerificationOption(const SSLContext::SSLVerifyPeerEnum&
204 CHECK(verifyPeer != SSLVerifyPeerEnum::USE_CTX); // dont recurse
205 verifyPeer_ = verifyPeer;
208 int SSLContext::getVerificationMode(const SSLContext::SSLVerifyPeerEnum&
210 CHECK(verifyPeer != SSLVerifyPeerEnum::USE_CTX);
211 int mode = SSL_VERIFY_NONE;
213 // case SSLVerifyPeerEnum::USE_CTX: // can't happen
216 case SSLVerifyPeerEnum::VERIFY:
217 mode = SSL_VERIFY_PEER;
220 case SSLVerifyPeerEnum::VERIFY_REQ_CLIENT_CERT:
221 mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
224 case SSLVerifyPeerEnum::NO_VERIFY:
225 mode = SSL_VERIFY_NONE;
234 int SSLContext::getVerificationMode() {
235 return getVerificationMode(verifyPeer_);
238 void SSLContext::authenticate(bool checkPeerCert, bool checkPeerName,
239 const std::string& peerName) {
242 mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE;
243 checkPeerName_ = checkPeerName;
244 peerFixedName_ = peerName;
246 mode = SSL_VERIFY_NONE;
247 checkPeerName_ = false; // can't check name without cert!
248 peerFixedName_.clear();
250 SSL_CTX_set_verify(ctx_, mode, nullptr);
253 void SSLContext::loadCertificate(const char* path, const char* format) {
254 if (path == nullptr || format == nullptr) {
255 throw std::invalid_argument(
256 "loadCertificateChain: either <path> or <format> is nullptr");
258 if (strcmp(format, "PEM") == 0) {
259 if (SSL_CTX_use_certificate_chain_file(ctx_, path) == 0) {
260 int errnoCopy = errno;
261 std::string reason("SSL_CTX_use_certificate_chain_file: ");
264 reason.append(getErrors(errnoCopy));
265 throw std::runtime_error(reason);
268 throw std::runtime_error("Unsupported certificate format: " + std::string(format));
272 void SSLContext::loadCertificateFromBufferPEM(folly::StringPiece cert) {
273 if (cert.data() == nullptr) {
274 throw std::invalid_argument("loadCertificate: <cert> is nullptr");
277 ssl::BioUniquePtr bio(BIO_new(BIO_s_mem()));
278 if (bio == nullptr) {
279 throw std::runtime_error("BIO_new: " + getErrors());
282 int written = BIO_write(bio.get(), cert.data(), int(cert.size()));
283 if (written <= 0 || static_cast<unsigned>(written) != cert.size()) {
284 throw std::runtime_error("BIO_write: " + getErrors());
287 ssl::X509UniquePtr x509(
288 PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
289 if (x509 == nullptr) {
290 throw std::runtime_error("PEM_read_bio_X509: " + getErrors());
293 if (SSL_CTX_use_certificate(ctx_, x509.get()) == 0) {
294 throw std::runtime_error("SSL_CTX_use_certificate: " + getErrors());
298 void SSLContext::loadPrivateKey(const char* path, const char* format) {
299 if (path == nullptr || format == nullptr) {
300 throw std::invalid_argument(
301 "loadPrivateKey: either <path> or <format> is nullptr");
303 if (strcmp(format, "PEM") == 0) {
304 if (SSL_CTX_use_PrivateKey_file(ctx_, path, SSL_FILETYPE_PEM) == 0) {
305 throw std::runtime_error("SSL_CTX_use_PrivateKey_file: " + getErrors());
308 throw std::runtime_error("Unsupported private key format: " + std::string(format));
312 void SSLContext::loadPrivateKeyFromBufferPEM(folly::StringPiece pkey) {
313 if (pkey.data() == nullptr) {
314 throw std::invalid_argument("loadPrivateKey: <pkey> is nullptr");
317 ssl::BioUniquePtr bio(BIO_new(BIO_s_mem()));
318 if (bio == nullptr) {
319 throw std::runtime_error("BIO_new: " + getErrors());
322 int written = BIO_write(bio.get(), pkey.data(), int(pkey.size()));
323 if (written <= 0 || static_cast<unsigned>(written) != pkey.size()) {
324 throw std::runtime_error("BIO_write: " + getErrors());
327 ssl::EvpPkeyUniquePtr key(
328 PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
329 if (key == nullptr) {
330 throw std::runtime_error("PEM_read_bio_PrivateKey: " + getErrors());
333 if (SSL_CTX_use_PrivateKey(ctx_, key.get()) == 0) {
334 throw std::runtime_error("SSL_CTX_use_PrivateKey: " + getErrors());
338 void SSLContext::loadTrustedCertificates(const char* path) {
339 if (path == nullptr) {
340 throw std::invalid_argument("loadTrustedCertificates: <path> is nullptr");
342 if (SSL_CTX_load_verify_locations(ctx_, path, nullptr) == 0) {
343 throw std::runtime_error("SSL_CTX_load_verify_locations: " + getErrors());
347 void SSLContext::loadTrustedCertificates(X509_STORE* store) {
348 SSL_CTX_set_cert_store(ctx_, store);
351 void SSLContext::loadClientCAList(const char* path) {
352 auto clientCAs = SSL_load_client_CA_file(path);
353 if (clientCAs == nullptr) {
354 LOG(ERROR) << "Unable to load ca file: " << path;
357 SSL_CTX_set_client_CA_list(ctx_, clientCAs);
360 void SSLContext::randomize() {
364 void SSLContext::passwordCollector(std::shared_ptr<PasswordCollector> collector) {
365 if (collector == nullptr) {
366 LOG(ERROR) << "passwordCollector: ignore invalid password collector";
369 collector_ = collector;
370 SSL_CTX_set_default_passwd_cb(ctx_, passwordCallback);
371 SSL_CTX_set_default_passwd_cb_userdata(ctx_, this);
374 #if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT)
376 void SSLContext::setServerNameCallback(const ServerNameCallback& cb) {
380 void SSLContext::addClientHelloCallback(const ClientHelloCallback& cb) {
381 clientHelloCbs_.push_back(cb);
384 int SSLContext::baseServerNameOpenSSLCallback(SSL* ssl, int* al, void* data) {
385 SSLContext* context = (SSLContext*)data;
387 if (context == nullptr) {
388 return SSL_TLSEXT_ERR_NOACK;
391 for (auto& cb : context->clientHelloCbs_) {
392 // Generic callbacks to happen after we receive the Client Hello.
393 // For example, we use one to switch which cipher we use depending
394 // on the user's TLS version. Because the primary purpose of
395 // baseServerNameOpenSSLCallback is for SNI support, and these callbacks
396 // are side-uses, we ignore any possible failures other than just logging
401 if (!context->serverNameCb_) {
402 return SSL_TLSEXT_ERR_NOACK;
405 ServerNameCallbackResult ret = context->serverNameCb_(ssl);
407 case SERVER_NAME_FOUND:
408 return SSL_TLSEXT_ERR_OK;
409 case SERVER_NAME_NOT_FOUND:
410 return SSL_TLSEXT_ERR_NOACK;
411 case SERVER_NAME_NOT_FOUND_ALERT_FATAL:
412 *al = TLS1_AD_UNRECOGNIZED_NAME;
413 return SSL_TLSEXT_ERR_ALERT_FATAL;
418 return SSL_TLSEXT_ERR_NOACK;
421 void SSLContext::switchCiphersIfTLS11(
423 const std::string& tls11CipherString,
424 const std::vector<std::pair<std::string, int>>& tls11AltCipherlist) {
425 CHECK(!(tls11CipherString.empty() && tls11AltCipherlist.empty()))
426 << "Shouldn't call if empty ciphers / alt ciphers";
428 if (TLS1_get_client_version(ssl) <= TLS1_VERSION) {
429 // We only do this for TLS v 1.1 and later
433 const std::string* ciphers = &tls11CipherString;
434 if (!tls11AltCipherlist.empty()) {
435 if (!cipherListPicker_) {
436 std::vector<int> weights;
438 tls11AltCipherlist.begin(),
439 tls11AltCipherlist.end(),
440 [&](const std::pair<std::string, int>& e) {
441 weights.push_back(e.second);
443 cipherListPicker_.reset(
444 new std::discrete_distribution<int>(weights.begin(), weights.end()));
446 auto rng = ThreadLocalPRNG();
447 auto index = (*cipherListPicker_)(rng);
448 if ((size_t)index >= tls11AltCipherlist.size()) {
449 LOG(ERROR) << "Trying to pick alt TLS11 cipher index " << index
450 << ", but tls11AltCipherlist is of length "
451 << tls11AltCipherlist.size();
453 ciphers = &tls11AltCipherlist[index].first;
457 // Prefer AES for TLS versions 1.1 and later since these are not
458 // vulnerable to BEAST attacks on AES. Note that we're setting the
459 // cipher list on the SSL object, not the SSL_CTX object, so it will
460 // only last for this request.
461 int rc = SSL_set_cipher_list(ssl, ciphers->c_str());
462 if ((rc == 0) || ERR_peek_error() != 0) {
463 // This shouldn't happen since we checked for this when proxygen
465 LOG(WARNING) << "ssl_cipher: No specified ciphers supported for switch";
466 SSL_set_cipher_list(ssl, providedCiphersString_.c_str());
471 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT)
472 int SSLContext::alpnSelectCallback(SSL* /* ssl */,
473 const unsigned char** out,
474 unsigned char* outlen,
475 const unsigned char* in,
478 SSLContext* context = (SSLContext*)data;
480 if (context->advertisedNextProtocols_.empty()) {
484 auto i = context->pickNextProtocols();
485 const auto& item = context->advertisedNextProtocols_[i];
486 if (SSL_select_next_proto((unsigned char**)out,
491 inlen) != OPENSSL_NPN_NEGOTIATED) {
492 return SSL_TLSEXT_ERR_NOACK;
495 return SSL_TLSEXT_ERR_OK;
499 #ifdef OPENSSL_NPN_NEGOTIATED
501 bool SSLContext::setAdvertisedNextProtocols(
502 const std::list<std::string>& protocols, NextProtocolType protocolType) {
503 return setRandomizedAdvertisedNextProtocols({{1, protocols}}, protocolType);
506 bool SSLContext::setRandomizedAdvertisedNextProtocols(
507 const std::list<NextProtocolsItem>& items, NextProtocolType protocolType) {
508 unsetNextProtocols();
509 if (items.size() == 0) {
512 int total_weight = 0;
513 for (const auto &item : items) {
514 if (item.protocols.size() == 0) {
517 AdvertisedNextProtocolsItem advertised_item;
518 advertised_item.length = 0;
519 for (const auto& proto : item.protocols) {
520 ++advertised_item.length;
521 auto protoLength = proto.length();
522 if (protoLength >= 256) {
523 deleteNextProtocolsStrings();
526 advertised_item.length += unsigned(protoLength);
528 advertised_item.protocols = new unsigned char[advertised_item.length];
529 if (!advertised_item.protocols) {
530 throw std::runtime_error("alloc failure");
532 unsigned char* dst = advertised_item.protocols;
533 for (auto& proto : item.protocols) {
534 uint8_t protoLength = uint8_t(proto.length());
535 *dst++ = (unsigned char)protoLength;
536 memcpy(dst, proto.data(), protoLength);
539 total_weight += item.weight;
540 advertisedNextProtocols_.push_back(advertised_item);
541 advertisedNextProtocolWeights_.push_back(item.weight);
543 if (total_weight == 0) {
544 deleteNextProtocolsStrings();
547 nextProtocolDistribution_ =
548 std::discrete_distribution<>(advertisedNextProtocolWeights_.begin(),
549 advertisedNextProtocolWeights_.end());
550 if ((uint8_t)protocolType & (uint8_t)NextProtocolType::NPN) {
551 SSL_CTX_set_next_protos_advertised_cb(
552 ctx_, advertisedNextProtocolCallback, this);
553 SSL_CTX_set_next_proto_select_cb(ctx_, selectNextProtocolCallback, this);
555 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT)
556 if ((uint8_t)protocolType & (uint8_t)NextProtocolType::ALPN) {
557 SSL_CTX_set_alpn_select_cb(ctx_, alpnSelectCallback, this);
558 // Client cannot really use randomized alpn
559 SSL_CTX_set_alpn_protos(ctx_,
560 advertisedNextProtocols_[0].protocols,
561 advertisedNextProtocols_[0].length);
567 void SSLContext::deleteNextProtocolsStrings() {
568 for (auto protocols : advertisedNextProtocols_) {
569 delete[] protocols.protocols;
571 advertisedNextProtocols_.clear();
572 advertisedNextProtocolWeights_.clear();
575 void SSLContext::unsetNextProtocols() {
576 deleteNextProtocolsStrings();
577 SSL_CTX_set_next_protos_advertised_cb(ctx_, nullptr, nullptr);
578 SSL_CTX_set_next_proto_select_cb(ctx_, nullptr, nullptr);
579 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT)
580 SSL_CTX_set_alpn_select_cb(ctx_, nullptr, nullptr);
581 SSL_CTX_set_alpn_protos(ctx_, nullptr, 0);
585 size_t SSLContext::pickNextProtocols() {
586 CHECK(!advertisedNextProtocols_.empty()) << "Failed to pickNextProtocols";
587 auto rng = ThreadLocalPRNG();
588 return nextProtocolDistribution_(rng);
591 int SSLContext::advertisedNextProtocolCallback(SSL* ssl,
592 const unsigned char** out, unsigned int* outlen, void* data) {
593 SSLContext* context = (SSLContext*)data;
594 if (context == nullptr || context->advertisedNextProtocols_.empty()) {
597 } else if (context->advertisedNextProtocols_.size() == 1) {
598 *out = context->advertisedNextProtocols_[0].protocols;
599 *outlen = context->advertisedNextProtocols_[0].length;
601 uintptr_t selected_index = reinterpret_cast<uintptr_t>(SSL_get_ex_data(ssl,
602 sNextProtocolsExDataIndex_));
603 if (selected_index) {
605 *out = context->advertisedNextProtocols_[selected_index].protocols;
606 *outlen = context->advertisedNextProtocols_[selected_index].length;
608 auto i = context->pickNextProtocols();
609 uintptr_t selected = i + 1;
610 SSL_set_ex_data(ssl, sNextProtocolsExDataIndex_, (void*)selected);
611 *out = context->advertisedNextProtocols_[i].protocols;
612 *outlen = context->advertisedNextProtocols_[i].length;
615 return SSL_TLSEXT_ERR_OK;
618 int SSLContext::selectNextProtocolCallback(SSL* ssl,
620 unsigned char* outlen,
621 const unsigned char* server,
622 unsigned int server_len,
624 (void)ssl; // Make -Wunused-parameters happy
625 SSLContext* ctx = (SSLContext*)data;
626 if (ctx->advertisedNextProtocols_.size() > 1) {
627 VLOG(3) << "SSLContext::selectNextProcolCallback() "
628 << "client should be deterministic in selecting protocols.";
631 unsigned char* client = nullptr;
632 unsigned int client_len = 0;
633 bool filtered = false;
634 auto cpf = ctx->getClientProtocolFilterCallback();
636 filtered = (*cpf)(&client, &client_len, server, server_len);
640 if (ctx->advertisedNextProtocols_.empty()) {
641 client = (unsigned char *) "";
644 client = ctx->advertisedNextProtocols_[0].protocols;
645 client_len = ctx->advertisedNextProtocols_[0].length;
649 int retval = SSL_select_next_proto(out, outlen, server, server_len,
651 if (retval != OPENSSL_NPN_NEGOTIATED) {
652 VLOG(3) << "SSLContext::selectNextProcolCallback() "
653 << "unable to pick a next protocol.";
655 return SSL_TLSEXT_ERR_OK;
657 #endif // OPENSSL_NPN_NEGOTIATED
659 SSL* SSLContext::createSSL() const {
660 SSL* ssl = SSL_new(ctx_);
661 if (ssl == nullptr) {
662 throw std::runtime_error("SSL_new: " + getErrors());
667 void SSLContext::setSessionCacheContext(const std::string& context) {
668 SSL_CTX_set_session_id_context(
670 reinterpret_cast<const unsigned char*>(context.data()),
672 static_cast<int>(context.length()), SSL_MAX_SSL_SESSION_ID_LENGTH));
676 * Match a name with a pattern. The pattern may include wildcard. A single
677 * wildcard "*" can match up to one component in the domain name.
679 * @param host Host name, typically the name of the remote host
680 * @param pattern Name retrieved from certificate
681 * @param size Size of "pattern"
682 * @return True, if "host" matches "pattern". False otherwise.
684 bool SSLContext::matchName(const char* host, const char* pattern, int size) {
687 while (i < size && host[j] != '\0') {
688 if (toupper(pattern[i]) == toupper(host[j])) {
693 if (pattern[i] == '*') {
694 while (host[j] != '.' && host[j] != '\0') {
702 if (i == size && host[j] == '\0') {
708 int SSLContext::passwordCallback(char* password,
712 SSLContext* context = (SSLContext*)data;
713 if (context == nullptr || context->passwordCollector() == nullptr) {
716 std::string userPassword;
717 // call user defined password collector to get password
718 context->passwordCollector()->getPassword(userPassword, size);
719 auto length = int(userPassword.size());
723 strncpy(password, userPassword.c_str(), length);
729 SSLContext::SSLLockType inLockType = SSLContext::LOCK_MUTEX) :
730 lockType(inLockType) {
734 if (lockType == SSLContext::LOCK_MUTEX) {
736 } else if (lockType == SSLContext::LOCK_SPINLOCK) {
739 // lockType == LOCK_NONE, no-op
743 if (lockType == SSLContext::LOCK_MUTEX) {
745 } else if (lockType == SSLContext::LOCK_SPINLOCK) {
748 // lockType == LOCK_NONE, no-op
751 SSLContext::SSLLockType lockType;
752 folly::SpinLock spinLock{};
756 // Statics are unsafe in environments that call exit().
757 // If one thread calls exit() while another thread is
758 // references a member of SSLContext, bad things can happen.
759 // SSLContext runs in such environments.
760 // Instead of declaring a static member we "new" the static
761 // member so that it won't be destructed on exit().
762 static std::unique_ptr<SSLLock[]>& locks() {
763 static auto locksInst = new std::unique_ptr<SSLLock[]>();
767 static std::map<int, SSLContext::SSLLockType>& lockTypes() {
768 static auto lockTypesInst = new std::map<int, SSLContext::SSLLockType>();
769 return *lockTypesInst;
772 static void callbackLocking(int mode, int n, const char*, int) {
773 if (mode & CRYPTO_LOCK) {
780 static unsigned long callbackThreadID() {
781 return static_cast<unsigned long>(
783 pthread_mach_thread_np(pthread_self())
785 pthread_getw32threadid_np(pthread_self())
792 static CRYPTO_dynlock_value* dyn_create(const char*, int) {
793 return new CRYPTO_dynlock_value;
796 static void dyn_lock(int mode,
797 struct CRYPTO_dynlock_value* lock,
799 if (lock != nullptr) {
800 if (mode & CRYPTO_LOCK) {
803 lock->mutex.unlock();
808 static void dyn_destroy(struct CRYPTO_dynlock_value* lock, const char*, int) {
812 void SSLContext::setSSLLockTypes(std::map<int, SSLLockType> inLockTypes) {
813 lockTypes() = inLockTypes;
816 #if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH)
817 void SSLContext::enableFalseStart() {
818 SSL_CTX_set_mode(ctx_, SSL_MODE_HANDSHAKE_CUTTHROUGH);
822 void SSLContext::markInitialized() {
823 std::lock_guard<std::mutex> g(initMutex());
827 void SSLContext::initializeOpenSSL() {
828 std::lock_guard<std::mutex> g(initMutex());
829 initializeOpenSSLLocked();
832 void SSLContext::initializeOpenSSLLocked() {
837 SSL_load_error_strings();
838 ERR_load_crypto_strings();
840 locks().reset(new SSLLock[::CRYPTO_num_locks()]);
841 for (auto it: lockTypes()) {
842 locks()[it.first].lockType = it.second;
844 CRYPTO_set_id_callback(callbackThreadID);
845 CRYPTO_set_locking_callback(callbackLocking);
847 CRYPTO_set_dynlock_create_callback(dyn_create);
848 CRYPTO_set_dynlock_lock_callback(dyn_lock);
849 CRYPTO_set_dynlock_destroy_callback(dyn_destroy);
851 #ifdef OPENSSL_NPN_NEGOTIATED
852 sNextProtocolsExDataIndex_ = SSL_get_ex_new_index(0,
853 (void*)"Advertised next protocol index", nullptr, nullptr, nullptr);
858 void SSLContext::cleanupOpenSSL() {
859 std::lock_guard<std::mutex> g(initMutex());
860 cleanupOpenSSLLocked();
863 void SSLContext::cleanupOpenSSLLocked() {
868 CRYPTO_set_id_callback(nullptr);
869 CRYPTO_set_locking_callback(nullptr);
870 CRYPTO_set_dynlock_create_callback(nullptr);
871 CRYPTO_set_dynlock_lock_callback(nullptr);
872 CRYPTO_set_dynlock_destroy_callback(nullptr);
873 CRYPTO_cleanup_all_ex_data();
878 initialized_ = false;
881 void SSLContext::setOptions(long options) {
882 long newOpt = SSL_CTX_set_options(ctx_, options);
883 if ((newOpt & options) != options) {
884 throw std::runtime_error("SSL_CTX_set_options failed");
888 std::string SSLContext::getErrors(int errnoCopy) {
890 unsigned long errorCode;
894 while ((errorCode = ERR_get_error()) != 0) {
895 if (!errors.empty()) {
898 const char* reason = ERR_reason_error_string(errorCode);
899 if (reason == nullptr) {
900 snprintf(message, sizeof(message) - 1, "SSL error # %lu", errorCode);
905 if (errors.empty()) {
906 errors = "error code: " + folly::to<std::string>(errnoCopy);
912 operator<<(std::ostream& os, const PasswordCollector& collector) {
913 os << collector.describe();