diff options
-rw-r--r-- | net/socket/ssl_client_socket_openssl.cc | 39 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_openssl.h | 7 |
2 files changed, 38 insertions, 8 deletions
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc index b253dfe..ee07f19 100644 --- a/net/socket/ssl_client_socket_openssl.cc +++ b/net/socket/ssl_client_socket_openssl.cc @@ -183,6 +183,10 @@ int MapOpenSSLErrorSSL() { case SSL_R_TLSV1_ALERT_RECORD_OVERFLOW: case SSL_R_TLSV1_ALERT_USER_CANCELLED: return ERR_SSL_PROTOCOL_ERROR; + case SSL_R_CERTIFICATE_VERIFY_FAILED: + // The only way that the certificate verify callback can fail is if + // the leaf certificate changed during a renegotiation. + return ERR_SSL_SERVER_CERT_CHANGED; default: LOG(WARNING) << "Unmapped error reason: " << ERR_GET_REASON(error_code); return ERR_FAILED; @@ -212,13 +216,6 @@ int MapOpenSSLError(int err, const crypto::OpenSSLErrStackTracer& tracer) { } } -// 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; -} - // Utility to construct the appropriate set & clear masks for use the OpenSSL // options and mode configuration functions. (SSL_set_options etc) struct SslSetClearMask { @@ -270,9 +267,10 @@ class SSLClientSocketOpenSSL::SSLContext { DCHECK_NE(ssl_socket_data_index_, -1); ssl_ctx_.reset(SSL_CTX_new(SSLv23_client_method())); session_cache_.Reset(ssl_ctx_.get(), kDefaultSessionCacheConfig); - SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), NoOpVerifyCallback, NULL); + SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), CertVerifyCallback, NULL); SSL_CTX_set_client_cert_cb(ssl_ctx_.get(), ClientCertCallback); SSL_CTX_set_channel_id_cb(ssl_ctx_.get(), ChannelIDCallback); + SSL_CTX_set_verify(ssl_ctx_.get(), SSL_VERIFY_PEER, NULL); #if defined(OPENSSL_NPN_NEGOTIATED) // TODO(kristianm): Only select this if ssl_config_.next_proto is not empty. // It would be better if the callback were not a global setting, @@ -302,6 +300,15 @@ class SSLClientSocketOpenSSL::SSLContext { socket->ChannelIDRequestCallback(ssl, pkey); } + static int CertVerifyCallback(X509_STORE_CTX *store_ctx, void *arg) { + SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data( + store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx())); + SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl); + CHECK(socket); + + return socket->CertVerifyCallback(store_ctx); + } + static int SelectNextProtoCallback(SSL* ssl, unsigned char** out, unsigned char* outlen, const unsigned char* in, @@ -1372,6 +1379,22 @@ void SSLClientSocketOpenSSL::ChannelIDRequestCallback(SSL* ssl, *pkey = EVP_PKEY_dup(ec_private_key->key()); } +int SSLClientSocketOpenSSL::CertVerifyCallback(X509_STORE_CTX* store_ctx) { + if (!completed_handshake_) { + // If the first handshake hasn't completed then we accept any certificates + // because we verify after the handshake. + return 1; + } + + if (X509Certificate::IsSameOSCert(server_cert_->os_cert_handle(), + sk_X509_value(store_ctx->untrusted, 0))) { + return 1; + } + + LOG(ERROR) << "Server certificate changed between handshakes"; + return 0; +} + // SelectNextProtoCallback is called by OpenSSL during the handshake. If the // server supports NPN, selects a protocol from the list that the server // provides. According to third_party/openssl/openssl/ssl/ssl_lib.c, the diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h index 5f4800a..0fc9cbe 100644 --- a/net/socket/ssl_client_socket_openssl.h +++ b/net/socket/ssl_client_socket_openssl.h @@ -27,6 +27,8 @@ typedef struct evp_pkey_st EVP_PKEY; typedef struct ssl_st SSL; // <openssl/x509.h> typedef struct x509_st X509; +// <openssl/ossl_type.h> +typedef struct x509_store_ctx_st X509_STORE_CTX; namespace net { @@ -131,6 +133,11 @@ class SSLClientSocketOpenSSL : public SSLClientSocket { // Channel IDs. void ChannelIDRequestCallback(SSL* ssl, EVP_PKEY** pkey); + // CertVerifyCallback is called to verify the server's certificates. We do + // verification after the handshake so this function only enforces that the + // certificates don't change during renegotiation. + int CertVerifyCallback(X509_STORE_CTX *store_ctx); + // Callback from the SSL layer to check which NPN protocol we are supporting int SelectNextProtoCallback(unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen); |