Cross-platform and (truly) thread-safe OpenSSL initialization.

This commit is contained in:
Vincent Richard 2013-05-13 16:05:56 +02:00
parent 20c1358402
commit ea700d80f5
5 changed files with 58 additions and 55 deletions

View File

@ -50,79 +50,69 @@ namespace tls {
ref <vmime::utility::sync::criticalSection >* OpenSSLInitializer::sm_mutexes; ref <vmime::utility::sync::criticalSection >* OpenSSLInitializer::sm_mutexes;
int OpenSSLInitializer::sm_initCount(0);
OpenSSLInitializer::OpenSSLInitializer() OpenSSLInitializer::autoInitializer::autoInitializer()
{
// The construction of this unique 'oneTimeInitializer' object will be triggered
// by the 'autoInitializer' objects from the other translation units
static OpenSSLInitializer::oneTimeInitializer oneTimeInitializer;
}
OpenSSLInitializer::autoInitializer::~autoInitializer()
{
}
OpenSSLInitializer::oneTimeInitializer::oneTimeInitializer()
{ {
initialize(); initialize();
} }
OpenSSLInitializer::~OpenSSLInitializer() OpenSSLInitializer::oneTimeInitializer::~oneTimeInitializer()
{ {
uninitialize(); uninitialize();
} }
// static
ref <vmime::utility::sync::criticalSection> OpenSSLInitializer::getMutex()
{
static ref <vmime::utility::sync::criticalSection> criticalSection
= vmime::platform::getHandler()->createCriticalSection();
return criticalSection;
}
// static // static
void OpenSSLInitializer::initialize() void OpenSSLInitializer::initialize()
{ {
ref <vmime::utility::sync::criticalSection> mutex = getMutex();
vmime::utility::sync::autoLock <vmime::utility::sync::criticalSection> lock(mutex);
if (++sm_initCount == 1)
{
#if OPENSSL_VERSION_NUMBER >= 0x0907000L #if OPENSSL_VERSION_NUMBER >= 0x0907000L
OPENSSL_config(NULL); OPENSSL_config(NULL);
#endif #endif
SSL_load_error_strings(); SSL_load_error_strings();
SSL_library_init(); SSL_library_init();
OpenSSL_add_all_algorithms(); OpenSSL_add_all_algorithms();
unsigned char seed[SEEDSIZE]; unsigned char seed[SEEDSIZE];
vmime::platform::getHandler()->generateRandomBytes(seed, SEEDSIZE); vmime::platform::getHandler()->generateRandomBytes(seed, SEEDSIZE);
RAND_seed(seed, SEEDSIZE); RAND_seed(seed, SEEDSIZE);
int numMutexes = CRYPTO_num_locks(); int numMutexes = CRYPTO_num_locks();
sm_mutexes = new ref <vmime::utility::sync::criticalSection>[numMutexes]; sm_mutexes = new ref <vmime::utility::sync::criticalSection>[numMutexes];
for (int i = 0 ; i < numMutexes ; ++i) for (int i = 0 ; i < numMutexes ; ++i)
sm_mutexes[i] = vmime::platform::getHandler()->createCriticalSection(); sm_mutexes[i] = vmime::platform::getHandler()->createCriticalSection();
CRYPTO_set_locking_callback(&OpenSSLInitializer::lock); CRYPTO_set_locking_callback(&OpenSSLInitializer::lock);
CRYPTO_set_id_callback(&OpenSSLInitializer::id); CRYPTO_set_id_callback(&OpenSSLInitializer::id);
}
} }
// static // static
void OpenSSLInitializer::uninitialize() void OpenSSLInitializer::uninitialize()
{ {
ref <vmime::utility::sync::criticalSection> mutex = getMutex(); EVP_cleanup();
vmime::utility::sync::autoLock <vmime::utility::sync::criticalSection> lock(mutex); ERR_free_strings();
if (--sm_initCount == 0) CRYPTO_set_locking_callback(NULL);
{ CRYPTO_set_id_callback(NULL);
EVP_cleanup();
ERR_free_strings();
CRYPTO_set_locking_callback(NULL); delete [] sm_mutexes;
CRYPTO_set_id_callback(NULL);
delete [] sm_mutexes;
}
} }

View File

@ -41,6 +41,9 @@ namespace net {
namespace tls { namespace tls {
static OpenSSLInitializer::autoInitializer openSSLInitializer;
// static // static
ref <TLSSession> TLSSession::create(ref <security::cert::certificateVerifier> cv) ref <TLSSession> TLSSession::create(ref <security::cert::certificateVerifier> cv)
{ {
@ -51,9 +54,6 @@ ref <TLSSession> TLSSession::create(ref <security::cert::certificateVerifier> cv
TLSSession_OpenSSL::TLSSession_OpenSSL(ref <vmime::security::cert::certificateVerifier> cv) TLSSession_OpenSSL::TLSSession_OpenSSL(ref <vmime::security::cert::certificateVerifier> cv)
: m_sslctx(0), m_certVerifier(cv) : m_sslctx(0), m_certVerifier(cv)
{ {
// Thread-safe OpenSSL initialization
static OpenSSLInitializer openSSLInitialization;
m_sslctx = SSL_CTX_new(SSLv23_client_method()); m_sslctx = SSL_CTX_new(SSLv23_client_method());
SSL_CTX_set_options(m_sslctx, SSL_OP_ALL | SSL_OP_NO_SSLv2); SSL_CTX_set_options(m_sslctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
SSL_CTX_set_mode(m_sslctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_mode(m_sslctx, SSL_MODE_AUTO_RETRY);

View File

@ -32,6 +32,7 @@
#include "vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp" #include "vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp"
#include "vmime/net/tls/openssl/TLSSession_OpenSSL.hpp" #include "vmime/net/tls/openssl/TLSSession_OpenSSL.hpp"
#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp"
#include "vmime/platform.hpp" #include "vmime/platform.hpp"
@ -45,6 +46,9 @@ namespace net {
namespace tls { namespace tls {
static OpenSSLInitializer::autoInitializer openSSLInitializer;
// static // static
BIO_METHOD TLSSocket_OpenSSL::sm_customBIOMethod = BIO_METHOD TLSSocket_OpenSSL::sm_customBIOMethod =
{ {

View File

@ -59,6 +59,9 @@ namespace security {
namespace cert { namespace cert {
static net::tls::OpenSSLInitializer::autoInitializer openSSLInitializer;
#ifndef VMIME_BUILDING_DOC #ifndef VMIME_BUILDING_DOC
class monthMap class monthMap
@ -107,9 +110,6 @@ struct OpenSSLX509CertificateInternalData
{ {
OpenSSLX509CertificateInternalData() OpenSSLX509CertificateInternalData()
{ {
// Thread-safe OpenSSL initialization
static net::tls::OpenSSLInitializer openSSLInitialization;
cert = 0; cert = 0;
} }

View File

@ -48,19 +48,29 @@ namespace tls {
*/ */
class OpenSSLInitializer class OpenSSLInitializer
{ {
public: public:
/** Automatically initialize OpenSSL /** Automatically initialize OpenSSL
*/ */
OpenSSLInitializer(); class autoInitializer
{
public:
/** Automatically uninitialize OpenSSL autoInitializer();
*/ ~autoInitializer();
~OpenSSLInitializer(); };
protected: protected:
class oneTimeInitializer
{
public:
oneTimeInitializer();
~oneTimeInitializer();
};
/** Initializes the OpenSSL lib /** Initializes the OpenSSL lib
*/ */
static void initialize(); static void initialize();
@ -85,7 +95,6 @@ protected:
private: private:
static ref <vmime::utility::sync::criticalSection >* sm_mutexes; static ref <vmime::utility::sync::criticalSection >* sm_mutexes;
static int sm_initCount;
}; };