1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/socket/ssl_client_socket.h"
7 #include "base/metrics/histogram.h"
8 #include "base/metrics/sparse_histogram.h"
9 #include "base/strings/string_util.h"
10 #include "crypto/ec_private_key.h"
11 #include "net/base/connection_type_histograms.h"
12 #include "net/base/host_port_pair.h"
13 #include "net/ssl/channel_id_service.h"
14 #include "net/ssl/ssl_config_service.h"
15 #include "net/ssl/ssl_connection_status_flags.h"
19 SSLClientSocket::SSLClientSocket()
20 : was_npn_negotiated_(false),
21 was_spdy_negotiated_(false),
22 protocol_negotiated_(kProtoUnknown
),
23 channel_id_sent_(false),
24 signed_cert_timestamps_received_(false),
25 stapled_ocsp_response_received_(false),
26 negotiation_extension_(kExtensionUnknown
) {
30 NextProto
SSLClientSocket::NextProtoFromString(
31 const std::string
& proto_string
) {
32 if (proto_string
== "http1.1" || proto_string
== "http/1.1") {
34 } else if (proto_string
== "spdy/2") {
35 return kProtoDeprecatedSPDY2
;
36 } else if (proto_string
== "spdy/3") {
38 } else if (proto_string
== "spdy/3.1") {
40 } else if (proto_string
== "h2-14") {
41 // For internal consistency, HTTP/2 is named SPDY4 within Chromium.
42 // This is the HTTP/2 draft-14 identifier.
43 return kProtoSPDY4_14
;
44 } else if (proto_string
== "h2-15") {
45 // This is the HTTP/2 draft-15 identifier.
46 return kProtoSPDY4_15
;
47 } else if (proto_string
== "quic/1+spdy/3") {
48 return kProtoQUIC1SPDY3
;
55 const char* SSLClientSocket::NextProtoToString(NextProto next_proto
) {
59 case kProtoDeprecatedSPDY2
:
66 // For internal consistency, HTTP/2 is named SPDY4 within Chromium.
67 // This is the HTTP/2 draft-14 identifier.
70 // This is the HTTP/2 draft-15 identifier.
72 case kProtoQUIC1SPDY3
:
73 return "quic/1+spdy/3";
81 const char* SSLClientSocket::NextProtoStatusToString(
82 const SSLClientSocket::NextProtoStatus status
) {
84 case kNextProtoUnsupported
:
86 case kNextProtoNegotiated
:
88 case kNextProtoNoOverlap
:
94 bool SSLClientSocket::WasNpnNegotiated() const {
95 return was_npn_negotiated_
;
98 NextProto
SSLClientSocket::GetNegotiatedProtocol() const {
99 return protocol_negotiated_
;
102 bool SSLClientSocket::IgnoreCertError(int error
, int load_flags
) {
103 if (error
== OK
|| load_flags
& LOAD_IGNORE_ALL_CERT_ERRORS
)
106 if (error
== ERR_CERT_COMMON_NAME_INVALID
&&
107 (load_flags
& LOAD_IGNORE_CERT_COMMON_NAME_INVALID
))
110 if (error
== ERR_CERT_DATE_INVALID
&&
111 (load_flags
& LOAD_IGNORE_CERT_DATE_INVALID
))
114 if (error
== ERR_CERT_AUTHORITY_INVALID
&&
115 (load_flags
& LOAD_IGNORE_CERT_AUTHORITY_INVALID
))
121 bool SSLClientSocket::set_was_npn_negotiated(bool negotiated
) {
122 return was_npn_negotiated_
= negotiated
;
125 bool SSLClientSocket::was_spdy_negotiated() const {
126 return was_spdy_negotiated_
;
129 bool SSLClientSocket::set_was_spdy_negotiated(bool negotiated
) {
130 return was_spdy_negotiated_
= negotiated
;
133 void SSLClientSocket::set_protocol_negotiated(NextProto protocol_negotiated
) {
134 protocol_negotiated_
= protocol_negotiated
;
137 void SSLClientSocket::set_negotiation_extension(
138 SSLNegotiationExtension negotiation_extension
) {
139 negotiation_extension_
= negotiation_extension
;
142 bool SSLClientSocket::WasChannelIDSent() const {
143 return channel_id_sent_
;
146 void SSLClientSocket::set_channel_id_sent(bool channel_id_sent
) {
147 channel_id_sent_
= channel_id_sent
;
150 void SSLClientSocket::set_signed_cert_timestamps_received(
151 bool signed_cert_timestamps_received
) {
152 signed_cert_timestamps_received_
= signed_cert_timestamps_received
;
155 void SSLClientSocket::set_stapled_ocsp_response_received(
156 bool stapled_ocsp_response_received
) {
157 stapled_ocsp_response_received_
= stapled_ocsp_response_received
;
161 void SSLClientSocket::RecordChannelIDSupport(
162 ChannelIDService
* channel_id_service
,
163 bool negotiated_channel_id
,
164 bool channel_id_enabled
,
166 // Since this enum is used for a histogram, do not change or re-use values.
170 CLIENT_AND_SERVER
= 2,
172 CLIENT_BAD_SYSTEM_TIME
= 4,
173 CLIENT_NO_CHANNEL_ID_SERVICE
= 5,
175 } supported
= DISABLED
;
176 if (negotiated_channel_id
) {
177 supported
= CLIENT_AND_SERVER
;
178 } else if (channel_id_enabled
) {
179 if (!channel_id_service
)
180 supported
= CLIENT_NO_CHANNEL_ID_SERVICE
;
181 else if (!supports_ecc
)
182 supported
= CLIENT_NO_ECC
;
183 else if (!channel_id_service
->IsSystemTimeValid())
184 supported
= CLIENT_BAD_SYSTEM_TIME
;
186 supported
= CLIENT_ONLY
;
188 UMA_HISTOGRAM_ENUMERATION("DomainBoundCerts.Support", supported
,
189 CHANNEL_ID_USAGE_MAX
);
193 void SSLClientSocket::RecordConnectionTypeMetrics(int ssl_version
) {
194 UpdateConnectionTypeHistograms(CONNECTION_SSL
);
195 switch (ssl_version
) {
196 case SSL_CONNECTION_VERSION_SSL2
:
197 UpdateConnectionTypeHistograms(CONNECTION_SSL_SSL2
);
199 case SSL_CONNECTION_VERSION_SSL3
:
200 UpdateConnectionTypeHistograms(CONNECTION_SSL_SSL3
);
202 case SSL_CONNECTION_VERSION_TLS1
:
203 UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1
);
205 case SSL_CONNECTION_VERSION_TLS1_1
:
206 UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_1
);
208 case SSL_CONNECTION_VERSION_TLS1_2
:
209 UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_2
);
215 bool SSLClientSocket::IsChannelIDEnabled(
216 const SSLConfig
& ssl_config
,
217 ChannelIDService
* channel_id_service
) {
218 if (!ssl_config
.channel_id_enabled
)
220 if (!channel_id_service
) {
221 DVLOG(1) << "NULL channel_id_service_, not enabling channel ID.";
224 if (!crypto::ECPrivateKey::IsSupported()) {
225 DVLOG(1) << "Elliptic Curve not supported, not enabling channel ID.";
228 if (!channel_id_service
->IsSystemTimeValid()) {
229 DVLOG(1) << "System time is not within the supported range for certificate "
230 "generation, not enabling channel ID.";
237 std::vector
<uint8_t> SSLClientSocket::SerializeNextProtos(
238 const std::vector
<std::string
>& next_protos
) {
239 // Do a first pass to determine the total length.
240 size_t wire_length
= 0;
241 for (std::vector
<std::string
>::const_iterator i
= next_protos
.begin();
242 i
!= next_protos
.end(); ++i
) {
243 if (i
->size() > 255) {
244 LOG(WARNING
) << "Ignoring overlong NPN/ALPN protocol: " << *i
;
247 if (i
->size() == 0) {
248 LOG(WARNING
) << "Ignoring empty NPN/ALPN protocol";
251 wire_length
+= i
->size();
255 // Allocate memory for the result and fill it in.
256 std::vector
<uint8_t> wire_protos
;
257 wire_protos
.reserve(wire_length
);
258 for (std::vector
<std::string
>::const_iterator i
= next_protos
.begin();
259 i
!= next_protos
.end(); i
++) {
260 if (i
->size() == 0 || i
->size() > 255)
262 wire_protos
.push_back(i
->size());
263 wire_protos
.resize(wire_protos
.size() + i
->size());
264 memcpy(&wire_protos
[wire_protos
.size() - i
->size()],
265 i
->data(), i
->size());
267 DCHECK_EQ(wire_protos
.size(), wire_length
);
272 void SSLClientSocket::RecordNegotiationExtension() {
273 if (negotiation_extension_
== kExtensionUnknown
)
276 SSLClientSocket::NextProtoStatus status
= GetNextProto(&proto
);
277 if (status
== kNextProtoUnsupported
)
279 // Convert protocol into numerical value for histogram.
280 NextProto protocol_negotiated
= SSLClientSocket::NextProtoFromString(proto
);
281 base::HistogramBase::Sample sample
=
282 static_cast<base::HistogramBase::Sample
>(protocol_negotiated
);
283 // In addition to the protocol negotiated, we want to record which TLS
284 // extension was used, and in case of NPN, whether there was overlap between
285 // server and client list of supported protocols.
286 if (negotiation_extension_
== kExtensionNPN
) {
287 if (status
== kNextProtoNoOverlap
) {
293 DCHECK_EQ(kExtensionALPN
, negotiation_extension_
);
295 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLProtocolNegotiation", sample
);