summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/socket/ssl_client_socket_openssl.cc39
-rw-r--r--net/socket/ssl_client_socket_openssl.h7
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);