summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-08 15:53:52 +0000
committerjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-08 15:53:52 +0000
commit2907525c5676868aa09104f84575ea27fca156cf (patch)
tree1fb7b6089f771c6913daf6d6f5438c7f9080e65d /net
parent2b0b0a4d90385d735d182352ab12de76ff4ca94f (diff)
downloadchromium_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.cc15
-rw-r--r--net/base/openssl_util.cc33
-rw-r--r--net/base/openssl_util.h4
-rw-r--r--net/socket/ssl_client_socket_openssl.cc129
-rw-r--r--net/socket/ssl_client_socket_openssl.h5
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);