Commit 43527bf8 authored by David Benjamin's avatar David Benjamin Committed by Commit Bot

Run the read pipe in SSLClientSocket immediately after the handshake.

See https://boringssl-review.googlesource.com/c/boringssl/+/37944 for
the rationale.

Bug: 950706, 958638
Change-Id: I221b0e7f6f626968fc38e0bce84260e4141c5e44
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1838456Reviewed-by: default avatarSteven Valdez <svaldez@chromium.org>
Commit-Queue: David Benjamin <davidben@chromium.org>
Cr-Commit-Position: refs/heads/master@{#702944}
parent bde80fe4
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "base/containers/span.h" #include "base/containers/span.h"
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/lazy_instance.h" #include "base/lazy_instance.h"
#include "base/location.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "base/metrics/field_trial.h" #include "base/metrics/field_trial.h"
...@@ -26,6 +27,7 @@ ...@@ -26,6 +27,7 @@
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "base/values.h" #include "base/values.h"
#include "build/build_config.h" #include "build/build_config.h"
...@@ -401,6 +403,7 @@ SSLClientSocketImpl::SSLClientSocketImpl( ...@@ -401,6 +403,7 @@ SSLClientSocketImpl::SSLClientSocketImpl(
ssl_config_(ssl_config), ssl_config_(ssl_config),
next_handshake_state_(STATE_NONE), next_handshake_state_(STATE_NONE),
in_confirm_handshake_(false), in_confirm_handshake_(false),
peek_complete_(false),
disconnected_(false), disconnected_(false),
negotiated_protocol_(kProtoUnknown), negotiated_protocol_(kProtoUnknown),
certificate_requested_(false), certificate_requested_(false),
...@@ -871,8 +874,10 @@ int SSLClientSocketImpl::Init() { ...@@ -871,8 +874,10 @@ int SSLClientSocketImpl::Init() {
// Configure BoringSSL to allow renegotiations. Once the initial handshake // Configure BoringSSL to allow renegotiations. Once the initial handshake
// completes, if renegotiations are not allowed, the default reject value will // completes, if renegotiations are not allowed, the default reject value will
// be restored. This is done in this order to permit a BoringSSL // be restored. This is done in this order to permit a BoringSSL
// optimization. See https://crbug.com/boringssl/123. // optimization. See https://crbug.com/boringssl/123. Use
SSL_set_renegotiate_mode(ssl_.get(), ssl_renegotiate_freely); // ssl_renegotiate_explicit rather than ssl_renegotiate_freely so DoPeek()
// does not trigger renegotiations.
SSL_set_renegotiate_mode(ssl_.get(), ssl_renegotiate_explicit);
SSL_set_shed_handshake_config(ssl_.get(), 1); SSL_set_shed_handshake_config(ssl_.get(), 1);
...@@ -1085,6 +1090,25 @@ int SSLClientSocketImpl::DoHandshakeComplete(int result) { ...@@ -1085,6 +1090,25 @@ int SSLClientSocketImpl::DoHandshakeComplete(int result) {
completed_connect_ = true; completed_connect_ = true;
next_handshake_state_ = STATE_NONE; next_handshake_state_ = STATE_NONE;
// Read from the transport immediately after the handshake, whether Read() is
// called immediately or not. This serves several purposes:
//
// First, if this socket is preconnected and negotiates 0-RTT, the ServerHello
// will not be processed. See https://crbug.com/950706
//
// Second, in False Start and TLS 1.3, the tickets arrive after immediately
// after the handshake. This allows preconnected sockets to process the
// tickets sooner. This also avoids a theoretical deadlock if the tickets are
// too large. See
// https://boringssl-review.googlesource.com/c/boringssl/+/34948.
//
// TODO(https://crbug.com/958638): It is also a step in making TLS 1.3 client
// certificate alerts less unreliable.
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&SSLClientSocketImpl::DoPeek, weak_factory_.GetWeakPtr()));
return OK; return OK;
} }
...@@ -1320,22 +1344,29 @@ int SSLClientSocketImpl::DoPayloadRead(IOBuffer* buf, int buf_len) { ...@@ -1320,22 +1344,29 @@ int SSLClientSocketImpl::DoPayloadRead(IOBuffer* buf, int buf_len) {
} }
int total_bytes_read = 0; int total_bytes_read = 0;
int ssl_ret; int ssl_ret, ssl_err;
do { do {
ssl_ret = SSL_read(ssl_.get(), buf->data() + total_bytes_read, ssl_ret = SSL_read(ssl_.get(), buf->data() + total_bytes_read,
buf_len - total_bytes_read); buf_len - total_bytes_read);
if (ssl_ret > 0) ssl_err = SSL_get_error(ssl_.get(), ssl_ret);
if (ssl_ret > 0) {
total_bytes_read += ssl_ret; total_bytes_read += ssl_ret;
} else if (ssl_err == SSL_ERROR_WANT_RENEGOTIATE) {
if (!SSL_renegotiate(ssl_.get())) {
ssl_err = SSL_ERROR_SSL;
}
}
// Continue processing records as long as there is more data available // Continue processing records as long as there is more data available
// synchronously. // synchronously.
} while (total_bytes_read < buf_len && ssl_ret > 0 && } while (ssl_err == SSL_ERROR_WANT_RENEGOTIATE ||
transport_adapter_->HasPendingReadData()); (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 // Although only the final SSL_read call may have failed, the failure needs to
// processed immediately, while the information still available in OpenSSL's // processed immediately, while the information still available in OpenSSL's
// error queue. // error queue.
if (ssl_ret <= 0) { if (ssl_ret <= 0) {
pending_read_ssl_error_ = SSL_get_error(ssl_.get(), ssl_ret); pending_read_ssl_error_ = ssl_err;
if (pending_read_ssl_error_ == SSL_ERROR_ZERO_RETURN) { if (pending_read_ssl_error_ == SSL_ERROR_ZERO_RETURN) {
pending_read_error_ = 0; pending_read_error_ = 0;
} else if (pending_read_ssl_error_ == SSL_ERROR_WANT_X509_LOOKUP && } else if (pending_read_ssl_error_ == SSL_ERROR_WANT_X509_LOOKUP &&
...@@ -1419,6 +1450,22 @@ int SSLClientSocketImpl::DoPayloadWrite() { ...@@ -1419,6 +1450,22 @@ int SSLClientSocketImpl::DoPayloadWrite() {
return net_error; return net_error;
} }
void SSLClientSocketImpl::DoPeek() {
if (ssl_config_.disable_post_handshake_peek_for_testing ||
!completed_connect_ || peek_complete_) {
return;
}
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
char byte;
int rv = SSL_peek(ssl_.get(), &byte, 1);
int ssl_err = SSL_get_error(ssl_.get(), rv);
if (ssl_err != SSL_ERROR_WANT_READ && ssl_err != SSL_ERROR_WANT_WRITE) {
peek_complete_ = true;
}
}
void SSLClientSocketImpl::RetryAllOperations() { void SSLClientSocketImpl::RetryAllOperations() {
// SSL_do_handshake, SSL_read, and SSL_write may all be retried when blocked, // SSL_do_handshake, SSL_read, and SSL_write may all be retried when blocked,
// so retry all operations for simplicity. (Otherwise, SSL_get_error for each // so retry all operations for simplicity. (Otherwise, SSL_get_error for each
...@@ -1436,6 +1483,8 @@ void SSLClientSocketImpl::RetryAllOperations() { ...@@ -1436,6 +1483,8 @@ void SSLClientSocketImpl::RetryAllOperations() {
if (!guard.get()) if (!guard.get())
return; return;
DoPeek();
int rv_read = ERR_IO_PENDING; int rv_read = ERR_IO_PENDING;
int rv_write = ERR_IO_PENDING; int rv_write = ERR_IO_PENDING;
if (user_read_buf_) { if (user_read_buf_) {
......
...@@ -136,6 +136,7 @@ class SSLClientSocketImpl : public SSLClientSocket, ...@@ -136,6 +136,7 @@ class SSLClientSocketImpl : public SSLClientSocket,
int DoHandshakeLoop(int last_io_result); int DoHandshakeLoop(int last_io_result);
int DoPayloadRead(IOBuffer* buf, int buf_len); int DoPayloadRead(IOBuffer* buf, int buf_len);
int DoPayloadWrite(); int DoPayloadWrite();
void DoPeek();
// Called when an asynchronous event completes which may have blocked the // Called when an asynchronous event completes which may have blocked the
// pending Connect, Read or Write calls, if any. Retries all state machines // pending Connect, Read or Write calls, if any. Retries all state machines
...@@ -272,6 +273,9 @@ class SSLClientSocketImpl : public SSLClientSocket, ...@@ -272,6 +273,9 @@ class SSLClientSocketImpl : public SSLClientSocket,
// True if we are currently confirming the handshake. // True if we are currently confirming the handshake.
bool in_confirm_handshake_; bool in_confirm_handshake_;
// True if the post-handshake SSL_peek has completed.
bool peek_complete_;
// True if the socket has been disconnected. // True if the socket has been disconnected.
bool disconnected_; bool disconnected_;
......
This diff is collapsed.
...@@ -21,13 +21,7 @@ SSLConfig::CertAndStatus::CertAndStatus(scoped_refptr<X509Certificate> cert_arg, ...@@ -21,13 +21,7 @@ SSLConfig::CertAndStatus::CertAndStatus(scoped_refptr<X509Certificate> cert_arg,
SSLConfig::CertAndStatus::CertAndStatus(const CertAndStatus& other) = default; SSLConfig::CertAndStatus::CertAndStatus(const CertAndStatus& other) = default;
SSLConfig::CertAndStatus::~CertAndStatus() = default; SSLConfig::CertAndStatus::~CertAndStatus() = default;
SSLConfig::SSLConfig() SSLConfig::SSLConfig() = default;
: early_data_enabled(false),
require_ecdhe(false),
ignore_certificate_errors(false),
disable_cert_verification_network_fetches(false),
renego_allowed_default(false),
privacy_mode(PRIVACY_MODE_DISABLED) {}
SSLConfig::SSLConfig(const SSLConfig& other) = default; SSLConfig::SSLConfig(const SSLConfig& other) = default;
......
...@@ -73,10 +73,10 @@ struct NET_EXPORT SSLConfig { ...@@ -73,10 +73,10 @@ struct NET_EXPORT SSLConfig {
// high-level operation. // high-level operation.
// //
// If unsure, do not enable this option. // If unsure, do not enable this option.
bool early_data_enabled; bool early_data_enabled = false;
// If true, causes only ECDHE cipher suites to be enabled. // If true, causes only ECDHE cipher suites to be enabled.
bool require_ecdhe; bool require_ecdhe = false;
// TODO(wtc): move the following members to a new SSLParams structure. They // TODO(wtc): move the following members to a new SSLParams structure. They
// are not SSL configuration settings. // are not SSL configuration settings.
...@@ -98,7 +98,7 @@ struct NET_EXPORT SSLConfig { ...@@ -98,7 +98,7 @@ struct NET_EXPORT SSLConfig {
std::vector<CertAndStatus> allowed_bad_certs; std::vector<CertAndStatus> allowed_bad_certs;
// True if all certificate errors should be ignored. // True if all certificate errors should be ignored.
bool ignore_certificate_errors; bool ignore_certificate_errors = false;
// True if, for a single connection, any dependent network fetches should // True if, for a single connection, any dependent network fetches should
// be disabled. This can be used to avoid triggering re-entrancy in the // be disabled. This can be used to avoid triggering re-entrancy in the
...@@ -106,7 +106,7 @@ struct NET_EXPORT SSLConfig { ...@@ -106,7 +106,7 @@ struct NET_EXPORT SSLConfig {
// AIA, OCSP, or CRL fetches to block on retrieving the PAC script, while // AIA, OCSP, or CRL fetches to block on retrieving the PAC script, while
// the PAC script fetch is waiting for those dependent fetches, creating a // the PAC script fetch is waiting for those dependent fetches, creating a
// deadlock. // deadlock.
bool disable_cert_verification_network_fetches; bool disable_cert_verification_network_fetches = false;
// The list of application level protocols supported with ALPN (Application // The list of application level protocols supported with ALPN (Application
// Layer Protocol Negotiation), in decreasing order of preference. Protocols // Layer Protocol Negotiation), in decreasing order of preference. Protocols
...@@ -115,7 +115,7 @@ struct NET_EXPORT SSLConfig { ...@@ -115,7 +115,7 @@ struct NET_EXPORT SSLConfig {
// True if renegotiation should be allowed for the default application-level // True if renegotiation should be allowed for the default application-level
// protocol when the peer negotiates neither ALPN nor NPN. // protocol when the peer negotiates neither ALPN nor NPN.
bool renego_allowed_default; bool renego_allowed_default = false;
// The list of application-level protocols to enable renegotiation for. // The list of application-level protocols to enable renegotiation for.
NextProtoVector renego_allowed_for_protos; NextProtoVector renego_allowed_for_protos;
...@@ -132,7 +132,12 @@ struct NET_EXPORT SSLConfig { ...@@ -132,7 +132,12 @@ struct NET_EXPORT SSLConfig {
// current session cache partitioning behavior will be needed to correctly // current session cache partitioning behavior will be needed to correctly
// implement it. For now, it acts as an incomplete version of // implement it. For now, it acts as an incomplete version of
// PartitionSSLSessionsByNetworkIsolationKey. // PartitionSSLSessionsByNetworkIsolationKey.
PrivacyMode privacy_mode; PrivacyMode privacy_mode = PRIVACY_MODE_DISABLED;
// True if the post-handshake peeking of the transport should be skipped. This
// logic ensures 0-RTT and tickets are resolved early, but can interfere with
// some unit tests.
bool disable_post_handshake_peek_for_testing = false;
}; };
} // namespace net } // namespace net
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment