Roll tools/swarming_client/ to b61a1802f5ef4bb8c7b81060cc80add47e6cf302.
[chromium-blink-merge.git] / net / socket / ssl_client_socket.cc
blob5268ad2049bd13dd140186c6264d060c740d494f
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/base/net_errors.h"
14 #include "net/ssl/channel_id_service.h"
15 #include "net/ssl/ssl_cipher_suite_names.h"
16 #include "net/ssl/ssl_config_service.h"
17 #include "net/ssl/ssl_connection_status_flags.h"
19 namespace net {
21 SSLClientSocket::SSLClientSocket()
22 : was_npn_negotiated_(false),
23 was_spdy_negotiated_(false),
24 protocol_negotiated_(kProtoUnknown),
25 channel_id_sent_(false),
26 signed_cert_timestamps_received_(false),
27 stapled_ocsp_response_received_(false),
28 negotiation_extension_(kExtensionUnknown) {
31 // static
32 NextProto SSLClientSocket::NextProtoFromString(
33 const std::string& proto_string) {
34 if (proto_string == "http1.1" || proto_string == "http/1.1") {
35 return kProtoHTTP11;
36 } else if (proto_string == "spdy/2") {
37 return kProtoDeprecatedSPDY2;
38 } else if (proto_string == "spdy/3") {
39 return kProtoSPDY3;
40 } else if (proto_string == "spdy/3.1") {
41 return kProtoSPDY31;
42 } else if (proto_string == "h2-14") {
43 // For internal consistency, HTTP/2 is named SPDY4 within Chromium.
44 // This is the HTTP/2 draft-14 identifier.
45 return kProtoSPDY4_14;
46 } else if (proto_string == "h2-15") {
47 // This is the HTTP/2 draft-15 identifier.
48 return kProtoSPDY4_15;
49 } else if (proto_string == "h2") {
50 return kProtoSPDY4;
51 } else if (proto_string == "quic/1+spdy/3") {
52 return kProtoQUIC1SPDY3;
53 } else {
54 return kProtoUnknown;
58 // static
59 const char* SSLClientSocket::NextProtoToString(NextProto next_proto) {
60 switch (next_proto) {
61 case kProtoHTTP11:
62 return "http/1.1";
63 case kProtoDeprecatedSPDY2:
64 return "spdy/2";
65 case kProtoSPDY3:
66 return "spdy/3";
67 case kProtoSPDY31:
68 return "spdy/3.1";
69 case kProtoSPDY4_14:
70 // For internal consistency, HTTP/2 is named SPDY4 within Chromium.
71 // This is the HTTP/2 draft-14 identifier.
72 return "h2-14";
73 case kProtoSPDY4_15:
74 // This is the HTTP/2 draft-15 identifier.
75 return "h2-15";
76 case kProtoSPDY4:
77 return "h2";
78 case kProtoQUIC1SPDY3:
79 return "quic/1+spdy/3";
80 case kProtoUnknown:
81 break;
83 return "unknown";
86 // static
87 const char* SSLClientSocket::NextProtoStatusToString(
88 const SSLClientSocket::NextProtoStatus status) {
89 switch (status) {
90 case kNextProtoUnsupported:
91 return "unsupported";
92 case kNextProtoNegotiated:
93 return "negotiated";
94 case kNextProtoNoOverlap:
95 return "no-overlap";
97 return NULL;
100 bool SSLClientSocket::WasNpnNegotiated() const {
101 return was_npn_negotiated_;
104 NextProto SSLClientSocket::GetNegotiatedProtocol() const {
105 return protocol_negotiated_;
108 bool SSLClientSocket::IgnoreCertError(int error, int load_flags) {
109 if (error == OK)
110 return true;
111 return (load_flags & LOAD_IGNORE_ALL_CERT_ERRORS) &&
112 IsCertificateError(error);
115 bool SSLClientSocket::set_was_npn_negotiated(bool negotiated) {
116 return was_npn_negotiated_ = negotiated;
119 bool SSLClientSocket::was_spdy_negotiated() const {
120 return was_spdy_negotiated_;
123 bool SSLClientSocket::set_was_spdy_negotiated(bool negotiated) {
124 return was_spdy_negotiated_ = negotiated;
127 void SSLClientSocket::set_protocol_negotiated(NextProto protocol_negotiated) {
128 protocol_negotiated_ = protocol_negotiated;
131 void SSLClientSocket::set_negotiation_extension(
132 SSLNegotiationExtension negotiation_extension) {
133 negotiation_extension_ = negotiation_extension;
136 bool SSLClientSocket::WasChannelIDSent() const {
137 return channel_id_sent_;
140 void SSLClientSocket::set_channel_id_sent(bool channel_id_sent) {
141 channel_id_sent_ = channel_id_sent;
144 void SSLClientSocket::set_signed_cert_timestamps_received(
145 bool signed_cert_timestamps_received) {
146 signed_cert_timestamps_received_ = signed_cert_timestamps_received;
149 void SSLClientSocket::set_stapled_ocsp_response_received(
150 bool stapled_ocsp_response_received) {
151 stapled_ocsp_response_received_ = stapled_ocsp_response_received;
154 // static
155 void SSLClientSocket::RecordChannelIDSupport(
156 ChannelIDService* channel_id_service,
157 bool negotiated_channel_id,
158 bool channel_id_enabled,
159 bool supports_ecc) {
160 // Since this enum is used for a histogram, do not change or re-use values.
161 enum {
162 DISABLED = 0,
163 CLIENT_ONLY = 1,
164 CLIENT_AND_SERVER = 2,
165 CLIENT_NO_ECC = 3,
166 CLIENT_BAD_SYSTEM_TIME = 4,
167 CLIENT_NO_CHANNEL_ID_SERVICE = 5,
168 CHANNEL_ID_USAGE_MAX
169 } supported = DISABLED;
170 if (negotiated_channel_id) {
171 supported = CLIENT_AND_SERVER;
172 } else if (channel_id_enabled) {
173 if (!channel_id_service)
174 supported = CLIENT_NO_CHANNEL_ID_SERVICE;
175 else if (!supports_ecc)
176 supported = CLIENT_NO_ECC;
177 else if (!channel_id_service->IsSystemTimeValid())
178 supported = CLIENT_BAD_SYSTEM_TIME;
179 else
180 supported = CLIENT_ONLY;
182 UMA_HISTOGRAM_ENUMERATION("DomainBoundCerts.Support", supported,
183 CHANNEL_ID_USAGE_MAX);
186 // static
187 bool SSLClientSocket::IsChannelIDEnabled(
188 const SSLConfig& ssl_config,
189 ChannelIDService* channel_id_service) {
190 if (!ssl_config.channel_id_enabled)
191 return false;
192 if (!channel_id_service) {
193 DVLOG(1) << "NULL channel_id_service_, not enabling channel ID.";
194 return false;
196 if (!crypto::ECPrivateKey::IsSupported()) {
197 DVLOG(1) << "Elliptic Curve not supported, not enabling channel ID.";
198 return false;
200 if (!channel_id_service->IsSystemTimeValid()) {
201 DVLOG(1) << "System time is not within the supported range for certificate "
202 "generation, not enabling channel ID.";
203 return false;
205 return true;
208 // static
209 bool SSLClientSocket::HasCipherAdequateForHTTP2(
210 const std::vector<uint16>& cipher_suites) {
211 for (uint16 cipher : cipher_suites) {
212 if (IsSecureTLSCipherSuite(cipher))
213 return true;
215 return false;
218 // static
219 bool SSLClientSocket::IsTLSVersionAdequateForHTTP2(
220 const SSLConfig& ssl_config) {
221 return ssl_config.version_max >= SSL_PROTOCOL_VERSION_TLS1_2;
224 // static
225 std::vector<uint8_t> SSLClientSocket::SerializeNextProtos(
226 const NextProtoVector& next_protos,
227 bool can_advertise_http2) {
228 std::vector<uint8_t> wire_protos;
229 for (const NextProto next_proto : next_protos) {
230 if (!can_advertise_http2 && kProtoSPDY4MinimumVersion <= next_proto &&
231 next_proto <= kProtoSPDY4MaximumVersion) {
232 continue;
234 const std::string proto = NextProtoToString(next_proto);
235 if (proto.size() > 255) {
236 LOG(WARNING) << "Ignoring overlong NPN/ALPN protocol: " << proto;
237 continue;
239 if (proto.size() == 0) {
240 LOG(WARNING) << "Ignoring empty NPN/ALPN protocol";
241 continue;
243 wire_protos.push_back(proto.size());
244 for (const char ch : proto) {
245 wire_protos.push_back(static_cast<uint8_t>(ch));
249 return wire_protos;
252 void SSLClientSocket::RecordNegotiationExtension() {
253 if (negotiation_extension_ == kExtensionUnknown)
254 return;
255 std::string proto;
256 SSLClientSocket::NextProtoStatus status = GetNextProto(&proto);
257 if (status == kNextProtoUnsupported)
258 return;
259 // Convert protocol into numerical value for histogram.
260 NextProto protocol_negotiated = SSLClientSocket::NextProtoFromString(proto);
261 base::HistogramBase::Sample sample =
262 static_cast<base::HistogramBase::Sample>(protocol_negotiated);
263 // In addition to the protocol negotiated, we want to record which TLS
264 // extension was used, and in case of NPN, whether there was overlap between
265 // server and client list of supported protocols.
266 if (negotiation_extension_ == kExtensionNPN) {
267 if (status == kNextProtoNoOverlap) {
268 sample += 1000;
269 } else {
270 sample += 500;
272 } else {
273 DCHECK_EQ(kExtensionALPN, negotiation_extension_);
275 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLProtocolNegotiation", sample);
278 } // namespace net