Implement HasPermission() method in PermissionService.
[chromium-blink-merge.git] / net / socket / ssl_client_socket.cc
bloba52e6a3c052c70eba239aa57594c8a390816fc56
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"
17 namespace net {
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) {
29 // static
30 NextProto SSLClientSocket::NextProtoFromString(
31 const std::string& proto_string) {
32 if (proto_string == "http1.1" || proto_string == "http/1.1") {
33 return kProtoHTTP11;
34 } else if (proto_string == "spdy/2") {
35 return kProtoDeprecatedSPDY2;
36 } else if (proto_string == "spdy/3") {
37 return kProtoSPDY3;
38 } else if (proto_string == "spdy/3.1") {
39 return kProtoSPDY31;
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;
49 } else {
50 return kProtoUnknown;
54 // static
55 const char* SSLClientSocket::NextProtoToString(NextProto next_proto) {
56 switch (next_proto) {
57 case kProtoHTTP11:
58 return "http/1.1";
59 case kProtoDeprecatedSPDY2:
60 return "spdy/2";
61 case kProtoSPDY3:
62 return "spdy/3";
63 case kProtoSPDY31:
64 return "spdy/3.1";
65 case kProtoSPDY4_14:
66 // For internal consistency, HTTP/2 is named SPDY4 within Chromium.
67 // This is the HTTP/2 draft-14 identifier.
68 return "h2-14";
69 case kProtoSPDY4_15:
70 // This is the HTTP/2 draft-15 identifier.
71 return "h2-15";
72 case kProtoQUIC1SPDY3:
73 return "quic/1+spdy/3";
74 case kProtoUnknown:
75 break;
77 return "unknown";
80 // static
81 const char* SSLClientSocket::NextProtoStatusToString(
82 const SSLClientSocket::NextProtoStatus status) {
83 switch (status) {
84 case kNextProtoUnsupported:
85 return "unsupported";
86 case kNextProtoNegotiated:
87 return "negotiated";
88 case kNextProtoNoOverlap:
89 return "no-overlap";
91 return NULL;
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)
104 return true;
106 if (error == ERR_CERT_COMMON_NAME_INVALID &&
107 (load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID))
108 return true;
110 if (error == ERR_CERT_DATE_INVALID &&
111 (load_flags & LOAD_IGNORE_CERT_DATE_INVALID))
112 return true;
114 if (error == ERR_CERT_AUTHORITY_INVALID &&
115 (load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID))
116 return true;
118 return false;
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;
160 // static
161 void SSLClientSocket::RecordChannelIDSupport(
162 ChannelIDService* channel_id_service,
163 bool negotiated_channel_id,
164 bool channel_id_enabled,
165 bool supports_ecc) {
166 // Since this enum is used for a histogram, do not change or re-use values.
167 enum {
168 DISABLED = 0,
169 CLIENT_ONLY = 1,
170 CLIENT_AND_SERVER = 2,
171 CLIENT_NO_ECC = 3,
172 CLIENT_BAD_SYSTEM_TIME = 4,
173 CLIENT_NO_CHANNEL_ID_SERVICE = 5,
174 CHANNEL_ID_USAGE_MAX
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;
185 else
186 supported = CLIENT_ONLY;
188 UMA_HISTOGRAM_ENUMERATION("DomainBoundCerts.Support", supported,
189 CHANNEL_ID_USAGE_MAX);
192 // static
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);
198 break;
199 case SSL_CONNECTION_VERSION_SSL3:
200 UpdateConnectionTypeHistograms(CONNECTION_SSL_SSL3);
201 break;
202 case SSL_CONNECTION_VERSION_TLS1:
203 UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1);
204 break;
205 case SSL_CONNECTION_VERSION_TLS1_1:
206 UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_1);
207 break;
208 case SSL_CONNECTION_VERSION_TLS1_2:
209 UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_2);
210 break;
214 // static
215 bool SSLClientSocket::IsChannelIDEnabled(
216 const SSLConfig& ssl_config,
217 ChannelIDService* channel_id_service) {
218 if (!ssl_config.channel_id_enabled)
219 return false;
220 if (!channel_id_service) {
221 DVLOG(1) << "NULL channel_id_service_, not enabling channel ID.";
222 return false;
224 if (!crypto::ECPrivateKey::IsSupported()) {
225 DVLOG(1) << "Elliptic Curve not supported, not enabling channel ID.";
226 return false;
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.";
231 return false;
233 return true;
236 // static
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;
245 continue;
247 if (i->size() == 0) {
248 LOG(WARNING) << "Ignoring empty NPN/ALPN protocol";
249 continue;
251 wire_length += i->size();
252 wire_length++;
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)
261 continue;
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);
269 return wire_protos;
272 void SSLClientSocket::RecordNegotiationExtension() {
273 if (negotiation_extension_ == kExtensionUnknown)
274 return;
275 std::string proto;
276 SSLClientSocket::NextProtoStatus status = GetNextProto(&proto);
277 if (status == kNextProtoUnsupported)
278 return;
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) {
288 sample += 1000;
289 } else {
290 sample += 500;
292 } else {
293 DCHECK_EQ(kExtensionALPN, negotiation_extension_);
295 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLProtocolNegotiation", sample);
298 } // namespace net