• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_client_socket.h"
6 
7 #include <string>
8 
9 #include "base/containers/flat_tree.h"
10 #include "base/logging.h"
11 #include "base/metrics/histogram_functions.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/observer_list.h"
14 #include "base/values.h"
15 #include "net/cert/x509_certificate_net_log_param.h"
16 #include "net/log/net_log.h"
17 #include "net/log/net_log_event_type.h"
18 #include "net/socket/ssl_client_socket_impl.h"
19 #include "net/socket/stream_socket.h"
20 #include "net/ssl/ssl_client_session_cache.h"
21 #include "net/ssl/ssl_connection_status_flags.h"
22 #include "net/ssl/ssl_info.h"
23 #include "net/ssl/ssl_key_logger.h"
24 
25 namespace net {
26 
27 namespace {
28 
29 // Returns true if |first_cert| and |second_cert| represent the same certificate
30 // (with the same chain), or if they're both NULL.
AreCertificatesEqual(const scoped_refptr<X509Certificate> & first_cert,const scoped_refptr<X509Certificate> & second_cert,bool include_chain=true)31 bool AreCertificatesEqual(const scoped_refptr<X509Certificate>& first_cert,
32                           const scoped_refptr<X509Certificate>& second_cert,
33                           bool include_chain = true) {
34   return (!first_cert && !second_cert) ||
35          (first_cert && second_cert &&
36           (include_chain
37                ? first_cert->EqualsIncludingChain(second_cert.get())
38                : first_cert->EqualsExcludingChain(second_cert.get())));
39 }
40 
41 // Returns a base::Value::Dict value NetLog parameter with the expected format
42 // for events of type CLEAR_CACHED_CLIENT_CERT.
NetLogClearCachedClientCertParams(const net::HostPortPair & host,const scoped_refptr<net::X509Certificate> & cert,bool is_cleared)43 base::Value::Dict NetLogClearCachedClientCertParams(
44     const net::HostPortPair& host,
45     const scoped_refptr<net::X509Certificate>& cert,
46     bool is_cleared) {
47   return base::Value::Dict()
48       .Set("host", host.ToString())
49       .Set("certificates", cert ? net::NetLogX509CertificateList(cert.get())
50                                 : base::Value(base::Value::List()))
51       .Set("is_cleared", is_cleared);
52 }
53 
54 // Returns a base::Value::Dict value NetLog parameter with the expected format
55 // for events of type CLEAR_MATCHING_CACHED_CLIENT_CERT.
NetLogClearMatchingCachedClientCertParams(const base::flat_set<net::HostPortPair> & hosts,const scoped_refptr<net::X509Certificate> & cert)56 base::Value::Dict NetLogClearMatchingCachedClientCertParams(
57     const base::flat_set<net::HostPortPair>& hosts,
58     const scoped_refptr<net::X509Certificate>& cert) {
59   base::Value::List hosts_values;
60   for (const auto& host : hosts) {
61     hosts_values.Append(host.ToString());
62   }
63 
64   return base::Value::Dict()
65       .Set("hosts", base::Value(std::move(hosts_values)))
66       .Set("certificates", cert ? net::NetLogX509CertificateList(cert.get())
67                                 : base::Value(base::Value::List()));
68 }
69 
70 }  // namespace
71 
72 // static
RecordSSLConnectResult(SSLClientSocket * ssl_socket,int result,bool is_ech_capable,bool ech_enabled,const std::optional<std::vector<uint8_t>> & ech_retry_configs,const LoadTimingInfo::ConnectTiming & connect_timing)73 void SSLClientSocket::RecordSSLConnectResult(
74     SSLClientSocket* ssl_socket,
75     int result,
76     bool is_ech_capable,
77     bool ech_enabled,
78     const std::optional<std::vector<uint8_t>>& ech_retry_configs,
79     const LoadTimingInfo::ConnectTiming& connect_timing) {
80   if (is_ech_capable && ech_enabled) {
81     // These values are persisted to logs. Entries should not be renumbered
82     // and numeric values should never be reused.
83     enum class ECHResult {
84       // The connection succeeded on the initial connection.
85       kSuccessInitial = 0,
86       // The connection failed on the initial connection, without providing
87       // retry configs.
88       kErrorInitial = 1,
89       // The connection succeeded after getting retry configs.
90       kSuccessRetry = 2,
91       // The connection failed after getting retry configs.
92       kErrorRetry = 3,
93       // The connection succeeded after getting a rollback signal.
94       kSuccessRollback = 4,
95       // The connection failed after getting a rollback signal.
96       kErrorRollback = 5,
97       kMaxValue = kErrorRollback,
98     };
99     const bool is_ok = result == OK;
100     ECHResult ech_result;
101     if (!ech_retry_configs.has_value()) {
102       ech_result =
103           is_ok ? ECHResult::kSuccessInitial : ECHResult::kErrorInitial;
104     } else if (ech_retry_configs->empty()) {
105       ech_result =
106           is_ok ? ECHResult::kSuccessRollback : ECHResult::kErrorRollback;
107     } else {
108       ech_result = is_ok ? ECHResult::kSuccessRetry : ECHResult::kErrorRetry;
109     }
110     base::UmaHistogramEnumeration("Net.SSL.ECHResult", ech_result);
111   }
112 
113   if (result == OK) {
114     DCHECK(!connect_timing.ssl_start.is_null());
115     CHECK(ssl_socket);
116     base::TimeDelta connect_duration =
117         connect_timing.ssl_end - connect_timing.ssl_start;
118     UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_2", connect_duration,
119                                base::Milliseconds(1), base::Minutes(1), 100);
120     if (is_ech_capable) {
121       UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_ECH",
122                                  connect_duration, base::Milliseconds(1),
123                                  base::Minutes(1), 100);
124     }
125 
126     SSLInfo ssl_info;
127     bool has_ssl_info = ssl_socket->GetSSLInfo(&ssl_info);
128     DCHECK(has_ssl_info);
129 
130     SSLVersion version =
131         SSLConnectionStatusToVersion(ssl_info.connection_status);
132     UMA_HISTOGRAM_ENUMERATION("Net.SSLVersion", version,
133                               SSL_CONNECTION_VERSION_MAX);
134 
135     uint16_t cipher_suite =
136         SSLConnectionStatusToCipherSuite(ssl_info.connection_status);
137     base::UmaHistogramSparse("Net.SSL_CipherSuite", cipher_suite);
138 
139     if (ssl_info.key_exchange_group != 0) {
140       base::UmaHistogramSparse("Net.SSL_KeyExchange.ECDHE",
141                                ssl_info.key_exchange_group);
142     }
143   }
144 
145   base::UmaHistogramSparse("Net.SSL_Connection_Error", std::abs(result));
146   if (is_ech_capable) {
147     base::UmaHistogramSparse("Net.SSL_Connection_Error_ECH", std::abs(result));
148   }
149 }
150 
151 SSLClientSocket::SSLClientSocket() = default;
152 
153 // static
SetSSLKeyLogger(std::unique_ptr<SSLKeyLogger> logger)154 void SSLClientSocket::SetSSLKeyLogger(std::unique_ptr<SSLKeyLogger> logger) {
155   SSLClientSocketImpl::SetSSLKeyLogger(std::move(logger));
156 }
157 
158 // static
SerializeNextProtos(const NextProtoVector & next_protos)159 std::vector<uint8_t> SSLClientSocket::SerializeNextProtos(
160     const NextProtoVector& next_protos) {
161   std::vector<uint8_t> wire_protos;
162   for (const NextProto next_proto : next_protos) {
163     const std::string proto = NextProtoToString(next_proto);
164     if (proto.size() > 255) {
165       LOG(WARNING) << "Ignoring overlong ALPN protocol: " << proto;
166       continue;
167     }
168     if (proto.size() == 0) {
169       LOG(WARNING) << "Ignoring empty ALPN protocol";
170       continue;
171     }
172     wire_protos.push_back(proto.size());
173     for (const char ch : proto) {
174       wire_protos.push_back(static_cast<uint8_t>(ch));
175     }
176   }
177 
178   return wire_protos;
179 }
180 
SSLClientContext(SSLConfigService * ssl_config_service,CertVerifier * cert_verifier,TransportSecurityState * transport_security_state,SSLClientSessionCache * ssl_client_session_cache,SCTAuditingDelegate * sct_auditing_delegate)181 SSLClientContext::SSLClientContext(
182     SSLConfigService* ssl_config_service,
183     CertVerifier* cert_verifier,
184     TransportSecurityState* transport_security_state,
185     SSLClientSessionCache* ssl_client_session_cache,
186     SCTAuditingDelegate* sct_auditing_delegate)
187     : ssl_config_service_(ssl_config_service),
188       cert_verifier_(cert_verifier),
189       transport_security_state_(transport_security_state),
190       ssl_client_session_cache_(ssl_client_session_cache),
191       sct_auditing_delegate_(sct_auditing_delegate) {
192   CHECK(cert_verifier_);
193   CHECK(transport_security_state_);
194 
195   if (ssl_config_service_) {
196     config_ = ssl_config_service_->GetSSLContextConfig();
197     ssl_config_service_->AddObserver(this);
198   }
199   cert_verifier_->AddObserver(this);
200   CertDatabase::GetInstance()->AddObserver(this);
201 }
202 
~SSLClientContext()203 SSLClientContext::~SSLClientContext() {
204   if (ssl_config_service_) {
205     ssl_config_service_->RemoveObserver(this);
206   }
207   cert_verifier_->RemoveObserver(this);
208   CertDatabase::GetInstance()->RemoveObserver(this);
209 }
210 
CreateSSLClientSocket(std::unique_ptr<StreamSocket> stream_socket,const HostPortPair & host_and_port,const SSLConfig & ssl_config)211 std::unique_ptr<SSLClientSocket> SSLClientContext::CreateSSLClientSocket(
212     std::unique_ptr<StreamSocket> stream_socket,
213     const HostPortPair& host_and_port,
214     const SSLConfig& ssl_config) {
215   return std::make_unique<SSLClientSocketImpl>(this, std::move(stream_socket),
216                                                host_and_port, ssl_config);
217 }
218 
GetClientCertificate(const HostPortPair & server,scoped_refptr<X509Certificate> * client_cert,scoped_refptr<SSLPrivateKey> * private_key)219 bool SSLClientContext::GetClientCertificate(
220     const HostPortPair& server,
221     scoped_refptr<X509Certificate>* client_cert,
222     scoped_refptr<SSLPrivateKey>* private_key) {
223   return ssl_client_auth_cache_.Lookup(server, client_cert, private_key);
224 }
225 
SetClientCertificate(const HostPortPair & server,scoped_refptr<X509Certificate> client_cert,scoped_refptr<SSLPrivateKey> private_key)226 void SSLClientContext::SetClientCertificate(
227     const HostPortPair& server,
228     scoped_refptr<X509Certificate> client_cert,
229     scoped_refptr<SSLPrivateKey> private_key) {
230   ssl_client_auth_cache_.Add(server, std::move(client_cert),
231                              std::move(private_key));
232 
233   if (ssl_client_session_cache_) {
234     // Session resumption bypasses client certificate negotiation, so flush all
235     // associated sessions when preferences change.
236     ssl_client_session_cache_->FlushForServers({server});
237   }
238   NotifySSLConfigForServersChanged({server});
239 }
240 
ClearClientCertificate(const HostPortPair & server)241 bool SSLClientContext::ClearClientCertificate(const HostPortPair& server) {
242   if (!ssl_client_auth_cache_.Remove(server)) {
243     return false;
244   }
245 
246   if (ssl_client_session_cache_) {
247     // Session resumption bypasses client certificate negotiation, so flush all
248     // associated sessions when preferences change.
249     ssl_client_session_cache_->FlushForServers({server});
250   }
251   NotifySSLConfigForServersChanged({server});
252   return true;
253 }
254 
AddObserver(Observer * observer)255 void SSLClientContext::AddObserver(Observer* observer) {
256   observers_.AddObserver(observer);
257 }
258 
RemoveObserver(Observer * observer)259 void SSLClientContext::RemoveObserver(Observer* observer) {
260   observers_.RemoveObserver(observer);
261 }
262 
OnSSLContextConfigChanged()263 void SSLClientContext::OnSSLContextConfigChanged() {
264   config_ = ssl_config_service_->GetSSLContextConfig();
265   if (ssl_client_session_cache_) {
266     ssl_client_session_cache_->Flush();
267   }
268   NotifySSLConfigChanged(SSLConfigChangeType::kSSLConfigChanged);
269 }
270 
OnCertVerifierChanged()271 void SSLClientContext::OnCertVerifierChanged() {
272   NotifySSLConfigChanged(SSLConfigChangeType::kCertVerifierChanged);
273 }
274 
OnTrustStoreChanged()275 void SSLClientContext::OnTrustStoreChanged() {
276   NotifySSLConfigChanged(SSLConfigChangeType::kCertDatabaseChanged);
277 }
278 
OnClientCertStoreChanged()279 void SSLClientContext::OnClientCertStoreChanged() {
280   base::flat_set<HostPortPair> servers =
281       ssl_client_auth_cache_.GetCachedServers();
282   ssl_client_auth_cache_.Clear();
283   if (ssl_client_session_cache_) {
284     ssl_client_session_cache_->FlushForServers(servers);
285   }
286   NotifySSLConfigForServersChanged(servers);
287 }
288 
ClearClientCertificateIfNeeded(const net::HostPortPair & host,const scoped_refptr<net::X509Certificate> & certificate)289 void SSLClientContext::ClearClientCertificateIfNeeded(
290     const net::HostPortPair& host,
291     const scoped_refptr<net::X509Certificate>& certificate) {
292   scoped_refptr<X509Certificate> cached_certificate;
293   scoped_refptr<SSLPrivateKey> cached_private_key;
294   if (!ssl_client_auth_cache_.Lookup(host, &cached_certificate,
295                                      &cached_private_key) ||
296       AreCertificatesEqual(cached_certificate, certificate)) {
297     // No cached client certificate preference for this host.
298     net::NetLog::Get()->AddGlobalEntry(
299         NetLogEventType::CLEAR_CACHED_CLIENT_CERT, [&]() {
300           return NetLogClearCachedClientCertParams(host, certificate,
301                                                    /*is_cleared=*/false);
302         });
303     return;
304   }
305 
306   net::NetLog::Get()->AddGlobalEntry(
307       NetLogEventType::CLEAR_CACHED_CLIENT_CERT, [&]() {
308         return NetLogClearCachedClientCertParams(host, certificate,
309                                                  /*is_cleared=*/true);
310       });
311 
312   ssl_client_auth_cache_.Remove(host);
313 
314   if (ssl_client_session_cache_) {
315     ssl_client_session_cache_->FlushForServers({host});
316   }
317 
318   NotifySSLConfigForServersChanged({host});
319 }
320 
ClearMatchingClientCertificate(const scoped_refptr<net::X509Certificate> & certificate)321 void SSLClientContext::ClearMatchingClientCertificate(
322     const scoped_refptr<net::X509Certificate>& certificate) {
323   CHECK(certificate);
324 
325   base::flat_set<HostPortPair> cleared_servers;
326   for (const auto& server : ssl_client_auth_cache_.GetCachedServers()) {
327     scoped_refptr<X509Certificate> cached_certificate;
328     scoped_refptr<SSLPrivateKey> cached_private_key;
329     if (ssl_client_auth_cache_.Lookup(server, &cached_certificate,
330                                       &cached_private_key) &&
331         AreCertificatesEqual(cached_certificate, certificate,
332                              /*include_chain=*/false)) {
333       cleared_servers.insert(cleared_servers.end(), server);
334     }
335   }
336 
337   net::NetLog::Get()->AddGlobalEntry(
338       NetLogEventType::CLEAR_MATCHING_CACHED_CLIENT_CERT, [&]() {
339         return NetLogClearMatchingCachedClientCertParams(cleared_servers,
340                                                          certificate);
341       });
342 
343   if (cleared_servers.empty()) {
344     return;
345   }
346 
347   for (const auto& server_to_clear : cleared_servers) {
348     ssl_client_auth_cache_.Remove(server_to_clear);
349   }
350 
351   if (ssl_client_session_cache_) {
352     ssl_client_session_cache_->FlushForServers(cleared_servers);
353   }
354 
355   NotifySSLConfigForServersChanged(cleared_servers);
356 }
357 
NotifySSLConfigChanged(SSLConfigChangeType change_type)358 void SSLClientContext::NotifySSLConfigChanged(SSLConfigChangeType change_type) {
359   for (Observer& observer : observers_) {
360     observer.OnSSLConfigChanged(change_type);
361   }
362 }
363 
NotifySSLConfigForServersChanged(const base::flat_set<HostPortPair> & servers)364 void SSLClientContext::NotifySSLConfigForServersChanged(
365     const base::flat_set<HostPortPair>& servers) {
366   for (Observer& observer : observers_) {
367     observer.OnSSLConfigForServersChanged(servers);
368   }
369 }
370 
371 }  // namespace net
372