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 "base/metrics/histogram_functions.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "net/base/connection_endpoint_metadata.h"
17 #include "net/base/features.h"
18 #include "net/base/host_port_pair.h"
19 #include "net/base/net_errors.h"
20 #include "net/base/trace_constants.h"
21 #include "net/base/tracing.h"
22 #include "net/base/url_util.h"
23 #include "net/cert/x509_util.h"
24 #include "net/http/http_proxy_connect_job.h"
25 #include "net/log/net_log_source_type.h"
26 #include "net/log/net_log_values.h"
27 #include "net/log/net_log_with_source.h"
28 #include "net/socket/client_socket_factory.h"
29 #include "net/socket/client_socket_handle.h"
30 #include "net/socket/socks_connect_job.h"
31 #include "net/socket/ssl_client_socket.h"
32 #include "net/socket/transport_connect_job.h"
33 #include "net/ssl/ssl_cert_request_info.h"
34 #include "net/ssl/ssl_connection_status_flags.h"
35 #include "net/ssl/ssl_info.h"
36 #include "net/ssl/ssl_legacy_crypto_fallback.h"
37 #include "third_party/boringssl/src/include/openssl/pool.h"
38 #include "third_party/boringssl/src/include/openssl/ssl.h"
39
40 namespace net {
41
42 namespace {
43
44 // Timeout for the SSL handshake portion of the connect.
45 constexpr base::TimeDelta kSSLHandshakeTimeout(base::Seconds(30));
46
47 } // namespace
48
SSLSocketParams(scoped_refptr<TransportSocketParams> direct_params,scoped_refptr<SOCKSSocketParams> socks_proxy_params,scoped_refptr<HttpProxySocketParams> http_proxy_params,const HostPortPair & host_and_port,const SSLConfig & ssl_config,PrivacyMode privacy_mode,NetworkAnonymizationKey network_anonymization_key)49 SSLSocketParams::SSLSocketParams(
50 scoped_refptr<TransportSocketParams> direct_params,
51 scoped_refptr<SOCKSSocketParams> socks_proxy_params,
52 scoped_refptr<HttpProxySocketParams> http_proxy_params,
53 const HostPortPair& host_and_port,
54 const SSLConfig& ssl_config,
55 PrivacyMode privacy_mode,
56 NetworkAnonymizationKey network_anonymization_key)
57 : direct_params_(std::move(direct_params)),
58 socks_proxy_params_(std::move(socks_proxy_params)),
59 http_proxy_params_(std::move(http_proxy_params)),
60 host_and_port_(host_and_port),
61 ssl_config_(ssl_config),
62 privacy_mode_(privacy_mode),
63 network_anonymization_key_(network_anonymization_key) {
64 // Only one set of lower level ConnectJob params should be non-NULL.
65 DCHECK((direct_params_ && !socks_proxy_params_ && !http_proxy_params_) ||
66 (!direct_params_ && socks_proxy_params_ && !http_proxy_params_) ||
67 (!direct_params_ && !socks_proxy_params_ && http_proxy_params_));
68 }
69
70 SSLSocketParams::~SSLSocketParams() = default;
71
GetConnectionType() const72 SSLSocketParams::ConnectionType SSLSocketParams::GetConnectionType() const {
73 if (direct_params_.get()) {
74 DCHECK(!socks_proxy_params_.get());
75 DCHECK(!http_proxy_params_.get());
76 return DIRECT;
77 }
78
79 if (socks_proxy_params_.get()) {
80 DCHECK(!http_proxy_params_.get());
81 return SOCKS_PROXY;
82 }
83
84 DCHECK(http_proxy_params_.get());
85 return HTTP_PROXY;
86 }
87
88 const scoped_refptr<TransportSocketParams>&
GetDirectConnectionParams() const89 SSLSocketParams::GetDirectConnectionParams() const {
90 DCHECK_EQ(GetConnectionType(), DIRECT);
91 return direct_params_;
92 }
93
94 const scoped_refptr<SOCKSSocketParams>&
GetSocksProxyConnectionParams() const95 SSLSocketParams::GetSocksProxyConnectionParams() const {
96 DCHECK_EQ(GetConnectionType(), SOCKS_PROXY);
97 return socks_proxy_params_;
98 }
99
100 const scoped_refptr<HttpProxySocketParams>&
GetHttpProxyConnectionParams() const101 SSLSocketParams::GetHttpProxyConnectionParams() const {
102 DCHECK_EQ(GetConnectionType(), HTTP_PROXY);
103 return http_proxy_params_;
104 }
105
Create(RequestPriority priority,const SocketTag & socket_tag,const CommonConnectJobParams * common_connect_job_params,scoped_refptr<SSLSocketParams> params,ConnectJob::Delegate * delegate,const NetLogWithSource * net_log)106 std::unique_ptr<SSLConnectJob> SSLConnectJob::Factory::Create(
107 RequestPriority priority,
108 const SocketTag& socket_tag,
109 const CommonConnectJobParams* common_connect_job_params,
110 scoped_refptr<SSLSocketParams> params,
111 ConnectJob::Delegate* delegate,
112 const NetLogWithSource* net_log) {
113 return std::make_unique<SSLConnectJob>(priority, socket_tag,
114 common_connect_job_params,
115 std::move(params), delegate, net_log);
116 }
117
SSLConnectJob(RequestPriority priority,const SocketTag & socket_tag,const CommonConnectJobParams * common_connect_job_params,scoped_refptr<SSLSocketParams> params,ConnectJob::Delegate * delegate,const NetLogWithSource * net_log)118 SSLConnectJob::SSLConnectJob(
119 RequestPriority priority,
120 const SocketTag& socket_tag,
121 const CommonConnectJobParams* common_connect_job_params,
122 scoped_refptr<SSLSocketParams> params,
123 ConnectJob::Delegate* delegate,
124 const NetLogWithSource* net_log)
125 : ConnectJob(
126 priority,
127 socket_tag,
128 // The SSLConnectJob's timer is only started during the SSL handshake.
129 base::TimeDelta(),
130 common_connect_job_params,
131 delegate,
132 net_log,
133 NetLogSourceType::SSL_CONNECT_JOB,
134 NetLogEventType::SSL_CONNECT_JOB_CONNECT),
135 params_(std::move(params)),
136 callback_(base::BindRepeating(&SSLConnectJob::OnIOComplete,
137 base::Unretained(this))) {}
138
~SSLConnectJob()139 SSLConnectJob::~SSLConnectJob() {
140 // In the case the job was canceled, need to delete nested job first to
141 // correctly order NetLog events.
142 nested_connect_job_.reset();
143 }
144
GetLoadState() const145 LoadState SSLConnectJob::GetLoadState() const {
146 switch (next_state_) {
147 case STATE_TRANSPORT_CONNECT:
148 case STATE_SOCKS_CONNECT:
149 case STATE_TUNNEL_CONNECT:
150 return LOAD_STATE_IDLE;
151 case STATE_TRANSPORT_CONNECT_COMPLETE:
152 case STATE_SOCKS_CONNECT_COMPLETE:
153 return nested_connect_job_->GetLoadState();
154 case STATE_TUNNEL_CONNECT_COMPLETE:
155 if (nested_socket_)
156 return LOAD_STATE_ESTABLISHING_PROXY_TUNNEL;
157 return nested_connect_job_->GetLoadState();
158 case STATE_SSL_CONNECT:
159 case STATE_SSL_CONNECT_COMPLETE:
160 return LOAD_STATE_SSL_HANDSHAKE;
161 default:
162 NOTREACHED();
163 return LOAD_STATE_IDLE;
164 }
165 }
166
HasEstablishedConnection() const167 bool SSLConnectJob::HasEstablishedConnection() const {
168 // If waiting on a nested ConnectJob, defer to that ConnectJob's state.
169 if (nested_connect_job_)
170 return nested_connect_job_->HasEstablishedConnection();
171 // Otherwise, return true if a socket has been created.
172 return nested_socket_ || ssl_socket_;
173 }
174
OnConnectJobComplete(int result,ConnectJob * job)175 void SSLConnectJob::OnConnectJobComplete(int result, ConnectJob* job) {
176 DCHECK_EQ(job, nested_connect_job_.get());
177 OnIOComplete(result);
178 }
179
OnNeedsProxyAuth(const HttpResponseInfo & response,HttpAuthController * auth_controller,base::OnceClosure restart_with_auth_callback,ConnectJob * job)180 void SSLConnectJob::OnNeedsProxyAuth(
181 const HttpResponseInfo& response,
182 HttpAuthController* auth_controller,
183 base::OnceClosure restart_with_auth_callback,
184 ConnectJob* job) {
185 DCHECK_EQ(next_state_, STATE_TUNNEL_CONNECT_COMPLETE);
186
187 // The timer shouldn't have started running yet, since the handshake only
188 // starts after a tunnel has been established through the proxy.
189 DCHECK(!TimerIsRunning());
190
191 // Just pass the callback up to the consumer. This class doesn't need to do
192 // anything once credentials are provided.
193 NotifyDelegateOfProxyAuth(response, auth_controller,
194 std::move(restart_with_auth_callback));
195 }
196
GetConnectionAttempts() const197 ConnectionAttempts SSLConnectJob::GetConnectionAttempts() const {
198 return connection_attempts_;
199 }
200
GetResolveErrorInfo() const201 ResolveErrorInfo SSLConnectJob::GetResolveErrorInfo() const {
202 return resolve_error_info_;
203 }
204
IsSSLError() const205 bool SSLConnectJob::IsSSLError() const {
206 return ssl_negotiation_started_;
207 }
208
GetCertRequestInfo()209 scoped_refptr<SSLCertRequestInfo> SSLConnectJob::GetCertRequestInfo() {
210 return ssl_cert_request_info_;
211 }
212
HandshakeTimeoutForTesting()213 base::TimeDelta SSLConnectJob::HandshakeTimeoutForTesting() {
214 return kSSLHandshakeTimeout;
215 }
216
OnIOComplete(int result)217 void SSLConnectJob::OnIOComplete(int result) {
218 int rv = DoLoop(result);
219 if (rv != ERR_IO_PENDING)
220 NotifyDelegateOfCompletion(rv); // Deletes |this|.
221 }
222
DoLoop(int result)223 int SSLConnectJob::DoLoop(int result) {
224 TRACE_EVENT0(NetTracingCategory(), "SSLConnectJob::DoLoop");
225 DCHECK_NE(next_state_, STATE_NONE);
226
227 int rv = result;
228 do {
229 State state = next_state_;
230 next_state_ = STATE_NONE;
231 switch (state) {
232 case STATE_TRANSPORT_CONNECT:
233 DCHECK_EQ(OK, rv);
234 rv = DoTransportConnect();
235 break;
236 case STATE_TRANSPORT_CONNECT_COMPLETE:
237 rv = DoTransportConnectComplete(rv);
238 break;
239 case STATE_SOCKS_CONNECT:
240 DCHECK_EQ(OK, rv);
241 rv = DoSOCKSConnect();
242 break;
243 case STATE_SOCKS_CONNECT_COMPLETE:
244 rv = DoSOCKSConnectComplete(rv);
245 break;
246 case STATE_TUNNEL_CONNECT:
247 DCHECK_EQ(OK, rv);
248 rv = DoTunnelConnect();
249 break;
250 case STATE_TUNNEL_CONNECT_COMPLETE:
251 rv = DoTunnelConnectComplete(rv);
252 break;
253 case STATE_SSL_CONNECT:
254 DCHECK_EQ(OK, rv);
255 rv = DoSSLConnect();
256 break;
257 case STATE_SSL_CONNECT_COMPLETE:
258 rv = DoSSLConnectComplete(rv);
259 break;
260 default:
261 NOTREACHED() << "bad state";
262 rv = ERR_FAILED;
263 break;
264 }
265 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
266
267 return rv;
268 }
269
DoTransportConnect()270 int SSLConnectJob::DoTransportConnect() {
271 DCHECK(!nested_connect_job_);
272 DCHECK(params_->GetDirectConnectionParams());
273 DCHECK(!TimerIsRunning());
274
275 next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE;
276 // If this is an ECH retry, connect to the same server as before.
277 absl::optional<TransportConnectJob::EndpointResultOverride>
278 endpoint_result_override;
279 if (ech_retry_configs_) {
280 DCHECK(ssl_client_context()->config().EncryptedClientHelloEnabled());
281 DCHECK(endpoint_result_);
282 endpoint_result_override.emplace(*endpoint_result_, dns_aliases_);
283 }
284 nested_connect_job_ = std::make_unique<TransportConnectJob>(
285 priority(), socket_tag(), common_connect_job_params(),
286 params_->GetDirectConnectionParams(), this, &net_log(),
287 std::move(endpoint_result_override));
288 return nested_connect_job_->Connect();
289 }
290
DoTransportConnectComplete(int result)291 int SSLConnectJob::DoTransportConnectComplete(int result) {
292 resolve_error_info_ = nested_connect_job_->GetResolveErrorInfo();
293 ConnectionAttempts connection_attempts =
294 nested_connect_job_->GetConnectionAttempts();
295 connection_attempts_.insert(connection_attempts_.end(),
296 connection_attempts.begin(),
297 connection_attempts.end());
298 if (result == OK) {
299 next_state_ = STATE_SSL_CONNECT;
300 nested_socket_ = nested_connect_job_->PassSocket();
301 nested_socket_->GetPeerAddress(&server_address_);
302 dns_aliases_ = nested_socket_->GetDnsAliases();
303 }
304
305 return result;
306 }
307
DoSOCKSConnect()308 int SSLConnectJob::DoSOCKSConnect() {
309 DCHECK(!nested_connect_job_);
310 DCHECK(params_->GetSocksProxyConnectionParams());
311 DCHECK(!TimerIsRunning());
312
313 next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
314 nested_connect_job_ = std::make_unique<SOCKSConnectJob>(
315 priority(), socket_tag(), common_connect_job_params(),
316 params_->GetSocksProxyConnectionParams(), this, &net_log());
317 return nested_connect_job_->Connect();
318 }
319
DoSOCKSConnectComplete(int result)320 int SSLConnectJob::DoSOCKSConnectComplete(int result) {
321 resolve_error_info_ = nested_connect_job_->GetResolveErrorInfo();
322 if (result == OK) {
323 next_state_ = STATE_SSL_CONNECT;
324 nested_socket_ = nested_connect_job_->PassSocket();
325 }
326
327 return result;
328 }
329
DoTunnelConnect()330 int SSLConnectJob::DoTunnelConnect() {
331 DCHECK(!nested_connect_job_);
332 DCHECK(params_->GetHttpProxyConnectionParams());
333 DCHECK(!TimerIsRunning());
334
335 next_state_ = STATE_TUNNEL_CONNECT_COMPLETE;
336 scoped_refptr<HttpProxySocketParams> http_proxy_params =
337 params_->GetHttpProxyConnectionParams();
338 nested_connect_job_ = std::make_unique<HttpProxyConnectJob>(
339 priority(), socket_tag(), common_connect_job_params(),
340 params_->GetHttpProxyConnectionParams(), this, &net_log());
341 return nested_connect_job_->Connect();
342 }
343
DoTunnelConnectComplete(int result)344 int SSLConnectJob::DoTunnelConnectComplete(int result) {
345 resolve_error_info_ = nested_connect_job_->GetResolveErrorInfo();
346 nested_socket_ = nested_connect_job_->PassSocket();
347
348 if (result < 0) {
349 // Extract the information needed to prompt for appropriate proxy
350 // authentication so that when ClientSocketPoolBaseHelper calls
351 // |GetAdditionalErrorState|, we can easily set the state.
352 if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
353 ssl_cert_request_info_ = nested_connect_job_->GetCertRequestInfo();
354 }
355 return result;
356 }
357
358 next_state_ = STATE_SSL_CONNECT;
359 return result;
360 }
361
DoSSLConnect()362 int SSLConnectJob::DoSSLConnect() {
363 TRACE_EVENT0(NetTracingCategory(), "SSLConnectJob::DoSSLConnect");
364 DCHECK(!TimerIsRunning());
365
366 next_state_ = STATE_SSL_CONNECT_COMPLETE;
367
368 // Set the timeout to just the time allowed for the SSL handshake.
369 ResetTimer(kSSLHandshakeTimeout);
370
371 // Get the transport's connect start and DNS times.
372 const LoadTimingInfo::ConnectTiming& socket_connect_timing =
373 nested_connect_job_->connect_timing();
374
375 // Overwriting |connect_start| serves two purposes - it adjusts timing so
376 // |connect_start| doesn't include dns times, and it adjusts the time so
377 // as not to include time spent waiting for an idle socket.
378 connect_timing_.connect_start = socket_connect_timing.connect_start;
379 connect_timing_.domain_lookup_start =
380 socket_connect_timing.domain_lookup_start;
381 connect_timing_.domain_lookup_end = socket_connect_timing.domain_lookup_end;
382
383 ssl_negotiation_started_ = true;
384 connect_timing_.ssl_start = base::TimeTicks::Now();
385
386 // Save the `HostResolverEndpointResult`. `nested_connect_job_` is destroyed
387 // at the end of this function.
388 endpoint_result_ = nested_connect_job_->GetHostResolverEndpointResult();
389
390 SSLConfig ssl_config = params_->ssl_config();
391 ssl_config.network_anonymization_key = params_->network_anonymization_key();
392 ssl_config.privacy_mode = params_->privacy_mode();
393 // We do the fallback in both cases here to ensure we separate the effect of
394 // disabling sha1 from the effect of having a single automatic retry
395 // on a potentially unreliably network connection.
396 ssl_config.disable_sha1_server_signatures =
397 disable_legacy_crypto_with_fallback_ ||
398 !ssl_client_context()->config().InsecureHashesInTLSHandshakesEnabled();
399
400 if (ssl_client_context()->config().EncryptedClientHelloEnabled()) {
401 if (ech_retry_configs_) {
402 ssl_config.ech_config_list = *ech_retry_configs_;
403 } else if (endpoint_result_) {
404 ssl_config.ech_config_list = endpoint_result_->metadata.ech_config_list;
405 }
406 if (!ssl_config.ech_config_list.empty()) {
407 // Overriding the DNS lookup only works for direct connections. We
408 // currently do not support ECH with other connection types.
409 DCHECK_EQ(params_->GetConnectionType(), SSLSocketParams::DIRECT);
410 }
411 }
412
413 ssl_socket_ = client_socket_factory()->CreateSSLClientSocket(
414 ssl_client_context(), std::move(nested_socket_), params_->host_and_port(),
415 ssl_config);
416 nested_connect_job_.reset();
417 return ssl_socket_->Connect(callback_);
418 }
419
DoSSLConnectComplete(int result)420 int SSLConnectJob::DoSSLConnectComplete(int result) {
421 connect_timing_.ssl_end = base::TimeTicks::Now();
422
423 if (result != OK && !server_address_.address().empty()) {
424 connection_attempts_.push_back(ConnectionAttempt(server_address_, result));
425 server_address_ = IPEndPoint();
426 }
427
428 // Many servers which negotiate SHA-1 server signatures in TLS 1.2 actually
429 // support SHA-2 but preferentially sign SHA-1 if available.
430 //
431 // To get more accurate metrics, initially connect with SHA-1 disabled. If
432 // this fails, retry with them enabled. This keeps the legacy algorithms
433 // working for now, but they will only appear in metrics and DevTools if the
434 // site relies on them.
435 //
436 // See https://crbug.com/658905.
437 if (disable_legacy_crypto_with_fallback_ &&
438 (result == ERR_CONNECTION_CLOSED || result == ERR_CONNECTION_RESET ||
439 result == ERR_SSL_PROTOCOL_ERROR ||
440 result == ERR_SSL_VERSION_OR_CIPHER_MISMATCH)) {
441 ResetStateForRestart();
442 disable_legacy_crypto_with_fallback_ = false;
443 next_state_ = GetInitialState(params_->GetConnectionType());
444 return OK;
445 }
446
447 // We record metrics based on whether the server advertised ECH support in
448 // DNS. This allows the metrics to measure the same set of servers in both
449 // control and experiment group.
450 const bool is_ech_capable =
451 endpoint_result_ && !endpoint_result_->metadata.ech_config_list.empty();
452
453 if (!ech_retry_configs_ && result == ERR_ECH_NOT_NEGOTIATED &&
454 ssl_client_context()->config().EncryptedClientHelloEnabled()) {
455 // We used ECH, and the server could not decrypt the ClientHello. However,
456 // it was able to handshake with the public name and send authenticated
457 // retry configs. If this is not the first time around, retry the connection
458 // with the new ECHConfigList, or with ECH disabled (empty retry configs),
459 // as directed.
460 //
461 // See
462 // https://www.ietf.org/archive/id/draft-ietf-tls-esni-13.html#section-6.1.6
463 DCHECK(is_ech_capable);
464 ech_retry_configs_ = ssl_socket_->GetECHRetryConfigs();
465 net_log().AddEvent(
466 NetLogEventType::SSL_CONNECT_JOB_RESTART_WITH_ECH_CONFIG_LIST, [&] {
467 base::Value::Dict dict;
468 dict.Set("bytes", NetLogBinaryValue(*ech_retry_configs_));
469 return dict;
470 });
471
472 // TODO(https://crbug.com/1091403): Add histograms for how often this
473 // happens.
474 ResetStateForRestart();
475 next_state_ = GetInitialState(params_->GetConnectionType());
476 return OK;
477 }
478
479 const std::string& host = params_->host_and_port().host();
480 if (is_ech_capable &&
481 base::FeatureList::IsEnabled(features::kEncryptedClientHello)) {
482 // These values are persisted to logs. Entries should not be renumbered
483 // and numeric values should never be reused.
484 enum class ECHResult {
485 // The connection succeeded on the initial connection.
486 kSuccessInitial = 0,
487 // The connection failed on the initial connection, without providing
488 // retry configs.
489 kErrorInitial = 1,
490 // The connection succeeded after getting retry configs.
491 kSuccessRetry = 2,
492 // The connection failed after getting retry configs.
493 kErrorRetry = 3,
494 // The connection succeeded after getting a rollback signal.
495 kSuccessRollback = 4,
496 // The connection failed after getting a rollback signal.
497 kErrorRollback = 5,
498 kMaxValue = kErrorRollback,
499 };
500 const bool is_ok = result == OK;
501 ECHResult ech_result;
502 if (!ech_retry_configs_.has_value()) {
503 ech_result =
504 is_ok ? ECHResult::kSuccessInitial : ECHResult::kErrorInitial;
505 } else if (ech_retry_configs_->empty()) {
506 ech_result =
507 is_ok ? ECHResult::kSuccessRollback : ECHResult::kErrorRollback;
508 } else {
509 ech_result = is_ok ? ECHResult::kSuccessRetry : ECHResult::kErrorRetry;
510 }
511 base::UmaHistogramEnumeration("Net.SSL.ECHResult", ech_result);
512 }
513
514 if (result == OK) {
515 DCHECK(!connect_timing_.ssl_start.is_null());
516 base::TimeDelta connect_duration =
517 connect_timing_.ssl_end - connect_timing_.ssl_start;
518 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_2", connect_duration,
519 base::Milliseconds(1), base::Minutes(1), 100);
520 if (is_ech_capable) {
521 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_ECH",
522 connect_duration, base::Milliseconds(1),
523 base::Minutes(1), 100);
524 }
525
526 SSLInfo ssl_info;
527 bool has_ssl_info = ssl_socket_->GetSSLInfo(&ssl_info);
528 DCHECK(has_ssl_info);
529
530 SSLVersion version =
531 SSLConnectionStatusToVersion(ssl_info.connection_status);
532 UMA_HISTOGRAM_ENUMERATION("Net.SSLVersion", version,
533 SSL_CONNECTION_VERSION_MAX);
534 if (IsGoogleHost(host)) {
535 // Google hosts all support TLS 1.2, so any occurrences of TLS 1.0 or TLS
536 // 1.1 will be from an outdated insecure TLS MITM proxy, such as some
537 // antivirus configurations. TLS 1.0 and 1.1 are deprecated, so record
538 // these to see how prevalent they are. See https://crbug.com/896013.
539 UMA_HISTOGRAM_ENUMERATION("Net.SSLVersionGoogle", version,
540 SSL_CONNECTION_VERSION_MAX);
541 }
542
543 uint16_t cipher_suite =
544 SSLConnectionStatusToCipherSuite(ssl_info.connection_status);
545 base::UmaHistogramSparse("Net.SSL_CipherSuite", cipher_suite);
546
547 if (ssl_info.key_exchange_group != 0) {
548 base::UmaHistogramSparse("Net.SSL_KeyExchange.ECDHE",
549 ssl_info.key_exchange_group);
550 }
551
552 // Classify whether the connection required the legacy crypto fallback.
553 SSLLegacyCryptoFallback fallback = SSLLegacyCryptoFallback::kNoFallback;
554 if (!disable_legacy_crypto_with_fallback_) {
555 // Some servers, though they do not negotiate SHA-1, still fail the
556 // connection when SHA-1 is not offered. We believe these are servers
557 // which match the sent certificates against the ClientHello and then
558 // are configured with a SHA-1 certificate.
559 //
560 // SHA-1 certificate chains are no longer accepted, however servers may
561 // send extra unused certificates, most commonly a copy of the trust
562 // anchor. We only need to check for RSASSA-PKCS1-v1_5 signatures, because
563 // other SHA-1 signature types have already been removed from the
564 // ClientHello.
565 bool sent_sha1_cert = ssl_info.unverified_cert &&
566 x509_util::HasRsaPkcs1Sha1Signature(
567 ssl_info.unverified_cert->cert_buffer());
568 if (!sent_sha1_cert && ssl_info.unverified_cert) {
569 for (const auto& cert :
570 ssl_info.unverified_cert->intermediate_buffers()) {
571 if (x509_util::HasRsaPkcs1Sha1Signature(cert.get())) {
572 sent_sha1_cert = true;
573 break;
574 }
575 }
576 }
577 if (ssl_info.peer_signature_algorithm == SSL_SIGN_RSA_PKCS1_SHA1) {
578 fallback = sent_sha1_cert
579 ? SSLLegacyCryptoFallback::kSentSHA1CertAndUsedSHA1
580 : SSLLegacyCryptoFallback::kUsedSHA1;
581 } else {
582 fallback = sent_sha1_cert ? SSLLegacyCryptoFallback::kSentSHA1Cert
583 : SSLLegacyCryptoFallback::kUnknownReason;
584 }
585 }
586 UMA_HISTOGRAM_ENUMERATION("Net.SSLLegacyCryptoFallback2", fallback);
587 }
588
589 base::UmaHistogramSparse("Net.SSL_Connection_Error", std::abs(result));
590 if (is_ech_capable) {
591 base::UmaHistogramSparse("Net.SSL_Connection_Error_ECH", std::abs(result));
592 }
593
594 if (result == OK || IsCertificateError(result)) {
595 SetSocket(std::move(ssl_socket_), std::move(dns_aliases_));
596 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
597 ssl_cert_request_info_ = base::MakeRefCounted<SSLCertRequestInfo>();
598 ssl_socket_->GetSSLCertRequestInfo(ssl_cert_request_info_.get());
599 }
600
601 return result;
602 }
603
GetInitialState(SSLSocketParams::ConnectionType connection_type)604 SSLConnectJob::State SSLConnectJob::GetInitialState(
605 SSLSocketParams::ConnectionType connection_type) {
606 switch (connection_type) {
607 case SSLSocketParams::DIRECT:
608 return STATE_TRANSPORT_CONNECT;
609 case SSLSocketParams::HTTP_PROXY:
610 return STATE_TUNNEL_CONNECT;
611 case SSLSocketParams::SOCKS_PROXY:
612 return STATE_SOCKS_CONNECT;
613 }
614 NOTREACHED();
615 return STATE_NONE;
616 }
617
ConnectInternal()618 int SSLConnectJob::ConnectInternal() {
619 next_state_ = GetInitialState(params_->GetConnectionType());
620 return DoLoop(OK);
621 }
622
ResetStateForRestart()623 void SSLConnectJob::ResetStateForRestart() {
624 ResetTimer(base::TimeDelta());
625 nested_connect_job_ = nullptr;
626 nested_socket_ = nullptr;
627 ssl_socket_ = nullptr;
628 ssl_cert_request_info_ = nullptr;
629 ssl_negotiation_started_ = false;
630 resolve_error_info_ = ResolveErrorInfo();
631 server_address_ = IPEndPoint();
632 }
633
ChangePriorityInternal(RequestPriority priority)634 void SSLConnectJob::ChangePriorityInternal(RequestPriority priority) {
635 if (nested_connect_job_)
636 nested_connect_job_->ChangePriority(priority);
637 }
638
639 } // namespace net
640