diff options
author | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-08 15:53:52 +0000 |
---|---|---|
committer | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-08 15:53:52 +0000 |
commit | 2907525c5676868aa09104f84575ea27fca156cf (patch) | |
tree | 1fb7b6089f771c6913daf6d6f5438c7f9080e65d /net | |
parent | 2b0b0a4d90385d735d182352ab12de76ff4ca94f (diff) | |
download | chromium_src-2907525c5676868aa09104f84575ea27fca156cf.zip chromium_src-2907525c5676868aa09104f84575ea27fca156cf.tar.gz chromium_src-2907525c5676868aa09104f84575ea27fca156cf.tar.bz2 |
Connect up OpenSSL socket to use the OpenSSL X509Certificate.
Also adds SSL_CTX to the OpenSSLInitSingleton to make initialization thread-safe.
Note this depends on http://codereview.chromium.org/3529008
BUG=None
TEST=build with use_openssl=1, open some https pages
Review URL: http://codereview.chromium.org/3591015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61963 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/cert_database_openssl.cc | 15 | ||||
-rw-r--r-- | net/base/openssl_util.cc | 33 | ||||
-rw-r--r-- | net/base/openssl_util.h | 4 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_openssl.cc | 129 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_openssl.h | 5 |
5 files changed, 83 insertions, 103 deletions
diff --git a/net/base/cert_database_openssl.cc b/net/base/cert_database_openssl.cc index b56d8ba..73a67c1 100644 --- a/net/base/cert_database_openssl.cc +++ b/net/base/cert_database_openssl.cc @@ -49,4 +49,19 @@ bool CertDatabase::DeleteCertAndKey(const X509Certificate* cert) { return false; } +unsigned int CertDatabase::GetCertTrust(const X509Certificate* cert, + CertType type) const { + // TODO(bulach): implement me. + // NOTE: This method is currently only declared for USE_NSS builds. + return 0; +} + +bool CertDatabase::SetCertTrust(const X509Certificate* cert, + CertType type, + unsigned int trust_bits) { + // TODO(bulach): implement me. + // NOTE: This method is currently only declared for USE_NSS builds. + return false; +} + } // namespace net diff --git a/net/base/openssl_util.cc b/net/base/openssl_util.cc index 54a3df4..fcdc3a1 100644 --- a/net/base/openssl_util.cc +++ b/net/base/openssl_util.cc @@ -5,27 +5,48 @@ #include "net/base/openssl_util.h" #include <openssl/err.h> -#include <openssl/x509v3.h> #include "base/logging.h" +#include "base/platform_thread.h" namespace net { -X509_STORE* OpenSSLInitSingleton::x509_store() const { - return store_.get(); +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; } -OpenSSLInitSingleton::OpenSSLInitSingleton() - : store_(X509_STORE_new()) { - CHECK(store_.get()); +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() { diff --git a/net/base/openssl_util.h b/net/base/openssl_util.h index 8015917..4218a89 100644 --- a/net/base/openssl_util.h +++ b/net/base/openssl_util.h @@ -28,7 +28,8 @@ class ScopedSSL { // Access it via EnsureOpenSSLInit(). class OpenSSLInitSingleton { public: - X509_STORE* x509_store() const; + SSL_CTX* ssl_ctx() const { return ssl_ctx_.get(); } + X509_STORE* x509_store() const { return store_.get(); } private: friend struct DefaultSingletonTraits<OpenSSLInitSingleton>; @@ -38,6 +39,7 @@ class 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_; diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc index 5384ba4..4ff1b48 100644 --- a/net/socket/ssl_client_socket_openssl.cc +++ b/net/socket/ssl_client_socket_openssl.cc @@ -13,9 +13,9 @@ #include "net/base/cert_verifier.h" #include "base/histogram.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" -#include "net/base/test_certificate_data.h" // TODO(joth): Remove!! namespace net { @@ -31,8 +31,6 @@ namespace { #endif const size_t kMaxRecvBufferSize = 4096; -static SSL_CTX* g_ctx = NULL; -static int g_app_data_index = -1; void MaybeLogSSLError() { int error_num; @@ -60,22 +58,6 @@ int MapOpenSSLError(int err) { } } -// Registered with |g_ctx| as global verify callback handler; we unpack the -// SSLClientSocketOpenSSL instance associated with this callback and delegate -// the handling to it. -int VerifyCallback(int preverify_ok, X509_STORE_CTX* x509_ctx) { - DCHECK_GE(g_app_data_index, 0); - // Retrieve the pointer to the SSL of the connection currently treated - // and from there, the application specific data stored in the SSL object. - SSL* ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data( - x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx())); - DCHECK(ssl); - SSLClientSocketOpenSSL* self = static_cast<SSLClientSocketOpenSSL*>( - SSL_get_ex_data(ssl, g_app_data_index)); - DCHECK(self); - return self->SSLVerifyCallback(preverify_ok, ssl, x509_ctx); -} - } // namespace SSLClientSocketOpenSSL::SSLClientSocketOpenSSL( @@ -107,54 +89,16 @@ SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() { Disconnect(); } -// TODO(joth): This method needs to be thread-safe. -bool SSLClientSocketOpenSSL::InitOpenSSL() { - if (g_ctx) - return true; - - SSL_load_error_strings(); - MaybeLogSSLError(); - SSL_library_init(); - MaybeLogSSLError(); - - // Allow all versions here; we disable the unneeded ones according to the - // SSL config options in Init(). - g_ctx = SSL_CTX_new(SSLv23_client_method()); - - if (!g_ctx) { - MaybeLogSSLError(); - return false; - } - g_app_data_index = SSL_get_ex_new_index(__LINE__, g_ctx, NULL, NULL, NULL); - DCHECK_GE(g_app_data_index, 0); - - SSL_CTX_set_verify(g_ctx, SSL_VERIFY_PEER, VerifyCallback); - - // For now, just let OpenSSL load CA certs directly from the filesystem. - if (!SSL_CTX_set_default_verify_paths(g_ctx)) { - MaybeLogSSLError(); - return false; - } - - return true; -} - bool SSLClientSocketOpenSSL::Init() { - DCHECK(g_ctx); DCHECK(!ssl_); DCHECK(!transport_bio_); - ssl_ = SSL_new(g_ctx); + ssl_ = SSL_new(GetOpenSSLInitSingleton()->ssl_ctx()); if (!ssl_) { MaybeLogSSLError(); return false; } - if (!SSL_set_ex_data(ssl_, g_app_data_index, this)) { - MaybeLogSSLError(); - return false; - } - if (!SSL_set_tlsext_host_name(ssl_, hostname_.c_str())) { MaybeLogSSLError(); return false; @@ -195,17 +139,6 @@ bool SSLClientSocketOpenSSL::Init() { return true; } -int SSLClientSocketOpenSSL::SSLVerifyCallback(int preverify_ok, - SSL* ssl, - X509_STORE_CTX* x509_ctx) { - DCHECK_EQ(ssl_, ssl); - int depth = X509_STORE_CTX_get_error_depth(x509_ctx); - DVLOG(preverify_ok ? 3 : 1) << "SSLVerifyCallback " << preverify_ok - << " depth " << depth; - MaybeLogSSLError(); - return preverify_ok; -} - // SSLClientSocket methods void SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) { @@ -213,16 +146,27 @@ void SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) { if (!server_cert_) return; - // Chrome DCHECKs that https pages provide a valid cert. For now (whilst in - // early dev) we just create a spoof cert. - // TODO(joth): implement X509Certificate for OpenSSL and remove this hack. - LOG(WARNING) << "Filling in certificate with bogus content"; ssl_info->cert = server_cert_; ssl_info->cert_status = server_cert_verify_result_.cert_status; - ssl_info->security_bits = 56; - ssl_info->connection_status = - ((TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA) & - SSL_CONNECTION_CIPHERSUITE_MASK) << SSL_CONNECTION_CIPHERSUITE_SHIFT; + + const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl_); + CHECK(cipher); + ssl_info->security_bits = SSL_CIPHER_get_bits(cipher, NULL); + ssl_info->connection_status |= (cipher->id & SSL_CONNECTION_CIPHERSUITE_MASK) + << SSL_CONNECTION_CIPHERSUITE_SHIFT; + DVLOG(2) << SSL_CIPHER_get_name(cipher) << ": cipher ID " << cipher->id + << " security bits " << ssl_info->security_bits; + + // Experimenting suggests the compression object is optional, whereas the + // cipher (above) is always present. + const COMP_METHOD* compression = SSL_get_current_compression(ssl_); + if (compression) { + ssl_info->connection_status |= + (compression->type & SSL_CONNECTION_COMPRESSION_MASK) + << SSL_CONNECTION_COMPRESSION_SHIFT; + DVLOG(2) << SSL_COMP_get_name(compression) + << ": compression ID " << compression->type; + } bool peer_supports_renego_ext = !!SSL_get_secure_renegotiation_support(ssl_); if (!peer_supports_renego_ext) @@ -270,11 +214,6 @@ void SSLClientSocketOpenSSL::DoWriteCallback(int rv) { int SSLClientSocketOpenSSL::Connect(CompletionCallback* callback) { net_log_.BeginEvent(NetLog::TYPE_SSL_CONNECT, NULL); - if (!InitOpenSSL()) { - net_log_.EndEvent(NetLog::TYPE_SSL_CONNECT, NULL); - return ERR_UNEXPECTED; - } - // Set up new ssl object. if (!Init()) { net_log_.EndEvent(NetLog::TYPE_SSL_CONNECT, NULL); @@ -420,6 +359,9 @@ int SSLClientSocketOpenSSL::DoVerifyCertComplete(int result) { if (result == OK) { // TODO(joth): Work out if we need to remember the intermediate CA certs // when the server sends them to us, and do so here. + } else { + DVLOG(1) << "DoVerifyCertComplete error " << ErrorToString(result) + << " (" << result << ")"; } // If we have been explicitly told to accept this certificate, override the @@ -452,7 +394,8 @@ 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(g_ctx, session); + int rv = SSL_CTX_remove_session(GetOpenSSLInitSingleton()->ssl_ctx(), + session); LOG_IF(ERROR, rv) << "Session was cached?? " << rv; } } @@ -461,19 +404,23 @@ X509Certificate* SSLClientSocketOpenSSL::UpdateServerCert() { if (server_cert_) return server_cert_; - X509* cert = SSL_get_peer_certificate(ssl_); - if (cert == NULL) { + ScopedSSL<X509, X509_free> cert(SSL_get_peer_certificate(ssl_)); + if (!cert.get()) { LOG(WARNING) << "SSL_get_peer_certificate returned NULL"; return NULL; } - // TODO(joth): Get |server_cert_| from |cert|. - server_cert_ = X509Certificate::CreateFromBytes( - reinterpret_cast<const char*>(google_der), sizeof(google_der)); - X509_free(cert); + // Unlike SSL_get_peer_certificate, SSL_get_peer_cert_chain does not + // increment the reference so sk_X509_free does not need to be called. + STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl_); + X509Certificate::OSCertHandles intermediates; + if (chain) { + for (int i = 0; i < sk_X509_num(chain); ++i) + intermediates.push_back(sk_X509_value(chain, i)); + } + server_cert_ = X509Certificate::CreateFromHandle( + cert.get(), X509Certificate::SOURCE_FROM_NETWORK, intermediates); DCHECK(server_cert_); - // Silence compiler about unused vars. - (void)google_der; (void)webkit_der; (void)thawte_der; (void)paypal_null_der; return server_cert_; } diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h index ce450aef..20f321e 100644 --- a/net/socket/ssl_client_socket_openssl.h +++ b/net/socket/ssl_client_socket_openssl.h @@ -16,7 +16,6 @@ typedef struct bio_st BIO; typedef struct ssl_st SSL; -typedef struct x509_store_ctx_st X509_STORE_CTX; namespace net { @@ -37,9 +36,6 @@ class SSLClientSocketOpenSSL : public SSLClientSocket { const SSLConfig& ssl_config); ~SSLClientSocketOpenSSL(); - // Called back from OpenSSL during cert verification (see SSL_CTX_set_verify). - int SSLVerifyCallback(int preverify_ok, SSL* ssl, X509_STORE_CTX* ctx); - // SSLClientSocket methods: virtual void GetSSLInfo(SSLInfo* ssl_info); virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info); @@ -63,7 +59,6 @@ class SSLClientSocketOpenSSL : public SSLClientSocket { virtual bool SetSendBufferSize(int32 size); private: - bool InitOpenSSL(); bool Init(); void DoReadCallback(int result); void DoWriteCallback(int result); |