Commit df3064cf authored by subodh's avatar subodh Committed by Dave Watson

Improve initialization of openssl

Summary:
SSLContext takes it upon itself to
perform initialization of openssl along with
cleaning it up.

However in applications where there are multiple
libraries using openssl, cleanup is not really
desirable. Thus the application should own init
and cleanup of openssl, rather than SSLContext.

This is bad because openssl's init apis are not thread
safe.

This diff modifies SSLContext with 3 changes to
make this possible in the context of apps:

1. Add macro SSLCONTEXT_NO_REFCOUNT, for apps to be
able to disable refcounting
2. Move all steps of init into initializeOpenSSL.
As a result, apps can choose when to call
SSLContext::intitializeOpenSSL and if it has
been called before, openssl will not be reinitialized.
3. Move randomize as a static method to make it a part
of the initialization process.

Test Plan: Unit tests.

Reviewed By: ranjeeth@fb.com

Subscribers: ranjeeth, folly-diffs@, ssl-diffs@, njormrod, seanc, trunkagent, dihde

FB internal diff: D1686397

Signature: t1:1686397:1416270565:de805794d65af1c164ed334ff7ba93fe60b2b78a
parent 832ecb9f
...@@ -34,24 +34,24 @@ struct CRYPTO_dynlock_value { ...@@ -34,24 +34,24 @@ struct CRYPTO_dynlock_value {
namespace folly { namespace folly {
uint64_t SSLContext::count_ = 0; bool SSLContext::initialized_ = false;
std::mutex SSLContext::mutex_; std::mutex SSLContext::mutex_;
#ifdef OPENSSL_NPN_NEGOTIATED #ifdef OPENSSL_NPN_NEGOTIATED
int SSLContext::sNextProtocolsExDataIndex_ = -1; int SSLContext::sNextProtocolsExDataIndex_ = -1;
#endif
#ifndef SSLCONTEXT_NO_REFCOUNT
uint64_t SSLContext::count_ = 0;
#endif #endif
// SSLContext implementation // SSLContext implementation
SSLContext::SSLContext(SSLVersion version) { SSLContext::SSLContext(SSLVersion version) {
{ {
std::lock_guard<std::mutex> g(mutex_); std::lock_guard<std::mutex> g(mutex_);
if (!count_++) { #ifndef SSLCONTEXT_NO_REFCOUNT
initializeOpenSSL(); count_++;
randomize();
#ifdef OPENSSL_NPN_NEGOTIATED
sNextProtocolsExDataIndex_ = SSL_get_ex_new_index(0,
(void*)"Advertised next protocol index", nullptr, nullptr, nullptr);
#endif #endif
} initializeOpenSSLLocked();
} }
ctx_ = SSL_CTX_new(SSLv23_method()); ctx_ = SSL_CTX_new(SSLv23_method());
...@@ -94,10 +94,14 @@ SSLContext::~SSLContext() { ...@@ -94,10 +94,14 @@ SSLContext::~SSLContext() {
deleteNextProtocolsStrings(); deleteNextProtocolsStrings();
#endif #endif
std::lock_guard<std::mutex> g(mutex_); #ifndef SSLCONTEXT_NO_REFCOUNT
if (!--count_) { {
cleanupOpenSSL(); std::lock_guard<std::mutex> g(mutex_);
if (!--count_) {
cleanupOpenSSLLocked();
}
} }
#endif
} }
void SSLContext::ciphers(const std::string& ciphers) { void SSLContext::ciphers(const std::string& ciphers) {
...@@ -580,6 +584,14 @@ void SSLContext::setSSLLockTypes(std::map<int, SSLLockType> inLockTypes) { ...@@ -580,6 +584,14 @@ void SSLContext::setSSLLockTypes(std::map<int, SSLLockType> inLockTypes) {
} }
void SSLContext::initializeOpenSSL() { void SSLContext::initializeOpenSSL() {
std::lock_guard<std::mutex> g(mutex_);
initializeOpenSSLLocked();
}
void SSLContext::initializeOpenSSLLocked() {
if (initialized_) {
return;
}
SSL_library_init(); SSL_library_init();
SSL_load_error_strings(); SSL_load_error_strings();
ERR_load_crypto_strings(); ERR_load_crypto_strings();
...@@ -594,9 +606,24 @@ void SSLContext::initializeOpenSSL() { ...@@ -594,9 +606,24 @@ void SSLContext::initializeOpenSSL() {
CRYPTO_set_dynlock_create_callback(dyn_create); CRYPTO_set_dynlock_create_callback(dyn_create);
CRYPTO_set_dynlock_lock_callback(dyn_lock); CRYPTO_set_dynlock_lock_callback(dyn_lock);
CRYPTO_set_dynlock_destroy_callback(dyn_destroy); CRYPTO_set_dynlock_destroy_callback(dyn_destroy);
randomize();
#ifdef OPENSSL_NPN_NEGOTIATED
sNextProtocolsExDataIndex_ = SSL_get_ex_new_index(0,
(void*)"Advertised next protocol index", nullptr, nullptr, nullptr);
#endif
initialized_ = true;
} }
void SSLContext::cleanupOpenSSL() { void SSLContext::cleanupOpenSSL() {
std::lock_guard<std::mutex> g(mutex_);
cleanupOpenSSLLocked();
}
void SSLContext::cleanupOpenSSLLocked() {
if (!initialized_) {
return;
}
CRYPTO_set_id_callback(nullptr); CRYPTO_set_id_callback(nullptr);
CRYPTO_set_locking_callback(nullptr); CRYPTO_set_locking_callback(nullptr);
CRYPTO_set_dynlock_create_callback(nullptr); CRYPTO_set_dynlock_create_callback(nullptr);
...@@ -607,6 +634,7 @@ void SSLContext::cleanupOpenSSL() { ...@@ -607,6 +634,7 @@ void SSLContext::cleanupOpenSSL() {
EVP_cleanup(); EVP_cleanup();
ERR_remove_state(0); ERR_remove_state(0);
locks.reset(); locks.reset();
initialized_ = false;
} }
void SSLContext::setOptions(long options) { void SSLContext::setOptions(long options) {
......
...@@ -198,10 +198,6 @@ class SSLContext { ...@@ -198,10 +198,6 @@ class SSLContext {
* Load a client CA list for validating clients * Load a client CA list for validating clients
*/ */
virtual void loadClientCAList(const char* path); virtual void loadClientCAList(const char* path);
/**
* Default randomize method.
*/
virtual void randomize();
/** /**
* Override default OpenSSL password collector. * Override default OpenSSL password collector.
* *
...@@ -388,6 +384,18 @@ class SSLContext { ...@@ -388,6 +384,18 @@ class SSLContext {
*/ */
static bool matchName(const char* host, const char* pattern, int size); static bool matchName(const char* host, const char* pattern, int size);
/**
* Functions for setting up and cleaning up openssl.
* They can be invoked during the start of the application.
*/
static void initializeOpenSSL();
static void cleanupOpenSSL();
/**
* Default randomize method.
*/
static void randomize();
protected: protected:
SSL_CTX* ctx_; SSL_CTX* ctx_;
...@@ -403,7 +411,11 @@ class SSLContext { ...@@ -403,7 +411,11 @@ class SSLContext {
#endif #endif
static std::mutex mutex_; static std::mutex mutex_;
static bool initialized_;
#ifndef SSLCONTEXT_NO_REFCOUNT
static uint64_t count_; static uint64_t count_;
#endif
#ifdef OPENSSL_NPN_NEGOTIATED #ifdef OPENSSL_NPN_NEGOTIATED
/** /**
...@@ -421,10 +433,6 @@ class SSLContext { ...@@ -421,10 +433,6 @@ class SSLContext {
static int passwordCallback(char* password, int size, int, void* data); static int passwordCallback(char* password, int size, int, void* data);
static void initializeOpenSSL();
static void cleanupOpenSSL();
#if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT) #if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT)
/** /**
* The function that will be called directly from openssl * The function that will be called directly from openssl
...@@ -444,6 +452,10 @@ class SSLContext { ...@@ -444,6 +452,10 @@ class SSLContext {
#endif #endif
std::string providedCiphersString_; std::string providedCiphersString_;
// Functions are called when locked by the calling function.
static void initializeOpenSSLLocked();
static void cleanupOpenSSLLocked();
}; };
typedef std::shared_ptr<SSLContext> SSLContextPtr; typedef std::shared_ptr<SSLContext> SSLContextPtr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment