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;
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();
}
OpenSSLInitializer::~OpenSSLInitializer()
OpenSSLInitializer::oneTimeInitializer::~oneTimeInitializer()
{
uninitialize();
}
// static
ref <vmime::utility::sync::criticalSection> OpenSSLInitializer::getMutex()
{
static ref <vmime::utility::sync::criticalSection> criticalSection
= vmime::platform::getHandler()->createCriticalSection();
return criticalSection;
}
// static
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
OPENSSL_config(NULL);
OPENSSL_config(NULL);
#endif
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
unsigned char seed[SEEDSIZE];
vmime::platform::getHandler()->generateRandomBytes(seed, SEEDSIZE);
RAND_seed(seed, SEEDSIZE);
unsigned char seed[SEEDSIZE];
vmime::platform::getHandler()->generateRandomBytes(seed, SEEDSIZE);
RAND_seed(seed, SEEDSIZE);
int numMutexes = CRYPTO_num_locks();
sm_mutexes = new ref <vmime::utility::sync::criticalSection>[numMutexes];
int numMutexes = CRYPTO_num_locks();
sm_mutexes = new ref <vmime::utility::sync::criticalSection>[numMutexes];
for (int i = 0 ; i < numMutexes ; ++i)
sm_mutexes[i] = vmime::platform::getHandler()->createCriticalSection();
for (int i = 0 ; i < numMutexes ; ++i)
sm_mutexes[i] = vmime::platform::getHandler()->createCriticalSection();
CRYPTO_set_locking_callback(&OpenSSLInitializer::lock);
CRYPTO_set_id_callback(&OpenSSLInitializer::id);
}
CRYPTO_set_locking_callback(&OpenSSLInitializer::lock);
CRYPTO_set_id_callback(&OpenSSLInitializer::id);
}
// static
void OpenSSLInitializer::uninitialize()
{
ref <vmime::utility::sync::criticalSection> mutex = getMutex();
vmime::utility::sync::autoLock <vmime::utility::sync::criticalSection> lock(mutex);
EVP_cleanup();
ERR_free_strings();
if (--sm_initCount == 0)
{
EVP_cleanup();
ERR_free_strings();
CRYPTO_set_locking_callback(NULL);
CRYPTO_set_id_callback(NULL);
CRYPTO_set_locking_callback(NULL);
CRYPTO_set_id_callback(NULL);
delete [] sm_mutexes;
}
delete [] sm_mutexes;
}

View File

@ -41,6 +41,9 @@ namespace net {
namespace tls {
static OpenSSLInitializer::autoInitializer openSSLInitializer;
// static
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)
: m_sslctx(0), m_certVerifier(cv)
{
// Thread-safe OpenSSL initialization
static OpenSSLInitializer openSSLInitialization;
m_sslctx = SSL_CTX_new(SSLv23_client_method());
SSL_CTX_set_options(m_sslctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
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/TLSSession_OpenSSL.hpp"
#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp"
#include "vmime/platform.hpp"
@ -45,6 +46,9 @@ namespace net {
namespace tls {
static OpenSSLInitializer::autoInitializer openSSLInitializer;
// static
BIO_METHOD TLSSocket_OpenSSL::sm_customBIOMethod =
{

View File

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

View File

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