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 bool SSLContext::initialized_ = false;
43 std::mutex& initMutex() {
48 } // anonymous namespace
50 #ifdef OPENSSL_NPN_NEGOTIATED
51 int SSLContext::sNextProtocolsExDataIndex_ = -1;
54 // SSLContext implementation
55 SSLContext::SSLContext(SSLVersion version) {
57 std::lock_guard<std::mutex> g(initMutex());
58 initializeOpenSSLLocked();
61 ctx_ = SSL_CTX_new(SSLv23_method());
62 if (ctx_ == nullptr) {
63 throw std::runtime_error("SSL_CTX_new: " + getErrors());
69 opt = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
72 opt = SSL_OP_NO_SSLv2;
78 int newOpt = SSL_CTX_set_options(ctx_, opt);
79 DCHECK((newOpt & opt) == opt);
81 SSL_CTX_set_mode(ctx_, SSL_MODE_AUTO_RETRY);
83 checkPeerName_ = false;
85 SSL_CTX_set_options(ctx_, SSL_OP_NO_COMPRESSION);
87 #if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT)
88 SSL_CTX_set_tlsext_servername_callback(ctx_, baseServerNameOpenSSLCallback);
89 SSL_CTX_set_tlsext_servername_arg(ctx_, this);
93 SSLContext::~SSLContext() {
94 if (ctx_ != nullptr) {
99 #ifdef OPENSSL_NPN_NEGOTIATED
100 deleteNextProtocolsStrings();
104 void SSLContext::ciphers(const std::string& ciphers) {
105 providedCiphersString_ = ciphers;
106 setCiphersOrThrow(ciphers);
109 void SSLContext::setCipherList(const std::vector<std::string>& ciphers) {
110 if (ciphers.size() == 0) {
113 std::string opensslCipherList;
114 join(":", ciphers, opensslCipherList);
115 setCiphersOrThrow(opensslCipherList);
118 void SSLContext::setSignatureAlgorithms(
119 const std::vector<std::string>& sigalgs) {
120 if (sigalgs.size() == 0) {
123 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL
124 std::string opensslSigAlgsList;
125 join(":", sigalgs, opensslSigAlgsList);
126 int rc = SSL_CTX_set1_sigalgs_list(ctx_, opensslSigAlgsList.c_str());
128 throw std::runtime_error("SSL_CTX_set1_sigalgs_list " + getErrors());
133 void SSLContext::setClientECCurvesList(
134 const std::vector<std::string>& ecCurves) {
135 if (ecCurves.size() == 0) {
138 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL
139 std::string ecCurvesList;
140 join(":", ecCurves, ecCurvesList);
141 int rc = SSL_CTX_set1_curves_list(ctx_, ecCurvesList.c_str());
143 throw std::runtime_error("SSL_CTX_set1_curves_list " + getErrors());
148 void SSLContext::setX509VerifyParam(
149 const ssl::X509VerifyParam& x509VerifyParam) {
150 if (!x509VerifyParam) {
153 if (SSL_CTX_set1_param(ctx_, x509VerifyParam.get()) != 1) {
154 throw std::runtime_error("SSL_CTX_set1_param " + getErrors());
158 void SSLContext::setCiphersOrThrow(const std::string& ciphers) {
159 int rc = SSL_CTX_set_cipher_list(ctx_, ciphers.c_str());
161 throw std::runtime_error("SSL_CTX_set_cipher_list: " + getErrors());
165 void SSLContext::setVerificationOption(const SSLContext::SSLVerifyPeerEnum&
167 CHECK(verifyPeer != SSLVerifyPeerEnum::USE_CTX); // dont recurse
168 verifyPeer_ = verifyPeer;
171 int SSLContext::getVerificationMode(const SSLContext::SSLVerifyPeerEnum&
173 CHECK(verifyPeer != SSLVerifyPeerEnum::USE_CTX);
174 int mode = SSL_VERIFY_NONE;
176 // case SSLVerifyPeerEnum::USE_CTX: // can't happen
179 case SSLVerifyPeerEnum::VERIFY:
180 mode = SSL_VERIFY_PEER;
183 case SSLVerifyPeerEnum::VERIFY_REQ_CLIENT_CERT:
184 mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
187 case SSLVerifyPeerEnum::NO_VERIFY:
188 mode = SSL_VERIFY_NONE;
197 int SSLContext::getVerificationMode() {
198 return getVerificationMode(verifyPeer_);
201 void SSLContext::authenticate(bool checkPeerCert, bool checkPeerName,
202 const std::string& peerName) {
205 mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE;
206 checkPeerName_ = checkPeerName;
207 peerFixedName_ = peerName;
209 mode = SSL_VERIFY_NONE;
210 checkPeerName_ = false; // can't check name without cert!
211 peerFixedName_.clear();
213 SSL_CTX_set_verify(ctx_, mode, nullptr);
216 void SSLContext::loadCertificate(const char* path, const char* format) {
217 if (path == nullptr || format == nullptr) {
218 throw std::invalid_argument(
219 "loadCertificateChain: either <path> or <format> is nullptr");
221 if (strcmp(format, "PEM") == 0) {
222 if (SSL_CTX_use_certificate_chain_file(ctx_, path) == 0) {
223 int errnoCopy = errno;
224 std::string reason("SSL_CTX_use_certificate_chain_file: ");
227 reason.append(getErrors(errnoCopy));
228 throw std::runtime_error(reason);
231 throw std::runtime_error("Unsupported certificate format: " + std::string(format));
235 void SSLContext::loadCertificateFromBufferPEM(folly::StringPiece cert) {
236 if (cert.data() == nullptr) {
237 throw std::invalid_argument("loadCertificate: <cert> is nullptr");
240 ssl::BioUniquePtr bio(BIO_new(BIO_s_mem()));
241 if (bio == nullptr) {
242 throw std::runtime_error("BIO_new: " + getErrors());
245 int written = BIO_write(bio.get(), cert.data(), cert.size());
246 if (written <= 0 || static_cast<unsigned>(written) != cert.size()) {
247 throw std::runtime_error("BIO_write: " + getErrors());
250 ssl::X509UniquePtr x509(
251 PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
252 if (x509 == nullptr) {
253 throw std::runtime_error("PEM_read_bio_X509: " + getErrors());
256 if (SSL_CTX_use_certificate(ctx_, x509.get()) == 0) {
257 throw std::runtime_error("SSL_CTX_use_certificate: " + getErrors());
261 void SSLContext::loadPrivateKey(const char* path, const char* format) {
262 if (path == nullptr || format == nullptr) {
263 throw std::invalid_argument(
264 "loadPrivateKey: either <path> or <format> is nullptr");
266 if (strcmp(format, "PEM") == 0) {
267 if (SSL_CTX_use_PrivateKey_file(ctx_, path, SSL_FILETYPE_PEM) == 0) {
268 throw std::runtime_error("SSL_CTX_use_PrivateKey_file: " + getErrors());
271 throw std::runtime_error("Unsupported private key format: " + std::string(format));
275 void SSLContext::loadPrivateKeyFromBufferPEM(folly::StringPiece pkey) {
276 if (pkey.data() == nullptr) {
277 throw std::invalid_argument("loadPrivateKey: <pkey> is nullptr");
280 ssl::BioUniquePtr bio(BIO_new(BIO_s_mem()));
281 if (bio == nullptr) {
282 throw std::runtime_error("BIO_new: " + getErrors());
285 int written = BIO_write(bio.get(), pkey.data(), pkey.size());
286 if (written <= 0 || static_cast<unsigned>(written) != pkey.size()) {
287 throw std::runtime_error("BIO_write: " + getErrors());
290 ssl::EvpPkeyUniquePtr key(
291 PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
292 if (key == nullptr) {
293 throw std::runtime_error("PEM_read_bio_PrivateKey: " + getErrors());
296 if (SSL_CTX_use_PrivateKey(ctx_, key.get()) == 0) {
297 throw std::runtime_error("SSL_CTX_use_PrivateKey: " + getErrors());
301 void SSLContext::loadTrustedCertificates(const char* path) {
302 if (path == nullptr) {
303 throw std::invalid_argument("loadTrustedCertificates: <path> is nullptr");
305 if (SSL_CTX_load_verify_locations(ctx_, path, nullptr) == 0) {
306 throw std::runtime_error("SSL_CTX_load_verify_locations: " + getErrors());
310 void SSLContext::loadTrustedCertificates(X509_STORE* store) {
311 SSL_CTX_set_cert_store(ctx_, store);
314 void SSLContext::loadClientCAList(const char* path) {
315 auto clientCAs = SSL_load_client_CA_file(path);
316 if (clientCAs == nullptr) {
317 LOG(ERROR) << "Unable to load ca file: " << path;
320 SSL_CTX_set_client_CA_list(ctx_, clientCAs);
323 void SSLContext::randomize() {
327 void SSLContext::passwordCollector(std::shared_ptr<PasswordCollector> collector) {
328 if (collector == nullptr) {
329 LOG(ERROR) << "passwordCollector: ignore invalid password collector";
332 collector_ = collector;
333 SSL_CTX_set_default_passwd_cb(ctx_, passwordCallback);
334 SSL_CTX_set_default_passwd_cb_userdata(ctx_, this);
337 #if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT)
339 void SSLContext::setServerNameCallback(const ServerNameCallback& cb) {
343 void SSLContext::addClientHelloCallback(const ClientHelloCallback& cb) {
344 clientHelloCbs_.push_back(cb);
347 int SSLContext::baseServerNameOpenSSLCallback(SSL* ssl, int* al, void* data) {
348 SSLContext* context = (SSLContext*)data;
350 if (context == nullptr) {
351 return SSL_TLSEXT_ERR_NOACK;
354 for (auto& cb : context->clientHelloCbs_) {
355 // Generic callbacks to happen after we receive the Client Hello.
356 // For example, we use one to switch which cipher we use depending
357 // on the user's TLS version. Because the primary purpose of
358 // baseServerNameOpenSSLCallback is for SNI support, and these callbacks
359 // are side-uses, we ignore any possible failures other than just logging
364 if (!context->serverNameCb_) {
365 return SSL_TLSEXT_ERR_NOACK;
368 ServerNameCallbackResult ret = context->serverNameCb_(ssl);
370 case SERVER_NAME_FOUND:
371 return SSL_TLSEXT_ERR_OK;
372 case SERVER_NAME_NOT_FOUND:
373 return SSL_TLSEXT_ERR_NOACK;
374 case SERVER_NAME_NOT_FOUND_ALERT_FATAL:
375 *al = TLS1_AD_UNRECOGNIZED_NAME;
376 return SSL_TLSEXT_ERR_ALERT_FATAL;
381 return SSL_TLSEXT_ERR_NOACK;
384 void SSLContext::switchCiphersIfTLS11(
386 const std::string& tls11CipherString,
387 const std::vector<std::pair<std::string, int>>& tls11AltCipherlist) {
388 CHECK(!(tls11CipherString.empty() && tls11AltCipherlist.empty()))
389 << "Shouldn't call if empty ciphers / alt ciphers";
391 if (TLS1_get_client_version(ssl) <= TLS1_VERSION) {
392 // We only do this for TLS v 1.1 and later
396 const std::string* ciphers = &tls11CipherString;
397 if (!tls11AltCipherlist.empty()) {
398 if (!cipherListPicker_) {
399 std::vector<int> weights;
401 tls11AltCipherlist.begin(),
402 tls11AltCipherlist.end(),
403 [&](const std::pair<std::string, int>& e) {
404 weights.push_back(e.second);
406 cipherListPicker_.reset(
407 new std::discrete_distribution<int>(weights.begin(), weights.end()));
409 auto rng = ThreadLocalPRNG();
410 auto index = (*cipherListPicker_)(rng);
411 if ((size_t)index >= tls11AltCipherlist.size()) {
412 LOG(ERROR) << "Trying to pick alt TLS11 cipher index " << index
413 << ", but tls11AltCipherlist is of length "
414 << tls11AltCipherlist.size();
416 ciphers = &tls11AltCipherlist[index].first;
420 // Prefer AES for TLS versions 1.1 and later since these are not
421 // vulnerable to BEAST attacks on AES. Note that we're setting the
422 // cipher list on the SSL object, not the SSL_CTX object, so it will
423 // only last for this request.
424 int rc = SSL_set_cipher_list(ssl, ciphers->c_str());
425 if ((rc == 0) || ERR_peek_error() != 0) {
426 // This shouldn't happen since we checked for this when proxygen
428 LOG(WARNING) << "ssl_cipher: No specified ciphers supported for switch";
429 SSL_set_cipher_list(ssl, providedCiphersString_.c_str());
434 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT)
435 int SSLContext::alpnSelectCallback(SSL* /* ssl */,
436 const unsigned char** out,
437 unsigned char* outlen,
438 const unsigned char* in,
441 SSLContext* context = (SSLContext*)data;
443 if (context->advertisedNextProtocols_.empty()) {
447 auto i = context->pickNextProtocols();
448 const auto& item = context->advertisedNextProtocols_[i];
449 if (SSL_select_next_proto((unsigned char**)out,
454 inlen) != OPENSSL_NPN_NEGOTIATED) {
455 return SSL_TLSEXT_ERR_NOACK;
458 return SSL_TLSEXT_ERR_OK;
462 #ifdef OPENSSL_NPN_NEGOTIATED
464 bool SSLContext::setAdvertisedNextProtocols(
465 const std::list<std::string>& protocols, NextProtocolType protocolType) {
466 return setRandomizedAdvertisedNextProtocols({{1, protocols}}, protocolType);
469 bool SSLContext::setRandomizedAdvertisedNextProtocols(
470 const std::list<NextProtocolsItem>& items, NextProtocolType protocolType) {
471 unsetNextProtocols();
472 if (items.size() == 0) {
475 int total_weight = 0;
476 for (const auto &item : items) {
477 if (item.protocols.size() == 0) {
480 AdvertisedNextProtocolsItem advertised_item;
481 advertised_item.length = 0;
482 for (const auto& proto : item.protocols) {
483 ++advertised_item.length;
484 unsigned protoLength = proto.length();
485 if (protoLength >= 256) {
486 deleteNextProtocolsStrings();
489 advertised_item.length += protoLength;
491 advertised_item.protocols = new unsigned char[advertised_item.length];
492 if (!advertised_item.protocols) {
493 throw std::runtime_error("alloc failure");
495 unsigned char* dst = advertised_item.protocols;
496 for (auto& proto : item.protocols) {
497 unsigned protoLength = proto.length();
498 *dst++ = (unsigned char)protoLength;
499 memcpy(dst, proto.data(), protoLength);
502 total_weight += item.weight;
503 advertisedNextProtocols_.push_back(advertised_item);
504 advertisedNextProtocolWeights_.push_back(item.weight);
506 if (total_weight == 0) {
507 deleteNextProtocolsStrings();
510 nextProtocolDistribution_ =
511 std::discrete_distribution<>(advertisedNextProtocolWeights_.begin(),
512 advertisedNextProtocolWeights_.end());
513 if ((uint8_t)protocolType & (uint8_t)NextProtocolType::NPN) {
514 SSL_CTX_set_next_protos_advertised_cb(
515 ctx_, advertisedNextProtocolCallback, this);
516 SSL_CTX_set_next_proto_select_cb(ctx_, selectNextProtocolCallback, this);
518 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT)
519 if ((uint8_t)protocolType & (uint8_t)NextProtocolType::ALPN) {
520 SSL_CTX_set_alpn_select_cb(ctx_, alpnSelectCallback, this);
521 // Client cannot really use randomized alpn
522 SSL_CTX_set_alpn_protos(ctx_,
523 advertisedNextProtocols_[0].protocols,
524 advertisedNextProtocols_[0].length);
530 void SSLContext::deleteNextProtocolsStrings() {
531 for (auto protocols : advertisedNextProtocols_) {
532 delete[] protocols.protocols;
534 advertisedNextProtocols_.clear();
535 advertisedNextProtocolWeights_.clear();
538 void SSLContext::unsetNextProtocols() {
539 deleteNextProtocolsStrings();
540 SSL_CTX_set_next_protos_advertised_cb(ctx_, nullptr, nullptr);
541 SSL_CTX_set_next_proto_select_cb(ctx_, nullptr, nullptr);
542 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT)
543 SSL_CTX_set_alpn_select_cb(ctx_, nullptr, nullptr);
544 SSL_CTX_set_alpn_protos(ctx_, nullptr, 0);
548 size_t SSLContext::pickNextProtocols() {
549 CHECK(!advertisedNextProtocols_.empty()) << "Failed to pickNextProtocols";
550 auto rng = ThreadLocalPRNG();
551 return nextProtocolDistribution_(rng);
554 int SSLContext::advertisedNextProtocolCallback(SSL* ssl,
555 const unsigned char** out, unsigned int* outlen, void* data) {
556 SSLContext* context = (SSLContext*)data;
557 if (context == nullptr || context->advertisedNextProtocols_.empty()) {
560 } else if (context->advertisedNextProtocols_.size() == 1) {
561 *out = context->advertisedNextProtocols_[0].protocols;
562 *outlen = context->advertisedNextProtocols_[0].length;
564 uintptr_t selected_index = reinterpret_cast<uintptr_t>(SSL_get_ex_data(ssl,
565 sNextProtocolsExDataIndex_));
566 if (selected_index) {
568 *out = context->advertisedNextProtocols_[selected_index].protocols;
569 *outlen = context->advertisedNextProtocols_[selected_index].length;
571 auto i = context->pickNextProtocols();
572 uintptr_t selected = i + 1;
573 SSL_set_ex_data(ssl, sNextProtocolsExDataIndex_, (void*)selected);
574 *out = context->advertisedNextProtocols_[i].protocols;
575 *outlen = context->advertisedNextProtocols_[i].length;
578 return SSL_TLSEXT_ERR_OK;
581 int SSLContext::selectNextProtocolCallback(SSL* ssl,
583 unsigned char* outlen,
584 const unsigned char* server,
585 unsigned int server_len,
587 (void)ssl; // Make -Wunused-parameters happy
588 SSLContext* ctx = (SSLContext*)data;
589 if (ctx->advertisedNextProtocols_.size() > 1) {
590 VLOG(3) << "SSLContext::selectNextProcolCallback() "
591 << "client should be deterministic in selecting protocols.";
594 unsigned char *client;
595 unsigned int client_len;
596 bool filtered = false;
597 auto cpf = ctx->getClientProtocolFilterCallback();
599 filtered = (*cpf)(&client, &client_len, server, server_len);
603 if (ctx->advertisedNextProtocols_.empty()) {
604 client = (unsigned char *) "";
607 client = ctx->advertisedNextProtocols_[0].protocols;
608 client_len = ctx->advertisedNextProtocols_[0].length;
612 int retval = SSL_select_next_proto(out, outlen, server, server_len,
614 if (retval != OPENSSL_NPN_NEGOTIATED) {
615 VLOG(3) << "SSLContext::selectNextProcolCallback() "
616 << "unable to pick a next protocol.";
618 return SSL_TLSEXT_ERR_OK;
620 #endif // OPENSSL_NPN_NEGOTIATED
622 SSL* SSLContext::createSSL() const {
623 SSL* ssl = SSL_new(ctx_);
624 if (ssl == nullptr) {
625 throw std::runtime_error("SSL_new: " + getErrors());
630 void SSLContext::setSessionCacheContext(const std::string& context) {
631 SSL_CTX_set_session_id_context(
633 reinterpret_cast<const unsigned char*>(context.data()),
635 static_cast<int>(context.length()), SSL_MAX_SSL_SESSION_ID_LENGTH));
639 * Match a name with a pattern. The pattern may include wildcard. A single
640 * wildcard "*" can match up to one component in the domain name.
642 * @param host Host name, typically the name of the remote host
643 * @param pattern Name retrieved from certificate
644 * @param size Size of "pattern"
645 * @return True, if "host" matches "pattern". False otherwise.
647 bool SSLContext::matchName(const char* host, const char* pattern, int size) {
650 while (i < size && host[j] != '\0') {
651 if (toupper(pattern[i]) == toupper(host[j])) {
656 if (pattern[i] == '*') {
657 while (host[j] != '.' && host[j] != '\0') {
665 if (i == size && host[j] == '\0') {
671 int SSLContext::passwordCallback(char* password,
675 SSLContext* context = (SSLContext*)data;
676 if (context == nullptr || context->passwordCollector() == nullptr) {
679 std::string userPassword;
680 // call user defined password collector to get password
681 context->passwordCollector()->getPassword(userPassword, size);
682 int length = userPassword.size();
686 strncpy(password, userPassword.c_str(), length);
692 SSLContext::SSLLockType inLockType = SSLContext::LOCK_MUTEX) :
693 lockType(inLockType) {
697 if (lockType == SSLContext::LOCK_MUTEX) {
699 } else if (lockType == SSLContext::LOCK_SPINLOCK) {
702 // lockType == LOCK_NONE, no-op
706 if (lockType == SSLContext::LOCK_MUTEX) {
708 } else if (lockType == SSLContext::LOCK_SPINLOCK) {
711 // lockType == LOCK_NONE, no-op
714 SSLContext::SSLLockType lockType;
715 folly::SpinLock spinLock{};
719 // Statics are unsafe in environments that call exit().
720 // If one thread calls exit() while another thread is
721 // references a member of SSLContext, bad things can happen.
722 // SSLContext runs in such environments.
723 // Instead of declaring a static member we "new" the static
724 // member so that it won't be destructed on exit().
725 static std::unique_ptr<SSLLock[]>& locks() {
726 static auto locksInst = new std::unique_ptr<SSLLock[]>();
730 static std::map<int, SSLContext::SSLLockType>& lockTypes() {
731 static auto lockTypesInst = new std::map<int, SSLContext::SSLLockType>();
732 return *lockTypesInst;
735 static void callbackLocking(int mode, int n, const char*, int) {
736 if (mode & CRYPTO_LOCK) {
743 static unsigned long callbackThreadID() {
744 return static_cast<unsigned long>(
746 pthread_mach_thread_np(pthread_self())
748 pthread_getw32threadid_np(pthread_self())
755 static CRYPTO_dynlock_value* dyn_create(const char*, int) {
756 return new CRYPTO_dynlock_value;
759 static void dyn_lock(int mode,
760 struct CRYPTO_dynlock_value* lock,
762 if (lock != nullptr) {
763 if (mode & CRYPTO_LOCK) {
766 lock->mutex.unlock();
771 static void dyn_destroy(struct CRYPTO_dynlock_value* lock, const char*, int) {
775 void SSLContext::setSSLLockTypes(std::map<int, SSLLockType> inLockTypes) {
776 lockTypes() = inLockTypes;
779 #if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH)
780 void SSLContext::enableFalseStart() {
781 SSL_CTX_set_mode(ctx_, SSL_MODE_HANDSHAKE_CUTTHROUGH);
785 void SSLContext::markInitialized() {
786 std::lock_guard<std::mutex> g(initMutex());
790 void SSLContext::initializeOpenSSL() {
791 std::lock_guard<std::mutex> g(initMutex());
792 initializeOpenSSLLocked();
795 void SSLContext::initializeOpenSSLLocked() {
800 SSL_load_error_strings();
801 ERR_load_crypto_strings();
803 locks().reset(new SSLLock[::CRYPTO_num_locks()]);
804 for (auto it: lockTypes()) {
805 locks()[it.first].lockType = it.second;
807 CRYPTO_set_id_callback(callbackThreadID);
808 CRYPTO_set_locking_callback(callbackLocking);
810 CRYPTO_set_dynlock_create_callback(dyn_create);
811 CRYPTO_set_dynlock_lock_callback(dyn_lock);
812 CRYPTO_set_dynlock_destroy_callback(dyn_destroy);
814 #ifdef OPENSSL_NPN_NEGOTIATED
815 sNextProtocolsExDataIndex_ = SSL_get_ex_new_index(0,
816 (void*)"Advertised next protocol index", nullptr, nullptr, nullptr);
821 void SSLContext::cleanupOpenSSL() {
822 std::lock_guard<std::mutex> g(initMutex());
823 cleanupOpenSSLLocked();
826 void SSLContext::cleanupOpenSSLLocked() {
831 CRYPTO_set_id_callback(nullptr);
832 CRYPTO_set_locking_callback(nullptr);
833 CRYPTO_set_dynlock_create_callback(nullptr);
834 CRYPTO_set_dynlock_lock_callback(nullptr);
835 CRYPTO_set_dynlock_destroy_callback(nullptr);
836 CRYPTO_cleanup_all_ex_data();
841 initialized_ = false;
844 void SSLContext::setOptions(long options) {
845 long newOpt = SSL_CTX_set_options(ctx_, options);
846 if ((newOpt & options) != options) {
847 throw std::runtime_error("SSL_CTX_set_options failed");
851 std::string SSLContext::getErrors(int errnoCopy) {
853 unsigned long errorCode;
857 while ((errorCode = ERR_get_error()) != 0) {
858 if (!errors.empty()) {
861 const char* reason = ERR_reason_error_string(errorCode);
862 if (reason == nullptr) {
863 snprintf(message, sizeof(message) - 1, "SSL error # %lu", errorCode);
868 if (errors.empty()) {
869 errors = "error code: " + folly::to<std::string>(errnoCopy);
875 operator<<(std::ostream& os, const PasswordCollector& collector) {
876 os << collector.describe();