Convert raw pointers to scoped_ptr in net module.
[chromium-blink-merge.git] / net / socket / ssl_client_socket.cc
blob4dd6a4e926d5a84f56076b94983fbc3c90774a68
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/net_errors.h"
13 #include "net/ssl/channel_id_service.h"
14 #include "net/ssl/ssl_cipher_suite_names.h"
15 #include "net/ssl/ssl_config_service.h"
16 #include "net/ssl/ssl_connection_status_flags.h"
18 namespace net {
20 SSLClientSocket::SSLClientSocket()
21 : signed_cert_timestamps_received_(false),
22 stapled_ocsp_response_received_(false),
23 negotiation_extension_(kExtensionUnknown) {
26 // static
27 NextProto SSLClientSocket::NextProtoFromString(
28 const std::string& proto_string) {
29 if (proto_string == "http1.1" || proto_string == "http/1.1") {
30 return kProtoHTTP11;
31 } else if (proto_string == "spdy/2") {
32 return kProtoDeprecatedSPDY2;
33 } else if (proto_string == "spdy/3") {
34 return kProtoSPDY3;
35 } else if (proto_string == "spdy/3.1") {
36 return kProtoSPDY31;
37 } else if (proto_string == "h2-14") {
38 // For internal consistency, HTTP/2 is named SPDY4 within Chromium.
39 // This is the HTTP/2 draft-14 identifier.
40 return kProtoSPDY4_14;
41 } else if (proto_string == "h2") {
42 return kProtoSPDY4;
43 } else if (proto_string == "quic/1+spdy/3") {
44 return kProtoQUIC1SPDY3;
45 } else {
46 return kProtoUnknown;
50 // static
51 const char* SSLClientSocket::NextProtoToString(NextProto next_proto) {
52 switch (next_proto) {
53 case kProtoHTTP11:
54 return "http/1.1";
55 case kProtoDeprecatedSPDY2:
56 return "spdy/2";
57 case kProtoSPDY3:
58 return "spdy/3";
59 case kProtoSPDY31:
60 return "spdy/3.1";
61 case kProtoSPDY4_14:
62 // For internal consistency, HTTP/2 is named SPDY4 within Chromium.
63 // This is the HTTP/2 draft-14 identifier.
64 return "h2-14";
65 case kProtoSPDY4:
66 return "h2";
67 case kProtoQUIC1SPDY3:
68 return "quic/1+spdy/3";
69 case kProtoUnknown:
70 break;
72 return "unknown";
75 // static
76 const char* SSLClientSocket::NextProtoStatusToString(
77 const SSLClientSocket::NextProtoStatus status) {
78 switch (status) {
79 case kNextProtoUnsupported:
80 return "unsupported";
81 case kNextProtoNegotiated:
82 return "negotiated";
83 case kNextProtoNoOverlap:
84 return "no-overlap";
86 return NULL;
89 bool SSLClientSocket::WasNpnNegotiated() const {
90 std::string unused_proto;
91 return GetNextProto(&unused_proto) == kNextProtoNegotiated;
94 NextProto SSLClientSocket::GetNegotiatedProtocol() const {
95 std::string proto;
96 if (GetNextProto(&proto) != kNextProtoNegotiated)
97 return kProtoUnknown;
98 return NextProtoFromString(proto);
101 bool SSLClientSocket::IgnoreCertError(int error, int load_flags) {
102 if (error == OK)
103 return true;
104 return (load_flags & LOAD_IGNORE_ALL_CERT_ERRORS) &&
105 IsCertificateError(error);
108 void SSLClientSocket::RecordNegotiationExtension() {
109 if (negotiation_extension_ == kExtensionUnknown)
110 return;
111 std::string proto;
112 SSLClientSocket::NextProtoStatus status = GetNextProto(&proto);
113 if (status == kNextProtoUnsupported)
114 return;
115 // Convert protocol into numerical value for histogram.
116 NextProto protocol_negotiated = SSLClientSocket::NextProtoFromString(proto);
117 base::HistogramBase::Sample sample =
118 static_cast<base::HistogramBase::Sample>(protocol_negotiated);
119 // In addition to the protocol negotiated, we want to record which TLS
120 // extension was used, and in case of NPN, whether there was overlap between
121 // server and client list of supported protocols.
122 if (negotiation_extension_ == kExtensionNPN) {
123 if (status == kNextProtoNoOverlap) {
124 sample += 1000;
125 } else {
126 sample += 500;
128 } else {
129 DCHECK_EQ(kExtensionALPN, negotiation_extension_);
131 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLProtocolNegotiation", sample);
134 // static
135 void SSLClientSocket::RecordChannelIDSupport(
136 ChannelIDService* channel_id_service,
137 bool negotiated_channel_id,
138 bool channel_id_enabled,
139 bool supports_ecc) {
140 // Since this enum is used for a histogram, do not change or re-use values.
141 enum {
142 DISABLED = 0,
143 CLIENT_ONLY = 1,
144 CLIENT_AND_SERVER = 2,
145 CLIENT_NO_ECC = 3,
146 CLIENT_BAD_SYSTEM_TIME = 4,
147 CLIENT_NO_CHANNEL_ID_SERVICE = 5,
148 CHANNEL_ID_USAGE_MAX
149 } supported = DISABLED;
150 if (negotiated_channel_id) {
151 supported = CLIENT_AND_SERVER;
152 } else if (channel_id_enabled) {
153 if (!channel_id_service)
154 supported = CLIENT_NO_CHANNEL_ID_SERVICE;
155 else if (!supports_ecc)
156 supported = CLIENT_NO_ECC;
157 else if (!channel_id_service->IsSystemTimeValid())
158 supported = CLIENT_BAD_SYSTEM_TIME;
159 else
160 supported = CLIENT_ONLY;
162 UMA_HISTOGRAM_ENUMERATION("DomainBoundCerts.Support", supported,
163 CHANNEL_ID_USAGE_MAX);
166 // static
167 bool SSLClientSocket::IsChannelIDEnabled(
168 const SSLConfig& ssl_config,
169 ChannelIDService* channel_id_service) {
170 if (!ssl_config.channel_id_enabled)
171 return false;
172 if (!channel_id_service) {
173 DVLOG(1) << "NULL channel_id_service_, not enabling channel ID.";
174 return false;
176 if (!crypto::ECPrivateKey::IsSupported()) {
177 DVLOG(1) << "Elliptic Curve not supported, not enabling channel ID.";
178 return false;
180 if (!channel_id_service->IsSystemTimeValid()) {
181 DVLOG(1) << "System time is not within the supported range for certificate "
182 "generation, not enabling channel ID.";
183 return false;
185 return true;
188 // static
189 bool SSLClientSocket::HasCipherAdequateForHTTP2(
190 const std::vector<uint16>& cipher_suites) {
191 for (uint16 cipher : cipher_suites) {
192 if (IsSecureTLSCipherSuite(cipher))
193 return true;
195 return false;
198 // static
199 bool SSLClientSocket::IsTLSVersionAdequateForHTTP2(
200 const SSLConfig& ssl_config) {
201 return ssl_config.version_max >= SSL_PROTOCOL_VERSION_TLS1_2;
204 // static
205 std::vector<uint8_t> SSLClientSocket::SerializeNextProtos(
206 const NextProtoVector& next_protos,
207 bool can_advertise_http2) {
208 std::vector<uint8_t> wire_protos;
209 for (const NextProto next_proto : next_protos) {
210 if (!can_advertise_http2 && kProtoSPDY4MinimumVersion <= next_proto &&
211 next_proto <= kProtoSPDY4MaximumVersion) {
212 continue;
214 const std::string proto = NextProtoToString(next_proto);
215 if (proto.size() > 255) {
216 LOG(WARNING) << "Ignoring overlong NPN/ALPN protocol: " << proto;
217 continue;
219 if (proto.size() == 0) {
220 LOG(WARNING) << "Ignoring empty NPN/ALPN protocol";
221 continue;
223 wire_protos.push_back(proto.size());
224 for (const char ch : proto) {
225 wire_protos.push_back(static_cast<uint8_t>(ch));
229 return wire_protos;
232 } // namespace net