summaryrefslogtreecommitdiff
path: root/chromium/net/socket/ssl_client_socket_impl.cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-12 14:07:37 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-17 10:29:26 +0000
commitec02ee4181c49b61fce1c8fb99292dbb8139cc90 (patch)
tree25cde714b2b71eb639d1cd53f5a22e9ba76e14ef /chromium/net/socket/ssl_client_socket_impl.cc
parentbb09965444b5bb20b096a291445170876225268d (diff)
downloadqtwebengine-chromium-ec02ee4181c49b61fce1c8fb99292dbb8139cc90.tar.gz
BASELINE: Update Chromium to 59.0.3071.134
Change-Id: Id02ef6fb2204c5fd21668a1c3e6911c83b17585a Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/net/socket/ssl_client_socket_impl.cc')
-rw-r--r--chromium/net/socket/ssl_client_socket_impl.cc370
1 files changed, 140 insertions, 230 deletions
diff --git a/chromium/net/socket/ssl_client_socket_impl.cc b/chromium/net/socket/ssl_client_socket_impl.cc
index a81e33144c1..ab4f11350e2 100644
--- a/chromium/net/socket/ssl_client_socket_impl.cc
+++ b/chromium/net/socket/ssl_client_socket_impl.cc
@@ -12,7 +12,6 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
-#include "base/feature_list.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
@@ -219,24 +218,44 @@ int GetBufferSize(const char* field_trial) {
return buffer_size;
}
-#if defined(OS_NACL)
-bool AreLegacyECDSACiphersEnabled() {
- return false;
-}
+scoped_refptr<X509Certificate> OSChainFromBuffers(STACK_OF(CRYPTO_BUFFER) *
+ openssl_chain) {
+ if (sk_CRYPTO_BUFFER_num(openssl_chain) == 0) {
+ NOTREACHED();
+ return nullptr;
+ }
+
+#if BUILDFLAG(USE_BYTE_CERTS)
+ std::vector<CRYPTO_BUFFER*> intermediate_chain;
+ for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(openssl_chain); ++i)
+ intermediate_chain.push_back(sk_CRYPTO_BUFFER_value(openssl_chain, i));
+ return X509Certificate::CreateFromHandle(
+ sk_CRYPTO_BUFFER_value(openssl_chain, 0), intermediate_chain);
#else
-// TODO(davidben): Remove this after the ECDSA CBC removal sticks.
-// https:/crbug.com/666191.
-const base::Feature kLegacyECDSACiphersFeature{
- "SSLLegacyECDSACiphers", base::FEATURE_DISABLED_BY_DEFAULT};
+ // Convert the certificate chains to a platform certificate handle.
+ std::vector<base::StringPiece> der_chain;
+ der_chain.reserve(sk_CRYPTO_BUFFER_num(openssl_chain));
+ for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(openssl_chain); ++i) {
+ const CRYPTO_BUFFER* cert = sk_CRYPTO_BUFFER_value(openssl_chain, i);
+ base::StringPiece der;
+ der_chain.push_back(base::StringPiece(
+ reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert)),
+ CRYPTO_BUFFER_len(cert)));
+ }
+ return X509Certificate::CreateFromDERCertChain(der_chain);
+#endif
+}
-bool AreLegacyECDSACiphersEnabled() {
- return base::FeatureList::IsEnabled(kLegacyECDSACiphersFeature);
+#if !defined(OS_IOS) && !BUILDFLAG(USE_BYTE_CERTS)
+bssl::UniquePtr<CRYPTO_BUFFER> OSCertHandleToBuffer(
+ X509Certificate::OSCertHandle os_handle) {
+ std::string der_encoded;
+ if (!X509Certificate::GetDEREncoded(os_handle, &der_encoded))
+ return nullptr;
+ return x509_util::CreateCryptoBuffer(der_encoded);
}
#endif
-const base::Feature kShortRecordHeaderFeature{
- "SSLShortRecordHeader", base::FEATURE_DISABLED_BY_DEFAULT};
-
} // namespace
class SSLClientSocketImpl::SSLContext {
@@ -279,10 +298,11 @@ class SSLClientSocketImpl::SSLContext {
crypto::EnsureOpenSSLInit();
ssl_socket_data_index_ = SSL_get_ex_new_index(0, 0, 0, 0, 0);
DCHECK_NE(ssl_socket_data_index_, -1);
- ssl_ctx_.reset(SSL_CTX_new(SSLv23_client_method()));
- SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), CertVerifyCallback, NULL);
+ ssl_ctx_.reset(SSL_CTX_new(TLS_with_buffers_method()));
SSL_CTX_set_cert_cb(ssl_ctx_.get(), ClientCertRequestCallback, NULL);
- SSL_CTX_set_verify(ssl_ctx_.get(), SSL_VERIFY_PEER, NULL);
+
+ // The server certificate is verified after the handshake in DoVerifyCert.
+ SSL_CTX_i_promise_to_verify_certs_after_the_handshake(ssl_ctx_.get());
// Disable the internal session cache. Session caching is handled
// externally (i.e. by SSLClientSessionCache).
@@ -296,10 +316,6 @@ class SSLClientSocketImpl::SSLContext {
// Deduplicate all certificates minted from the SSL_CTX in memory.
SSL_CTX_set0_buffer_pool(ssl_ctx_.get(), x509_util::GetBufferPool());
- if (base::FeatureList::IsEnabled(kShortRecordHeaderFeature)) {
- SSL_CTX_set_short_header_enabled(ssl_ctx_.get(), 1);
- }
-
if (!SSL_CTX_add_client_custom_ext(ssl_ctx_.get(), kTbExtNum,
&TokenBindingAddCallback,
&TokenBindingFreeCallback, nullptr,
@@ -348,15 +364,6 @@ class SSLClientSocketImpl::SSLContext {
return socket->ClientCertRequestCallback(ssl);
}
- 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()));
- SSLClientSocketImpl* socket = GetInstance()->GetClientSocketFromSSL(ssl);
- CHECK(socket);
-
- return socket->CertVerifyCallback(store_ctx);
- }
-
static int NewSessionCallback(SSL* ssl, SSL_SESSION* session) {
SSLClientSocketImpl* socket = GetInstance()->GetClientSocketFromSSL(ssl);
return socket->NewSessionCallback(session);
@@ -428,88 +435,6 @@ const SSL_PRIVATE_KEY_METHOD
&SSLClientSocketImpl::SSLContext::PrivateKeyCompleteCallback,
};
-// PeerCertificateChain is a helper object which extracts the certificate
-// chain, as given by the server, from an OpenSSL socket and performs the needed
-// resource management. The first element of the chain is the leaf certificate
-// and the other elements are in the order given by the server.
-class SSLClientSocketImpl::PeerCertificateChain {
- public:
- explicit PeerCertificateChain(STACK_OF(X509) * chain) { Reset(chain); }
- PeerCertificateChain(const PeerCertificateChain& other) { *this = other; }
- ~PeerCertificateChain() {}
- PeerCertificateChain& operator=(const PeerCertificateChain& other);
-
- // Resets the PeerCertificateChain to the set of certificates in|chain|,
- // which may be NULL, indicating to empty the store certificates.
- // Note: If an error occurs, such as being unable to parse the certificates,
- // this will behave as if Reset(NULL) was called.
- void Reset(STACK_OF(X509) * chain);
-
- // Note that when USE_OPENSSL_CERTS is defined, OSCertHandle is X509*
- scoped_refptr<X509Certificate> AsOSChain() const;
-
- size_t size() const {
- if (!openssl_chain_.get())
- return 0;
- return sk_X509_num(openssl_chain_.get());
- }
-
- bool empty() const { return size() == 0; }
-
- X509* Get(size_t index) const {
- DCHECK_LT(index, size());
- return sk_X509_value(openssl_chain_.get(), index);
- }
-
- private:
- bssl::UniquePtr<STACK_OF(X509)> openssl_chain_;
-};
-
-SSLClientSocketImpl::PeerCertificateChain&
-SSLClientSocketImpl::PeerCertificateChain::operator=(
- const PeerCertificateChain& other) {
- if (this == &other)
- return *this;
-
- openssl_chain_.reset(X509_chain_up_ref(other.openssl_chain_.get()));
- return *this;
-}
-
-void SSLClientSocketImpl::PeerCertificateChain::Reset(STACK_OF(X509) * chain) {
- openssl_chain_.reset(chain ? X509_chain_up_ref(chain) : NULL);
-}
-
-scoped_refptr<X509Certificate>
-SSLClientSocketImpl::PeerCertificateChain::AsOSChain() const {
-#if defined(USE_OPENSSL_CERTS)
- // When OSCertHandle is typedef'ed to X509, this implementation does a short
- // cut to avoid converting back and forth between DER and the X509 struct.
- X509Certificate::OSCertHandles intermediates;
- for (size_t i = 1; i < sk_X509_num(openssl_chain_.get()); ++i) {
- X509* cert = sk_X509_value(openssl_chain_.get(), i);
- DCHECK(cert->buf);
- intermediates.push_back(cert);
- }
-
- X509* leaf = sk_X509_value(openssl_chain_.get(), 0);
- DCHECK(leaf->buf);
- return X509Certificate::CreateFromHandle(leaf, intermediates);
-#else
- // Convert the certificate chains to a platform certificate handle.
- std::vector<base::StringPiece> der_chain;
- der_chain.reserve(sk_X509_num(openssl_chain_.get()));
- for (size_t i = 0; i < sk_X509_num(openssl_chain_.get()); ++i) {
- X509* cert = sk_X509_value(openssl_chain_.get(), i);
- DCHECK(cert->buf);
- base::StringPiece der;
- if (!x509_util::GetDER(cert, &der))
- return nullptr;
- der_chain.push_back(der);
- }
- return X509Certificate::CreateFromDERCertChain(der_chain);
-#endif
-}
-
// static
void SSLClientSocket::ClearSessionCache() {
SSLClientSocketImpl::SSLContext* context =
@@ -524,7 +449,6 @@ SSLClientSocketImpl::SSLClientSocketImpl(
const SSLClientSocketContext& context)
: pending_read_error_(kNoPendingResult),
pending_read_ssl_error_(SSL_ERROR_NONE),
- server_cert_chain_(new PeerCertificateChain(NULL)),
completed_connect_(false),
was_ever_used_(false),
cert_verifier_(context.cert_verifier),
@@ -577,18 +501,13 @@ void SSLClientSocketImpl::GetSSLCertRequestInfo(
cert_request_info->host_and_port = host_and_port_;
cert_request_info->cert_authorities.clear();
- STACK_OF(X509_NAME)* authorities = SSL_get_client_CA_list(ssl_.get());
- for (size_t i = 0; i < sk_X509_NAME_num(authorities); i++) {
- X509_NAME* ca_name = sk_X509_NAME_value(authorities, i);
- uint8_t* str = nullptr;
- int length = i2d_X509_NAME(ca_name, &str);
- if (length > 0) {
- cert_request_info->cert_authorities.push_back(std::string(
- reinterpret_cast<const char*>(str), static_cast<size_t>(length)));
- } else {
- NOTREACHED(); // Error serializing |ca_name|.
- }
- OPENSSL_free(str);
+ const STACK_OF(CRYPTO_BUFFER)* authorities =
+ SSL_get0_server_requested_CAs(ssl_.get());
+ for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(authorities); i++) {
+ const CRYPTO_BUFFER* ca_name = sk_CRYPTO_BUFFER_value(authorities, i);
+ cert_request_info->cert_authorities.push_back(
+ std::string(reinterpret_cast<const char*>(CRYPTO_BUFFER_data(ca_name)),
+ CRYPTO_BUFFER_len(ca_name)));
}
cert_request_info->cert_key_types.clear();
@@ -792,7 +711,7 @@ NextProto SSLClientSocketImpl::GetNegotiatedProtocol() const {
bool SSLClientSocketImpl::GetSSLInfo(SSLInfo* ssl_info) {
ssl_info->Reset();
- if (server_cert_chain_->empty())
+ if (!server_cert_)
return false;
ssl_info->cert = server_cert_verify_result_.verified_cert;
@@ -842,16 +761,14 @@ int64_t SSLClientSocketImpl::GetTotalReceivedBytes() const {
void SSLClientSocketImpl::DumpMemoryStats(SocketMemoryStats* stats) const {
if (transport_adapter_)
stats->buffer_size = transport_adapter_->GetAllocationSize();
- if (server_cert_chain_) {
- for (size_t i = 0; i < server_cert_chain_->size(); ++i) {
- X509* cert = server_cert_chain_->Get(i);
- // Estimate the size of the certificate before deduplication.
- // The multiplier (4) is added to account for the difference between the
- // serialized cert size and the actual cert allocation.
- // TODO(xunjieli): Update this after crbug.com/671420 is done.
- stats->cert_size += 4 * i2d_X509(cert, nullptr);
+ const STACK_OF(CRYPTO_BUFFER)* server_cert_chain =
+ SSL_get0_peer_certificates(ssl_.get());
+ if (server_cert_chain) {
+ for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(server_cert_chain); ++i) {
+ const CRYPTO_BUFFER* cert = sk_CRYPTO_BUFFER_value(server_cert_chain, i);
+ stats->cert_size += CRYPTO_BUFFER_len(cert);
}
- stats->cert_count = server_cert_chain_->size();
+ stats->cert_count = sk_CRYPTO_BUFFER_num(server_cert_chain);
}
stats->total_size = stats->buffer_size + stats->cert_size;
}
@@ -865,20 +782,25 @@ void SSLClientSocketImpl::DumpSSLClientSessionMemoryStats(
int SSLClientSocketImpl::Read(IOBuffer* buf,
int buf_len,
const CompletionCallback& callback) {
- user_read_buf_ = buf;
- user_read_buf_len_ = buf_len;
+ int rv = ReadIfReady(buf, buf_len, callback);
+ if (rv == ERR_IO_PENDING) {
+ user_read_buf_ = buf;
+ user_read_buf_len_ = buf_len;
+ }
+ return rv;
+}
- int rv = DoPayloadRead();
+int SSLClientSocketImpl::ReadIfReady(IOBuffer* buf,
+ int buf_len,
+ const CompletionCallback& callback) {
+ int rv = DoPayloadRead(buf, buf_len);
if (rv == ERR_IO_PENDING) {
user_read_callback_ = callback;
} else {
if (rv > 0)
was_ever_used_ = true;
- user_read_buf_ = NULL;
- user_read_buf_len_ = 0;
}
-
return rv;
}
@@ -999,16 +921,13 @@ int SSLClientSocketImpl::Init() {
// Use BoringSSL defaults, but disable HMAC-SHA256 and HMAC-SHA384 ciphers
// (note that SHA256 and SHA384 only select legacy CBC ciphers).
- std::string command("ALL:!SHA256:!SHA384:!kDHE:!aPSK:!RC4");
+ // Additionally disable HMAC-SHA1 ciphers in ECDSA. These are the remaining
+ // CBC-mode ECDSA ciphers.
+ std::string command("ALL:!SHA256:!SHA384:!kDHE:!aPSK:!RC4:!ECDSA+SHA1");
if (ssl_config_.require_ecdhe)
command.append(":!kRSA:!kDHE");
- // Additionally disable HMAC-SHA1 ciphers in ECDSA. These are the remaining
- // CBC-mode ECDSA ciphers.
- if (!AreLegacyECDSACiphersEnabled())
- command.append("!ECDSA+SHA1");
-
// Remove any disabled ciphers.
for (uint16_t id : ssl_config_.disabled_cipher_suites) {
const SSL_CIPHER* cipher = SSL_get_cipher_by_value(id);
@@ -1061,7 +980,7 @@ void SSLClientSocketImpl::DoReadCallback(int rv) {
// up front.
if (rv > 0)
was_ever_used_ = true;
- user_read_buf_ = NULL;
+ user_read_buf_ = nullptr;
user_read_buf_len_ = 0;
base::ResetAndReturn(&user_read_callback_).Run(rv);
}
@@ -1147,6 +1066,11 @@ int SSLClientSocketImpl::DoHandshakeComplete(int result) {
if (result < 0)
return result;
+ if (ssl_config_.version_interference_probe) {
+ DCHECK_LT(ssl_config_.version_max, TLS1_3_VERSION);
+ return ERR_SSL_VERSION_INTERFERENCE;
+ }
+
SSLContext::GetInstance()->session_cache()->ResetLookupCount(
GetSessionCacheKey());
// Check that if token binding was negotiated, then extended master secret
@@ -1201,7 +1125,6 @@ int SSLClientSocketImpl::DoHandshakeComplete(int result) {
}
// Verify the certificate.
- UpdateServerCert();
next_handshake_state_ = STATE_VERIFY_CERT;
return OK;
}
@@ -1241,10 +1164,9 @@ int SSLClientSocketImpl::DoChannelIDLookupComplete(int result) {
}
int SSLClientSocketImpl::DoVerifyCert(int result) {
- DCHECK(!server_cert_chain_->empty());
DCHECK(start_cert_verification_time_.is_null());
- next_handshake_state_ = STATE_VERIFY_CERT_COMPLETE;
+ server_cert_ = OSChainFromBuffers(SSL_get0_peer_certificates(ssl_.get()));
// OpenSSL decoded the certificate, but the platform certificate
// implementation could not. This is treated as a fatal SSL-level protocol
@@ -1252,6 +1174,12 @@ int SSLClientSocketImpl::DoVerifyCert(int result) {
if (!server_cert_)
return ERR_SSL_SERVER_CERT_BAD_FORMAT;
+ net_log_.AddEvent(NetLogEventType::SSL_CERTIFICATES_RECEIVED,
+ base::Bind(&NetLogX509CertificateCallback,
+ base::Unretained(server_cert_.get())));
+
+ next_handshake_state_ = STATE_VERIFY_CERT_COMPLETE;
+
// If the certificate is bad and has been previously accepted, use
// the previous status and bypass the error.
CertStatus cert_status;
@@ -1356,16 +1284,6 @@ void SSLClientSocketImpl::DoConnectCallback(int rv) {
}
}
-void SSLClientSocketImpl::UpdateServerCert() {
- server_cert_chain_->Reset(SSL_get_peer_cert_chain(ssl_.get()));
- server_cert_ = server_cert_chain_->AsOSChain();
- if (server_cert_.get()) {
- net_log_.AddEvent(NetLogEventType::SSL_CERTIFICATES_RECEIVED,
- base::Bind(&NetLogX509CertificateCallback,
- base::Unretained(server_cert_.get())));
- }
-}
-
void SSLClientSocketImpl::OnHandshakeIOComplete(int result) {
int rv = DoHandshakeLoop(result);
if (rv != ERR_IO_PENDING) {
@@ -1416,11 +1334,11 @@ int SSLClientSocketImpl::DoHandshakeLoop(int last_io_result) {
return rv;
}
-int SSLClientSocketImpl::DoPayloadRead() {
+int SSLClientSocketImpl::DoPayloadRead(IOBuffer* buf, int buf_len) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- DCHECK_LT(0, user_read_buf_len_);
- DCHECK(user_read_buf_.get());
+ DCHECK_LT(0, buf_len);
+ DCHECK(buf);
int rv;
if (pending_read_error_ != kNoPendingResult) {
@@ -1428,7 +1346,7 @@ int SSLClientSocketImpl::DoPayloadRead() {
pending_read_error_ = kNoPendingResult;
if (rv == 0) {
net_log_.AddByteTransferEvent(NetLogEventType::SSL_SOCKET_BYTES_RECEIVED,
- rv, user_read_buf_->data());
+ rv, buf->data());
} else {
net_log_.AddEvent(
NetLogEventType::SSL_READ_ERROR,
@@ -1443,11 +1361,14 @@ int SSLClientSocketImpl::DoPayloadRead() {
int total_bytes_read = 0;
int ssl_ret;
do {
- ssl_ret = SSL_read(ssl_.get(), user_read_buf_->data() + total_bytes_read,
- user_read_buf_len_ - total_bytes_read);
+ ssl_ret = SSL_read(ssl_.get(), buf->data() + total_bytes_read,
+ buf_len - total_bytes_read);
if (ssl_ret > 0)
total_bytes_read += ssl_ret;
- } while (total_bytes_read < user_read_buf_len_ && ssl_ret > 0);
+ // Continue processing records as long as there is more data available
+ // synchronously.
+ } while (total_bytes_read < buf_len && ssl_ret > 0 &&
+ transport_adapter_->HasPendingReadData());
// Although only the final SSL_read call may have failed, the failure needs to
// processed immediately, while the information still available in OpenSSL's
@@ -1504,7 +1425,7 @@ int SSLClientSocketImpl::DoPayloadRead() {
if (rv >= 0) {
net_log_.AddByteTransferEvent(NetLogEventType::SSL_SOCKET_BYTES_RECEIVED,
- rv, user_read_buf_->data());
+ rv, buf->data());
} else if (rv != ERR_IO_PENDING) {
net_log_.AddEvent(
NetLogEventType::SSL_READ_ERROR,
@@ -1553,8 +1474,14 @@ void SSLClientSocketImpl::RetryAllOperations() {
int rv_read = ERR_IO_PENDING;
int rv_write = ERR_IO_PENDING;
- if (user_read_buf_)
- rv_read = DoPayloadRead();
+ if (user_read_buf_) {
+ rv_read = DoPayloadRead(user_read_buf_.get(), user_read_buf_len_);
+ } else if (!user_read_callback_.is_null()) {
+ // ReadIfReady() is called by the user. Skip DoPayloadRead() and just let
+ // the user know that read can be retried.
+ rv_read = OK;
+ }
+
if (user_write_buf_)
rv_write = DoPayloadWrite();
@@ -1660,38 +1587,53 @@ int SSLClientSocketImpl::ClientCertRequestCallback(SSL* ssl) {
// Second pass: a client certificate should have been selected.
if (ssl_config_.client_cert.get()) {
- bssl::UniquePtr<X509> leaf_x509 =
- OSCertHandleToOpenSSL(ssl_config_.client_cert->os_cert_handle());
- if (!leaf_x509) {
- LOG(WARNING) << "Failed to import certificate";
- OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT);
+ if (!ssl_config_.client_private_key) {
+ // The caller supplied a null private key. Fail the handshake and surface
+ // an appropriate error to the caller.
+ LOG(WARNING) << "Client cert found without private key";
+ OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY);
return -1;
}
- bssl::UniquePtr<STACK_OF(X509)> chain = OSCertHandlesToOpenSSL(
- ssl_config_.client_cert->GetIntermediateCertificates());
- if (!chain) {
- LOG(WARNING) << "Failed to import intermediate certificates";
+#if BUILDFLAG(USE_BYTE_CERTS)
+ std::vector<CRYPTO_BUFFER*> chain_raw;
+ chain_raw.push_back(ssl_config_.client_cert->os_cert_handle());
+ for (X509Certificate::OSCertHandle cert :
+ ssl_config_.client_cert->GetIntermediateCertificates()) {
+ chain_raw.push_back(cert);
+ }
+#else
+ std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> chain;
+ std::vector<CRYPTO_BUFFER*> chain_raw;
+ bssl::UniquePtr<CRYPTO_BUFFER> buf =
+ OSCertHandleToBuffer(ssl_config_.client_cert->os_cert_handle());
+ if (!buf) {
+ LOG(WARNING) << "Failed to import certificate";
OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT);
return -1;
}
-
- if (!SSL_use_certificate(ssl_.get(), leaf_x509.get()) ||
- !SSL_set1_chain(ssl_.get(), chain.get())) {
- LOG(WARNING) << "Failed to set client certificate";
- return -1;
+ chain_raw.push_back(buf.get());
+ chain.push_back(std::move(buf));
+
+ for (X509Certificate::OSCertHandle cert :
+ ssl_config_.client_cert->GetIntermediateCertificates()) {
+ bssl::UniquePtr<CRYPTO_BUFFER> buf = OSCertHandleToBuffer(cert);
+ if (!buf) {
+ LOG(WARNING) << "Failed to import intermediate";
+ OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT);
+ return -1;
+ }
+ chain_raw.push_back(buf.get());
+ chain.push_back(std::move(buf));
}
+#endif
- if (!ssl_config_.client_private_key) {
- // The caller supplied a null private key. Fail the handshake and surface
- // an appropriate error to the caller.
- LOG(WARNING) << "Client cert found without private key";
- OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY);
+ if (!SSL_set_chain_and_key(ssl_.get(), chain_raw.data(), chain_raw.size(),
+ nullptr, &SSLContext::kPrivateKeyMethod)) {
+ LOG(WARNING) << "Failed to set client certificate";
return -1;
}
- SSL_set_private_key_method(ssl_.get(), &SSLContext::kPrivateKeyMethod);
-
std::vector<SSLPrivateKey::Hash> digest_prefs =
ssl_config_.client_private_key->GetDigestPreferences();
@@ -1720,9 +1662,8 @@ int SSLClientSocketImpl::ClientCertRequestCallback(SSL* ssl) {
SSL_set_private_key_digest_prefs(ssl_.get(), digests.data(),
digests.size());
- int cert_count = 1 + sk_X509_num(chain.get());
net_log_.AddEvent(NetLogEventType::SSL_CLIENT_CERT_PROVIDED,
- NetLog::IntCallback("cert_count", cert_count));
+ NetLog::IntCallback("cert_count", chain_raw.size()));
return 1;
}
#endif // defined(OS_IOS)
@@ -1733,33 +1674,6 @@ int SSLClientSocketImpl::ClientCertRequestCallback(SSL* ssl) {
return 1;
}
-int SSLClientSocketImpl::CertVerifyCallback(X509_STORE_CTX* store_ctx) {
- if (!completed_connect_) {
- // If the first handshake hasn't completed then we accept any certificates
- // because we verify after the handshake.
- return 1;
- }
-
- // Disallow the server certificate to change in a renegotiation.
- if (server_cert_chain_->empty()) {
- LOG(ERROR) << "Received invalid certificate chain between handshakes";
- return 0;
- }
- base::StringPiece old_der, new_der;
- if (store_ctx->cert == NULL ||
- !x509_util::GetDER(server_cert_chain_->Get(0), &old_der) ||
- !x509_util::GetDER(store_ctx->cert, &new_der)) {
- LOG(ERROR) << "Failed to encode certificates";
- return 0;
- }
- if (old_der != new_der) {
- LOG(ERROR) << "Server certificate changed between handshakes";
- return 0;
- }
-
- return 1;
-}
-
void SSLClientSocketImpl::MaybeCacheSession() {
// Only cache the session once both a new session has been established and the
// certificate has been verified. Due to False Start, these events may happen
@@ -1785,17 +1699,13 @@ void SSLClientSocketImpl::AddCTInfoToSSLInfo(SSLInfo* ssl_info) const {
std::string SSLClientSocketImpl::GetSessionCacheKey() const {
std::string result = host_and_port_.ToString();
- result.append("/");
+ result.push_back('/');
result.append(ssl_session_cache_shard_);
- result.append("/");
- if (ssl_config_.deprecated_cipher_suites_enabled)
- result.append("deprecated");
-
- result.append("/");
- if (ssl_config_.channel_id_enabled)
- result.append("channelid");
-
+ result.push_back('/');
+ result.push_back(ssl_config_.deprecated_cipher_suites_enabled ? '1' : '0');
+ result.push_back(ssl_config_.channel_id_enabled ? '1' : '0');
+ result.push_back(ssl_config_.version_interference_probe ? '1' : '0');
return result;
}