diff options
author | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-17 09:57:18 +0000 |
---|---|---|
committer | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-17 09:57:18 +0000 |
commit | 313834720d46a68071afe305975f8b70e9bc5782 (patch) | |
tree | 1d7b0dea339a8bcf3499cf29f27217cc985f35a1 | |
parent | 0d18ee21d5ddbfecf3951ac8fc0f5a30465e0ffe (diff) | |
download | chromium_src-313834720d46a68071afe305975f8b70e9bc5782.zip chromium_src-313834720d46a68071afe305975f8b70e9bc5782.tar.gz chromium_src-313834720d46a68071afe305975f8b70e9bc5782.tar.bz2 |
Refactor EnsureOpenSSLInit and openssl_util into base
This allows the base/crypto methods to call EnsureOpenSSLInit.
Also factors out the SSL_CTX and X509_STORE to be more closely associated with their consumers (ssl socket and X509Certificate resp.) rather than process wide globals.
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/4963002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66413 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/crypto/encryptor_openssl.cc | 5 | ||||
-rw-r--r-- | base/crypto/symmetric_key_openssl.cc | 2 | ||||
-rw-r--r-- | base/openssl_util.cc | 57 | ||||
-rw-r--r-- | base/openssl_util.h | 20 | ||||
-rw-r--r-- | base/scoped_vector.h | 1 | ||||
-rw-r--r-- | net/base/cert_test_util.cc | 22 | ||||
-rw-r--r-- | net/base/openssl_util.cc | 86 | ||||
-rw-r--r-- | net/base/openssl_util.h | 59 | ||||
-rw-r--r-- | net/base/x509_certificate.h | 7 | ||||
-rw-r--r-- | net/base/x509_certificate_openssl.cc | 36 | ||||
-rw-r--r-- | net/net.gyp | 4 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_openssl.cc | 34 |
12 files changed, 155 insertions, 178 deletions
diff --git a/base/crypto/encryptor_openssl.cc b/base/crypto/encryptor_openssl.cc index 6b08bd6..44ae932 100644 --- a/base/crypto/encryptor_openssl.cc +++ b/base/crypto/encryptor_openssl.cc @@ -44,7 +44,8 @@ class ScopedCipherCTX { } // namespace -Encryptor::Encryptor() { +Encryptor::Encryptor() + : key_(NULL) { } Encryptor::~Encryptor() { @@ -54,6 +55,7 @@ bool Encryptor::Init(SymmetricKey* key, Mode mode, const std::string& iv) { DCHECK(key); DCHECK_EQ(CBC, mode); + EnsureOpenSSLInit(); if (iv.size() != AES_BLOCK_SIZE) return false; @@ -77,6 +79,7 @@ bool Encryptor::Decrypt(const std::string& ciphertext, std::string* plaintext) { bool Encryptor::Crypt(bool do_encrypt, const std::string& input, std::string* output) { + DCHECK(key_); // Must call Init() before En/De-crypt. // Work on the result in a local variable, and then only transfer it to // |output| on success to ensure no partial data is returned. std::string result; diff --git a/base/crypto/symmetric_key_openssl.cc b/base/crypto/symmetric_key_openssl.cc index e469135..9f0ad38 100644 --- a/base/crypto/symmetric_key_openssl.cc +++ b/base/crypto/symmetric_key_openssl.cc @@ -30,6 +30,7 @@ SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm, if (key_size_in_bits == 0) return NULL; + EnsureOpenSSLInit(); scoped_ptr<SymmetricKey> key(new SymmetricKey); uint8* key_data = reinterpret_cast<uint8*>(WriteInto(&key->key_, key_size_in_bytes + 1)); @@ -53,6 +54,7 @@ SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm, int key_size_in_bytes = key_size_in_bits / 8; DCHECK_EQ(static_cast<int>(key_size_in_bits), key_size_in_bytes * 8); + EnsureOpenSSLInit(); scoped_ptr<SymmetricKey> key(new SymmetricKey); uint8* key_data = reinterpret_cast<uint8*>(WriteInto(&key->key_, key_size_in_bytes + 1)); diff --git a/base/openssl_util.cc b/base/openssl_util.cc index 82da868..894c710 100644 --- a/base/openssl_util.cc +++ b/base/openssl_util.cc @@ -5,11 +5,68 @@ #include "base/openssl_util.h" #include <openssl/err.h> +#include <openssl/ssl.h> +#include "base/lock.h" #include "base/logging.h" +#include "base/scoped_vector.h" +#include "base/singleton.h" namespace base { +namespace { + +unsigned long CurrentThreadId() { + return static_cast<unsigned long>(PlatformThread::CurrentId()); +} + +// Singleton for initializing and cleaning up the OpenSSL library. +class OpenSSLInitSingleton { + private: + friend struct DefaultSingletonTraits<OpenSSLInitSingleton>; + OpenSSLInitSingleton() { + SSL_load_error_strings(); + SSL_library_init(); + OpenSSL_add_all_algorithms(); + int num_locks = CRYPTO_num_locks(); + locks_.reserve(num_locks); + for (int i = 0; i < num_locks; ++i) + locks_.push_back(new Lock()); + CRYPTO_set_locking_callback(LockingCallback); + CRYPTO_set_id_callback(CurrentThreadId); + } + + ~OpenSSLInitSingleton() { + CRYPTO_set_locking_callback(NULL); + EVP_cleanup(); + ERR_free_strings(); + } + + static void LockingCallback(int mode, int n, const char* file, int line) { + Singleton<OpenSSLInitSingleton>::get()->OnLockingCallback(mode, n, file, + line); + } + + void OnLockingCallback(int mode, int n, const char* file, int line) { + CHECK_LT(static_cast<size_t>(n), locks_.size()); + if (mode & CRYPTO_LOCK) + locks_[n]->Acquire(); + else + locks_[n]->Release(); + } + + // These locks are used and managed by OpenSSL via LockingCallback(). + ScopedVector<Lock> locks_; + + DISALLOW_COPY_AND_ASSIGN(OpenSSLInitSingleton); +}; + +} // namespace + +void EnsureOpenSSLInit() { + (void)Singleton<OpenSSLInitSingleton>::get(); +} + void ClearOpenSSLERRStack() { if (logging::DEBUG_MODE && VLOG_IS_ON(1)) { int error_num = ERR_get_error(); diff --git a/base/openssl_util.h b/base/openssl_util.h index ed4101f..1d290ae 100644 --- a/base/openssl_util.h +++ b/base/openssl_util.h @@ -11,6 +11,20 @@ namespace base { +// A helper class that takes care of destroying OpenSSL objects when it goes out +// of scope. +template <typename T, void (*destructor)(T*)> +class ScopedOpenSSL { + public: + explicit ScopedOpenSSL(T* ptr_) : ptr_(ptr_) { } + ~ScopedOpenSSL() { if (ptr_) (*destructor)(ptr_); } + + T* get() const { return ptr_; } + + private: + T* ptr_; +}; + // Provides a buffer of at least MIN_SIZE bytes, for use when calling OpenSSL's // SHA256, HMAC, etc functions, adapting the buffer sizing rules to meet those // of the our base wrapper APIs. @@ -51,6 +65,12 @@ class ScopedOpenSSLSafeSizeBuffer { DISALLOW_COPY_AND_ASSIGN(ScopedOpenSSLSafeSizeBuffer); }; +// Initialize OpenSSL if it isn't already initialized. This must be called +// before any other OpenSSL functions. +// This function is thread-safe, and OpenSSL will only ever be initialized once. +// OpenSSL will be properly shut down on program exit. +void EnsureOpenSSLInit(); + // Drains the OpenSSL ERR_get_error stack. On a debug build the error codes // are send to VLOG(1), on a release build they are disregarded. void ClearOpenSSLERRStack(); diff --git a/base/scoped_vector.h b/base/scoped_vector.h index ec152c9..9d372f3 100644 --- a/base/scoped_vector.h +++ b/base/scoped_vector.h @@ -54,6 +54,7 @@ class ScopedVector { } void reset() { STLDeleteElements(&v); } + void reserve(size_t capacity) { v.reserve(capacity); } void resize(size_t new_size) { v.resize(new_size); } // Lets the ScopedVector take ownership of |x|. diff --git a/net/base/cert_test_util.cc b/net/base/cert_test_util.cc index 1042d50..d5c678e 100644 --- a/net/base/cert_test_util.cc +++ b/net/base/cert_test_util.cc @@ -8,8 +8,9 @@ #if defined(USE_OPENSSL) #include <openssl/err.h> +#include <openssl/ssl.h> #include <openssl/x509v3.h> -#include "net/base/openssl_util.h" +#include "base/openssl_util.h" #elif defined(USE_NSS) #include <cert.h> #include "base/nss_util.h" @@ -27,15 +28,11 @@ namespace net { #if defined(USE_OPENSSL) X509Certificate* AddTemporaryRootCertToStore(X509* x509_cert) { - OpenSSLInitSingleton* openssl_init = GetOpenSSLInitSingleton(); - - if (!X509_STORE_add_cert(openssl_init->x509_store(), x509_cert)) { + if (!X509_STORE_add_cert(X509Certificate::cert_store(), x509_cert)) { unsigned long error_code = ERR_get_error(); if (ERR_GET_LIB(error_code) != ERR_LIB_X509 || ERR_GET_REASON(error_code) != X509_R_CERT_ALREADY_IN_HASH_TABLE) { - do { - LOG(ERROR) << "X509_STORE_add_cert error: " << error_code; - } while ((error_code = ERR_get_error()) != 0); + base::ClearOpenSSLERRStack(); return NULL; } } @@ -45,7 +42,7 @@ X509Certificate* AddTemporaryRootCertToStore(X509* x509_cert) { } X509Certificate* LoadTemporaryRootCert(const FilePath& filename) { - EnsureOpenSSLInit(); + base::EnsureOpenSSLInit(); std::string rawcert; if (!file_util::ReadFileToString(filename, &rawcert)) { @@ -53,7 +50,7 @@ X509Certificate* LoadTemporaryRootCert(const FilePath& filename) { return NULL; } - ScopedSSL<BIO, BIO_free_all> cert_bio( + base::ScopedOpenSSL<BIO, BIO_free_all> cert_bio( BIO_new_mem_buf(const_cast<char*>(rawcert.c_str()), rawcert.length())); if (!cert_bio.get()) { @@ -61,8 +58,8 @@ X509Certificate* LoadTemporaryRootCert(const FilePath& filename) { return NULL; } - ScopedSSL<X509, X509_free> pem_cert(PEM_read_bio_X509(cert_bio.get(), - NULL, NULL, NULL)); + base::ScopedOpenSSL<X509, X509_free> pem_cert(PEM_read_bio_X509( + cert_bio.get(), NULL, NULL, NULL)); if (pem_cert.get()) return AddTemporaryRootCertToStore(pem_cert.get()); @@ -70,7 +67,8 @@ X509Certificate* LoadTemporaryRootCert(const FilePath& filename) { const unsigned char* der_data = reinterpret_cast<const unsigned char*>(rawcert.c_str()); int der_length = rawcert.length(); - ScopedSSL<X509, X509_free> der_cert(d2i_X509(NULL, &der_data, der_length)); + base::ScopedOpenSSL<X509, X509_free> der_cert(d2i_X509( + NULL, &der_data, der_length)); if (der_cert.get()) return AddTemporaryRootCertToStore(der_cert.get()); diff --git a/net/base/openssl_util.cc b/net/base/openssl_util.cc deleted file mode 100644 index 51797ac..0000000 --- a/net/base/openssl_util.cc +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/base/openssl_util.h" - -#include <openssl/err.h> - -#include "base/logging.h" -#include "base/platform_thread.h" - -namespace net { - -namespace { - -// We do certificate verification after handshake, so we disable the default -// by registering a no-op verify function. -int NoOpVerifyCallback(X509_STORE_CTX*, void *) { - DVLOG(3) << "skipping cert verify"; - return 1; -} - -unsigned long CurrentThreadId() { - return static_cast<unsigned long>(PlatformThread::CurrentId()); -} - -SSL_CTX* CreateSSL_CTX() { - SSL_load_error_strings(); - SSL_library_init(); - OpenSSL_add_all_algorithms(); - return SSL_CTX_new(SSLv23_client_method()); -} - -} // namespace - -OpenSSLInitSingleton::OpenSSLInitSingleton() - : ssl_ctx_(CreateSSL_CTX()), - store_(X509_STORE_new()) { - CHECK(ssl_ctx_.get()); - CHECK(store_.get()); - - SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), NoOpVerifyCallback, NULL); - X509_STORE_set_default_paths(store_.get()); - // TODO(bulach): Enable CRL (see X509_STORE_set_flags(X509_V_FLAG_CRL_CHECK)). - int num_locks = CRYPTO_num_locks(); - for (int i = 0; i < num_locks; ++i) - locks_.push_back(new Lock()); - CRYPTO_set_locking_callback(LockingCallback); - CRYPTO_set_id_callback(CurrentThreadId); -} - -OpenSSLInitSingleton::~OpenSSLInitSingleton() { - CRYPTO_set_locking_callback(NULL); - EVP_cleanup(); - ERR_free_strings(); -} - -OpenSSLInitSingleton* GetOpenSSLInitSingleton() { - return Singleton<OpenSSLInitSingleton>::get(); -} - -void EnsureOpenSSLInit() { - Singleton<OpenSSLInitSingleton>::get(); -} - -// static -void OpenSSLInitSingleton::LockingCallback(int mode, - int n, - const char* file, - int line) { - GetOpenSSLInitSingleton()->OnLockingCallback(mode, n, file, line); -} - -void OpenSSLInitSingleton::OnLockingCallback(int mode, - int n, - const char* file, - int line) { - CHECK_LT(static_cast<size_t>(n), locks_.size()); - if (mode & CRYPTO_LOCK) - locks_[n]->Acquire(); - else - locks_[n]->Release(); -} - -} // namespace net - diff --git a/net/base/openssl_util.h b/net/base/openssl_util.h deleted file mode 100644 index d4603c6..0000000 --- a/net/base/openssl_util.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <openssl/ssl.h> - -#include "base/lock.h" -#include "base/scoped_vector.h" -#include "base/singleton.h" - -namespace net { - -// A helper class that takes care of destroying OpenSSL objects when it goes out -// of scope. -template <typename T, void (*destructor)(T*)> -class ScopedSSL { - public: - explicit ScopedSSL(T* ptr_) : ptr_(ptr_) { } - ~ScopedSSL() { if (ptr_) (*destructor)(ptr_); } - - T* get() const { return ptr_; } - - private: - T* ptr_; -}; - -// Singleton for initializing / cleaning up OpenSSL and holding a X509 store. -// Access it via GetOpenSSLInitSingleton(). -class OpenSSLInitSingleton { - public: - SSL_CTX* ssl_ctx() const { return ssl_ctx_.get(); } - X509_STORE* x509_store() const { return store_.get(); } - - private: - friend struct DefaultSingletonTraits<OpenSSLInitSingleton>; - OpenSSLInitSingleton(); - ~OpenSSLInitSingleton(); - - static void LockingCallback(int mode, int n, const char* file, int line); - void OnLockingCallback(int mode, int n, const char* file, int line); - - ScopedSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_; - ScopedSSL<X509_STORE, X509_STORE_free> store_; - // These locks are used and managed by OpenSSL via LockingCallback(). - ScopedVector<Lock> locks_; - - DISALLOW_COPY_AND_ASSIGN(OpenSSLInitSingleton); -}; - -OpenSSLInitSingleton* GetOpenSSLInitSingleton(); - -// Initialize OpenSSL if it isn't already initialized. This must be called -// before any other OpenSSL functions (except GetOpenSSLInitSingleton above). -// This function is thread-safe, and OpenSSL will only ever be initialized once. -// OpenSSL will be properly shut down on program exit. -void EnsureOpenSSLInit(); - -} // namespace net - diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h index 2a7e6d7..1866a17 100644 --- a/net/base/x509_certificate.h +++ b/net/base/x509_certificate.h @@ -26,6 +26,7 @@ #elif defined(USE_OPENSSL) // Forward declaration; real one in <x509.h> struct x509_st; +typedef struct x509_store_st X509_STORE; #elif defined(USE_NSS) // Forward declaration; real one in <cert.h> struct CERTCertificateStr; @@ -234,6 +235,12 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { static HCERTSTORE cert_store(); #endif +#if defined(USE_OPENSSL) + // Returns a handle to a global, in-memory certificate store. We + // use it for test code, e.g. importing the test server's certificate. + static X509_STORE* cert_store(); +#endif + // Verifies the certificate against the given hostname. Returns OK if // successful or an error code upon failure. // diff --git a/net/base/x509_certificate_openssl.cc b/net/base/x509_certificate_openssl.cc index 512de14..2be38dd 100644 --- a/net/base/x509_certificate_openssl.cc +++ b/net/base/x509_certificate_openssl.cc @@ -13,13 +13,13 @@ #include <openssl/ssl.h> #include <openssl/x509v3.h> +#include "base/openssl_util.h" #include "base/pickle.h" #include "base/singleton.h" #include "base/string_number_conversions.h" #include "net/base/cert_status_flags.h" #include "net/base/cert_verify_result.h" #include "net/base/net_errors.h" -#include "net/base/openssl_util.h" #include "net/base/x509_openssl_util.h" namespace net { @@ -31,8 +31,9 @@ namespace { void CreateOSCertHandlesFromPKCS7Bytes( const char* data, int length, X509Certificate::OSCertHandles* handles) { + base::EnsureOpenSSLInit(); const unsigned char* der_data = reinterpret_cast<const unsigned char*>(data); - ScopedSSL<PKCS7, PKCS7_free> pkcs7_cert( + base::ScopedOpenSSL<PKCS7, PKCS7_free> pkcs7_cert( d2i_PKCS7(NULL, &der_data, length)); if (!pkcs7_cert.get()) return; @@ -98,7 +99,7 @@ void ParseSubjectAltNames(X509Certificate::OSCertHandle cert, if (!alt_name_ext) return; - ScopedSSL<GENERAL_NAMES, GENERAL_NAMES_free> alt_names( + base::ScopedOpenSSL<GENERAL_NAMES, GENERAL_NAMES_free> alt_names( reinterpret_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(alt_name_ext))); if (!alt_names.get()) return; @@ -206,16 +207,22 @@ void DERCache_free(void* parent, void* ptr, CRYPTO_EX_DATA* ad, int idx, class X509InitSingleton { public: int der_cache_ex_index() const { return der_cache_ex_index_; } + X509_STORE* store() const { return store_.get(); } private: friend struct DefaultSingletonTraits<X509InitSingleton>; - X509InitSingleton() { - der_cache_ex_index_ = X509_get_ex_new_index(0, 0, 0, 0, DERCache_free); + X509InitSingleton() + : der_cache_ex_index_((base::EnsureOpenSSLInit(), + X509_get_ex_new_index(0, 0, 0, 0, + DERCache_free))), + store_(X509_STORE_new()) { DCHECK_NE(der_cache_ex_index_, -1); + X509_STORE_set_default_paths(store_.get()); + // TODO(joth): Enable CRL (see X509_STORE_set_flags(X509_V_FLAG_CRL_CHECK)). } - ~X509InitSingleton() {} int der_cache_ex_index_; + base::ScopedOpenSSL<X509_STORE, X509_STORE_free> store_; DISALLOW_COPY_AND_ASSIGN(X509InitSingleton); }; @@ -290,6 +297,7 @@ void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { } void X509Certificate::Initialize() { + base::EnsureOpenSSLInit(); fingerprint_ = CalculateFingerprint(cert_handle_); ParsePrincipal(cert_handle_, X509_get_subject_name(cert_handle_), &subject_); ParsePrincipal(cert_handle_, X509_get_issuer_name(cert_handle_), &issuer_); @@ -311,6 +319,7 @@ X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( const char* data, int length) { if (length < 0) return NULL; + base::EnsureOpenSSLInit(); const unsigned char* d2i_data = reinterpret_cast<const unsigned char*>(data); // Don't cache this data via SetDERCache as this wire format may be not be @@ -346,6 +355,7 @@ X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( return results; } +// static X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, void** pickle_iter) { const char* data; @@ -374,6 +384,11 @@ void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { dns_names->push_back(subject_.common_name); } +// static +X509_STORE* X509Certificate::cert_store() { + return Singleton<X509InitSingleton>::get()->store(); +} + int X509Certificate::Verify(const std::string& hostname, int flags, CertVerifyResult* verify_result) const { @@ -387,9 +402,11 @@ int X509Certificate::Verify(const std::string& hostname, if (!x509_openssl_util::VerifyHostname(hostname, cert_names)) verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; - ScopedSSL<X509_STORE_CTX, X509_STORE_CTX_free> ctx(X509_STORE_CTX_new()); + base::ScopedOpenSSL<X509_STORE_CTX, X509_STORE_CTX_free> ctx( + X509_STORE_CTX_new()); - ScopedSSL<STACK_OF(X509), sk_X509_free_fn> intermediates(sk_X509_new_null()); + base::ScopedOpenSSL<STACK_OF(X509), sk_X509_free_fn> intermediates( + sk_X509_new_null()); if (!intermediates.get()) return ERR_OUT_OF_MEMORY; @@ -398,8 +415,7 @@ int X509Certificate::Verify(const std::string& hostname, if (!sk_X509_push(intermediates.get(), *it)) return ERR_OUT_OF_MEMORY; } - int rv = X509_STORE_CTX_init(ctx.get(), - GetOpenSSLInitSingleton()->x509_store(), + int rv = X509_STORE_CTX_init(ctx.get(), cert_store(), cert_handle_, intermediates.get()); CHECK_EQ(1, rv); diff --git a/net/net.gyp b/net/net.gyp index 1d73dd1..b9e3776 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -142,8 +142,6 @@ 'base/network_config_watcher_mac.h', 'base/nss_memio.c', 'base/nss_memio.h', - 'base/openssl_util.cc', - 'base/openssl_util.h', 'base/pem_tokenizer.cc', 'base/pem_tokenizer.h', 'base/platform_mime_util.h', @@ -287,8 +285,6 @@ 'sources!': [ 'base/cert_database_openssl.cc', 'base/keygen_handler_openssl.cc', - 'base/openssl_util.cc', - 'base/openssl_util.h', 'base/x509_certificate_openssl.cc', 'base/x509_openssl_util.cc', 'base/x509_openssl_util.h', diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc index 3f01db2..62f3dbb 100644 --- a/net/socket/ssl_client_socket_openssl.cc +++ b/net/socket/ssl_client_socket_openssl.cc @@ -10,10 +10,10 @@ #include <openssl/ssl.h> #include <openssl/err.h> -#include "net/base/cert_verifier.h" #include "base/metrics/histogram.h" +#include "base/openssl_util.h" +#include "net/base/cert_verifier.h" #include "net/base/net_errors.h" -#include "net/base/openssl_util.h" #include "net/base/ssl_connection_status_flags.h" #include "net/base/ssl_info.h" @@ -58,6 +58,29 @@ int MapOpenSSLError(int err) { } } +// We do certificate verification after handshake, so we disable the default +// by registering a no-op verify function. +int NoOpVerifyCallback(X509_STORE_CTX*, void *) { + DVLOG(3) << "skipping cert verify"; + return 1; +} + +struct SSLContextSingletonTraits : public DefaultSingletonTraits<SSL_CTX> { + static SSL_CTX* New() { + base::EnsureOpenSSLInit(); + SSL_CTX* self = SSL_CTX_new(SSLv23_client_method()); + SSL_CTX_set_cert_verify_callback(self, NoOpVerifyCallback, NULL); + return self; + } + static void Delete(SSL_CTX* self) { + SSL_CTX_free(self); + } +}; + +SSL_CTX* GetSSLContext() { + return Singleton<SSL_CTX, SSLContextSingletonTraits>::get(); +} + } // namespace SSLClientSocketOpenSSL::SSLClientSocketOpenSSL( @@ -93,7 +116,7 @@ bool SSLClientSocketOpenSSL::Init() { DCHECK(!ssl_); DCHECK(!transport_bio_); - ssl_ = SSL_new(GetOpenSSLInitSingleton()->ssl_ctx()); + ssl_ = SSL_new(GetSSLContext()); if (!ssl_) { MaybeLogSSLError(); return false; @@ -394,8 +417,7 @@ void SSLClientSocketOpenSSL::InvalidateSessionIfBadCertificate() { // see SSL_CTX_set_session_cache_mode(SSL_SESS_CACHE_CLIENT). SSL_SESSION* session = SSL_get_session(ssl_); LOG_IF(ERROR, session) << "Connection has a session?? " << session; - int rv = SSL_CTX_remove_session(GetOpenSSLInitSingleton()->ssl_ctx(), - session); + int rv = SSL_CTX_remove_session(GetSSLContext(), session); LOG_IF(ERROR, rv) << "Session was cached?? " << rv; } } @@ -404,7 +426,7 @@ X509Certificate* SSLClientSocketOpenSSL::UpdateServerCert() { if (server_cert_) return server_cert_; - ScopedSSL<X509, X509_free> cert(SSL_get_peer_certificate(ssl_)); + base::ScopedOpenSSL<X509, X509_free> cert(SSL_get_peer_certificate(ssl_)); if (!cert.get()) { LOG(WARNING) << "SSL_get_peer_certificate returned NULL"; return NULL; |