1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/socket/ssl_connect_job.h"
6
7 #include <cstdlib>
8 #include <memory>
9 #include <utility>
10
11 #include "base/feature_list.h"
12 #include "base/functional/bind.h"
13 #include "base/functional/callback_helpers.h"
14 #include "net/base/connection_endpoint_metadata.h"
15 #include "net/base/features.h"
16 #include "net/base/host_port_pair.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/trace_constants.h"
19 #include "net/base/tracing.h"
20 #include "net/base/url_util.h"
21 #include "net/cert/x509_util.h"
22 #include "net/http/http_proxy_connect_job.h"
23 #include "net/log/net_log_source_type.h"
24 #include "net/log/net_log_values.h"
25 #include "net/log/net_log_with_source.h"
26 #include "net/socket/client_socket_factory.h"
27 #include "net/socket/client_socket_handle.h"
28 #include "net/socket/socks_connect_job.h"
29 #include "net/socket/ssl_client_socket.h"
30 #include "net/socket/transport_connect_job.h"
31 #include "net/ssl/ssl_cert_request_info.h"
32 #include "net/ssl/ssl_connection_status_flags.h"
33 #include "net/ssl/ssl_info.h"
34 #include "third_party/abseil-cpp/absl/types/variant.h"
35 #include "third_party/boringssl/src/include/openssl/pool.h"
36 #include "third_party/boringssl/src/include/openssl/ssl.h"
37
38 namespace net {
39
40 namespace {
41
42 // Timeout for the SSL handshake portion of the connect.
43 constexpr base::TimeDelta kSSLHandshakeTimeout(base::Seconds(30));
44
45 } // namespace
46
SSLSocketParams(ConnectJobParams nested_params,const HostPortPair & host_and_port,const SSLConfig & ssl_config,NetworkAnonymizationKey network_anonymization_key)47 SSLSocketParams::SSLSocketParams(
48 ConnectJobParams nested_params,
49 const HostPortPair& host_and_port,
50 const SSLConfig& ssl_config,
51 NetworkAnonymizationKey network_anonymization_key)
52 : nested_params_(nested_params),
53 host_and_port_(host_and_port),
54 ssl_config_(ssl_config),
55 network_anonymization_key_(network_anonymization_key) {
56 CHECK(!nested_params_.is_ssl());
57 }
58
59 SSLSocketParams::~SSLSocketParams() = default;
60
GetConnectionType() const61 SSLSocketParams::ConnectionType SSLSocketParams::GetConnectionType() const {
62 if (nested_params_.is_socks()) {
63 return SOCKS_PROXY;
64 }
65 if (nested_params_.is_http_proxy()) {
66 return HTTP_PROXY;
67 }
68 return DIRECT;
69 }
70
Create(RequestPriority priority,const SocketTag & socket_tag,const CommonConnectJobParams * common_connect_job_params,scoped_refptr<SSLSocketParams> params,ConnectJob::Delegate * delegate,const NetLogWithSource * net_log)71 std::unique_ptr<SSLConnectJob> SSLConnectJob::Factory::Create(
72 RequestPriority priority,
73 const SocketTag& socket_tag,
74 const CommonConnectJobParams* common_connect_job_params,
75 scoped_refptr<SSLSocketParams> params,
76 ConnectJob::Delegate* delegate,
77 const NetLogWithSource* net_log) {
78 return std::make_unique<SSLConnectJob>(priority, socket_tag,
79 common_connect_job_params,
80 std::move(params), delegate, net_log);
81 }
82
SSLConnectJob(RequestPriority priority,const SocketTag & socket_tag,const CommonConnectJobParams * common_connect_job_params,scoped_refptr<SSLSocketParams> params,ConnectJob::Delegate * delegate,const NetLogWithSource * net_log)83 SSLConnectJob::SSLConnectJob(
84 RequestPriority priority,
85 const SocketTag& socket_tag,
86 const CommonConnectJobParams* common_connect_job_params,
87 scoped_refptr<SSLSocketParams> params,
88 ConnectJob::Delegate* delegate,
89 const NetLogWithSource* net_log)
90 : ConnectJob(
91 priority,
92 socket_tag,
93 // The SSLConnectJob's timer is only started during the SSL handshake.
94 base::TimeDelta(),
95 common_connect_job_params,
96 delegate,
97 net_log,
98 NetLogSourceType::SSL_CONNECT_JOB,
99 NetLogEventType::SSL_CONNECT_JOB_CONNECT),
100 params_(std::move(params)),
101 callback_(base::BindRepeating(&SSLConnectJob::OnIOComplete,
102 base::Unretained(this))) {}
103
~SSLConnectJob()104 SSLConnectJob::~SSLConnectJob() {
105 // In the case the job was canceled, need to delete nested job first to
106 // correctly order NetLog events.
107 nested_connect_job_.reset();
108 }
109
GetLoadState() const110 LoadState SSLConnectJob::GetLoadState() const {
111 switch (next_state_) {
112 case STATE_TRANSPORT_CONNECT:
113 case STATE_SOCKS_CONNECT:
114 case STATE_TUNNEL_CONNECT:
115 return LOAD_STATE_IDLE;
116 case STATE_TRANSPORT_CONNECT_COMPLETE:
117 case STATE_SOCKS_CONNECT_COMPLETE:
118 return nested_connect_job_->GetLoadState();
119 case STATE_TUNNEL_CONNECT_COMPLETE:
120 if (nested_socket_) {
121 return LOAD_STATE_ESTABLISHING_PROXY_TUNNEL;
122 }
123 return nested_connect_job_->GetLoadState();
124 case STATE_SSL_CONNECT:
125 case STATE_SSL_CONNECT_COMPLETE:
126 return LOAD_STATE_SSL_HANDSHAKE;
127 default:
128 NOTREACHED();
129 }
130 }
131
HasEstablishedConnection() const132 bool SSLConnectJob::HasEstablishedConnection() const {
133 // If waiting on a nested ConnectJob, defer to that ConnectJob's state.
134 if (nested_connect_job_) {
135 return nested_connect_job_->HasEstablishedConnection();
136 }
137 // Otherwise, return true if a socket has been created.
138 return nested_socket_ || ssl_socket_;
139 }
140
OnConnectJobComplete(int result,ConnectJob * job)141 void SSLConnectJob::OnConnectJobComplete(int result, ConnectJob* job) {
142 DCHECK_EQ(job, nested_connect_job_.get());
143 OnIOComplete(result);
144 }
145
OnNeedsProxyAuth(const HttpResponseInfo & response,HttpAuthController * auth_controller,base::OnceClosure restart_with_auth_callback,ConnectJob * job)146 void SSLConnectJob::OnNeedsProxyAuth(
147 const HttpResponseInfo& response,
148 HttpAuthController* auth_controller,
149 base::OnceClosure restart_with_auth_callback,
150 ConnectJob* job) {
151 DCHECK_EQ(next_state_, STATE_TUNNEL_CONNECT_COMPLETE);
152
153 // The timer shouldn't have started running yet, since the handshake only
154 // starts after a tunnel has been established through the proxy.
155 DCHECK(!TimerIsRunning());
156
157 // Just pass the callback up to the consumer. This class doesn't need to do
158 // anything once credentials are provided.
159 NotifyDelegateOfProxyAuth(response, auth_controller,
160 std::move(restart_with_auth_callback));
161 }
162
GetConnectionAttempts() const163 ConnectionAttempts SSLConnectJob::GetConnectionAttempts() const {
164 return connection_attempts_;
165 }
166
GetResolveErrorInfo() const167 ResolveErrorInfo SSLConnectJob::GetResolveErrorInfo() const {
168 return resolve_error_info_;
169 }
170
IsSSLError() const171 bool SSLConnectJob::IsSSLError() const {
172 return ssl_negotiation_started_;
173 }
174
GetCertRequestInfo()175 scoped_refptr<SSLCertRequestInfo> SSLConnectJob::GetCertRequestInfo() {
176 return ssl_cert_request_info_;
177 }
178
HandshakeTimeoutForTesting()179 base::TimeDelta SSLConnectJob::HandshakeTimeoutForTesting() {
180 return kSSLHandshakeTimeout;
181 }
182
OnIOComplete(int result)183 void SSLConnectJob::OnIOComplete(int result) {
184 int rv = DoLoop(result);
185 if (rv != ERR_IO_PENDING) {
186 NotifyDelegateOfCompletion(rv); // Deletes |this|.
187 }
188 }
189
DoLoop(int result)190 int SSLConnectJob::DoLoop(int result) {
191 TRACE_EVENT0(NetTracingCategory(), "SSLConnectJob::DoLoop");
192 DCHECK_NE(next_state_, STATE_NONE);
193
194 int rv = result;
195 do {
196 State state = next_state_;
197 next_state_ = STATE_NONE;
198 switch (state) {
199 case STATE_TRANSPORT_CONNECT:
200 DCHECK_EQ(OK, rv);
201 rv = DoTransportConnect();
202 break;
203 case STATE_TRANSPORT_CONNECT_COMPLETE:
204 rv = DoTransportConnectComplete(rv);
205 break;
206 case STATE_SOCKS_CONNECT:
207 DCHECK_EQ(OK, rv);
208 rv = DoSOCKSConnect();
209 break;
210 case STATE_SOCKS_CONNECT_COMPLETE:
211 rv = DoSOCKSConnectComplete(rv);
212 break;
213 case STATE_TUNNEL_CONNECT:
214 DCHECK_EQ(OK, rv);
215 rv = DoTunnelConnect();
216 break;
217 case STATE_TUNNEL_CONNECT_COMPLETE:
218 rv = DoTunnelConnectComplete(rv);
219 break;
220 case STATE_SSL_CONNECT:
221 DCHECK_EQ(OK, rv);
222 rv = DoSSLConnect();
223 break;
224 case STATE_SSL_CONNECT_COMPLETE:
225 rv = DoSSLConnectComplete(rv);
226 break;
227 default:
228 NOTREACHED() << "bad state";
229 }
230 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
231
232 return rv;
233 }
234
DoTransportConnect()235 int SSLConnectJob::DoTransportConnect() {
236 DCHECK(!nested_connect_job_);
237 DCHECK(params_->GetDirectConnectionParams());
238 DCHECK(!TimerIsRunning());
239
240 next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE;
241 // If this is an ECH retry, connect to the same server as before.
242 std::optional<TransportConnectJob::EndpointResultOverride>
243 endpoint_result_override;
244 if (ech_retry_configs_) {
245 DCHECK(ssl_client_context()->config().ech_enabled);
246 DCHECK(endpoint_result_);
247 endpoint_result_override.emplace(*endpoint_result_, dns_aliases_);
248 }
249 nested_connect_job_ = std::make_unique<TransportConnectJob>(
250 priority(), socket_tag(), common_connect_job_params(),
251 params_->GetDirectConnectionParams(), this, &net_log(),
252 std::move(endpoint_result_override));
253 return nested_connect_job_->Connect();
254 }
255
DoTransportConnectComplete(int result)256 int SSLConnectJob::DoTransportConnectComplete(int result) {
257 resolve_error_info_ = nested_connect_job_->GetResolveErrorInfo();
258 ConnectionAttempts connection_attempts =
259 nested_connect_job_->GetConnectionAttempts();
260 connection_attempts_.insert(connection_attempts_.end(),
261 connection_attempts.begin(),
262 connection_attempts.end());
263 if (result == OK) {
264 next_state_ = STATE_SSL_CONNECT;
265 nested_socket_ = nested_connect_job_->PassSocket();
266 nested_socket_->GetPeerAddress(&server_address_);
267 dns_aliases_ = nested_socket_->GetDnsAliases();
268 }
269
270 return result;
271 }
272
DoSOCKSConnect()273 int SSLConnectJob::DoSOCKSConnect() {
274 DCHECK(!nested_connect_job_);
275 DCHECK(params_->GetSocksProxyConnectionParams());
276 DCHECK(!TimerIsRunning());
277
278 next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
279 nested_connect_job_ = std::make_unique<SOCKSConnectJob>(
280 priority(), socket_tag(), common_connect_job_params(),
281 params_->GetSocksProxyConnectionParams(), this, &net_log());
282 return nested_connect_job_->Connect();
283 }
284
DoSOCKSConnectComplete(int result)285 int SSLConnectJob::DoSOCKSConnectComplete(int result) {
286 resolve_error_info_ = nested_connect_job_->GetResolveErrorInfo();
287 if (result == OK) {
288 next_state_ = STATE_SSL_CONNECT;
289 nested_socket_ = nested_connect_job_->PassSocket();
290 }
291
292 return result;
293 }
294
DoTunnelConnect()295 int SSLConnectJob::DoTunnelConnect() {
296 DCHECK(!nested_connect_job_);
297 DCHECK(params_->GetHttpProxyConnectionParams());
298 DCHECK(!TimerIsRunning());
299
300 next_state_ = STATE_TUNNEL_CONNECT_COMPLETE;
301 nested_connect_job_ = std::make_unique<HttpProxyConnectJob>(
302 priority(), socket_tag(), common_connect_job_params(),
303 params_->GetHttpProxyConnectionParams(), this, &net_log());
304 return nested_connect_job_->Connect();
305 }
306
DoTunnelConnectComplete(int result)307 int SSLConnectJob::DoTunnelConnectComplete(int result) {
308 resolve_error_info_ = nested_connect_job_->GetResolveErrorInfo();
309 nested_socket_ = nested_connect_job_->PassSocket();
310
311 if (result < 0) {
312 // Extract the information needed to prompt for appropriate proxy
313 // authentication so that when ClientSocketPoolBaseHelper calls
314 // |GetAdditionalErrorState|, we can easily set the state.
315 if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
316 ssl_cert_request_info_ = nested_connect_job_->GetCertRequestInfo();
317 }
318 return result;
319 }
320
321 next_state_ = STATE_SSL_CONNECT;
322 return result;
323 }
324
DoSSLConnect()325 int SSLConnectJob::DoSSLConnect() {
326 TRACE_EVENT0(NetTracingCategory(), "SSLConnectJob::DoSSLConnect");
327 DCHECK(!TimerIsRunning());
328
329 next_state_ = STATE_SSL_CONNECT_COMPLETE;
330
331 // Set the timeout to just the time allowed for the SSL handshake.
332 ResetTimer(kSSLHandshakeTimeout);
333
334 // Get the transport's connect start and DNS times.
335 const LoadTimingInfo::ConnectTiming& socket_connect_timing =
336 nested_connect_job_->connect_timing();
337
338 // Overwriting |connect_start| serves two purposes - it adjusts timing so
339 // |connect_start| doesn't include dns times, and it adjusts the time so
340 // as not to include time spent waiting for an idle socket.
341 connect_timing_.connect_start = socket_connect_timing.connect_start;
342 connect_timing_.domain_lookup_start =
343 socket_connect_timing.domain_lookup_start;
344 connect_timing_.domain_lookup_end = socket_connect_timing.domain_lookup_end;
345
346 ssl_negotiation_started_ = true;
347 connect_timing_.ssl_start = base::TimeTicks::Now();
348
349 // Save the `HostResolverEndpointResult`. `nested_connect_job_` is destroyed
350 // at the end of this function.
351 endpoint_result_ = nested_connect_job_->GetHostResolverEndpointResult();
352
353 SSLConfig ssl_config = params_->ssl_config();
354 ssl_config.ignore_certificate_errors =
355 *common_connect_job_params()->ignore_certificate_errors;
356 ssl_config.network_anonymization_key = params_->network_anonymization_key();
357
358 if (ssl_client_context()->config().ech_enabled) {
359 if (ech_retry_configs_) {
360 ssl_config.ech_config_list = *ech_retry_configs_;
361 } else if (endpoint_result_) {
362 ssl_config.ech_config_list = endpoint_result_->metadata.ech_config_list;
363 }
364 if (!ssl_config.ech_config_list.empty()) {
365 // Overriding the DNS lookup only works for direct connections. We
366 // currently do not support ECH with other connection types.
367 DCHECK_EQ(params_->GetConnectionType(), SSLSocketParams::DIRECT);
368 }
369 }
370
371 ssl_socket_ = client_socket_factory()->CreateSSLClientSocket(
372 ssl_client_context(), std::move(nested_socket_), params_->host_and_port(),
373 ssl_config);
374 nested_connect_job_.reset();
375 return ssl_socket_->Connect(callback_);
376 }
377
DoSSLConnectComplete(int result)378 int SSLConnectJob::DoSSLConnectComplete(int result) {
379 connect_timing_.ssl_end = base::TimeTicks::Now();
380
381 if (result != OK && !server_address_.address().empty()) {
382 connection_attempts_.push_back(ConnectionAttempt(server_address_, result));
383 server_address_ = IPEndPoint();
384 }
385
386 // Historically, many servers which negotiated SHA-1 server signatures in
387 // TLS 1.2 actually support SHA-2 but preferentially sign SHA-1 if available.
388 // In order to get accurate metrics while deprecating SHA-1, we initially
389 // connected with SHA-1 disabled and then retried with enabled.
390 //
391 // SHA-1 is now always disabled, but we retained the fallback to separate the
392 // effect of disabling SHA-1 from the effect of having a single automatic
393 // retry on a potentially unreliably network connection.
394 //
395 // TODO(crbug.com/40085786): Remove this now redundant retry.
396 if (disable_legacy_crypto_with_fallback_ &&
397 (result == ERR_CONNECTION_CLOSED || result == ERR_CONNECTION_RESET ||
398 result == ERR_SSL_PROTOCOL_ERROR ||
399 result == ERR_SSL_VERSION_OR_CIPHER_MISMATCH)) {
400 ResetStateForRestart();
401 disable_legacy_crypto_with_fallback_ = false;
402 next_state_ = GetInitialState(params_->GetConnectionType());
403 return OK;
404 }
405
406 // We record metrics based on whether the server advertised ECH support in
407 // DNS. This allows the metrics to measure the same set of servers in both
408 // control and experiment group.
409 const bool is_ech_capable =
410 endpoint_result_ && !endpoint_result_->metadata.ech_config_list.empty();
411 const bool ech_enabled = ssl_client_context()->config().ech_enabled;
412
413 if (!ech_retry_configs_ && result == ERR_ECH_NOT_NEGOTIATED && ech_enabled) {
414 // We used ECH, and the server could not decrypt the ClientHello. However,
415 // it was able to handshake with the public name and send authenticated
416 // retry configs. If this is not the first time around, retry the connection
417 // with the new ECHConfigList, or with ECH disabled (empty retry configs),
418 // as directed.
419 //
420 // See
421 // https://www.ietf.org/archive/id/draft-ietf-tls-esni-13.html#section-6.1.6
422 DCHECK(is_ech_capable);
423 ech_retry_configs_ = ssl_socket_->GetECHRetryConfigs();
424 net_log().AddEvent(
425 NetLogEventType::SSL_CONNECT_JOB_RESTART_WITH_ECH_CONFIG_LIST, [&] {
426 return base::Value::Dict().Set(
427 "bytes", NetLogBinaryValue(*ech_retry_configs_));
428 });
429
430 ResetStateForRestart();
431 next_state_ = GetInitialState(params_->GetConnectionType());
432 return OK;
433 }
434
435 SSLClientSocket::RecordSSLConnectResult(ssl_socket_.get(), result,
436 is_ech_capable, ech_enabled,
437 ech_retry_configs_, connect_timing_);
438
439 if (result == OK || IsCertificateError(result)) {
440 SetSocket(std::move(ssl_socket_), std::move(dns_aliases_));
441 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
442 ssl_cert_request_info_ = base::MakeRefCounted<SSLCertRequestInfo>();
443 ssl_socket_->GetSSLCertRequestInfo(ssl_cert_request_info_.get());
444 }
445
446 return result;
447 }
448
GetInitialState(SSLSocketParams::ConnectionType connection_type)449 SSLConnectJob::State SSLConnectJob::GetInitialState(
450 SSLSocketParams::ConnectionType connection_type) {
451 switch (connection_type) {
452 case SSLSocketParams::DIRECT:
453 return STATE_TRANSPORT_CONNECT;
454 case SSLSocketParams::HTTP_PROXY:
455 return STATE_TUNNEL_CONNECT;
456 case SSLSocketParams::SOCKS_PROXY:
457 return STATE_SOCKS_CONNECT;
458 }
459 NOTREACHED();
460 }
461
ConnectInternal()462 int SSLConnectJob::ConnectInternal() {
463 next_state_ = GetInitialState(params_->GetConnectionType());
464 return DoLoop(OK);
465 }
466
ResetStateForRestart()467 void SSLConnectJob::ResetStateForRestart() {
468 ResetTimer(base::TimeDelta());
469 nested_connect_job_ = nullptr;
470 nested_socket_ = nullptr;
471 ssl_socket_ = nullptr;
472 ssl_cert_request_info_ = nullptr;
473 ssl_negotiation_started_ = false;
474 resolve_error_info_ = ResolveErrorInfo();
475 server_address_ = IPEndPoint();
476 }
477
ChangePriorityInternal(RequestPriority priority)478 void SSLConnectJob::ChangePriorityInternal(RequestPriority priority) {
479 if (nested_connect_job_) {
480 nested_connect_job_->ChangePriority(priority);
481 }
482 }
483
484 } // namespace net
485