• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "net/socket/ssl_client_socket.h"
6 
7 #include "base/metrics/histogram.h"
8 #include "base/strings/string_util.h"
9 #include "crypto/ec_private_key.h"
10 #include "net/base/host_port_pair.h"
11 #include "net/ssl/channel_id_service.h"
12 #include "net/ssl/ssl_config_service.h"
13 
14 namespace net {
15 
SSLClientSocket()16 SSLClientSocket::SSLClientSocket()
17     : was_npn_negotiated_(false),
18       was_spdy_negotiated_(false),
19       protocol_negotiated_(kProtoUnknown),
20       channel_id_sent_(false),
21       signed_cert_timestamps_received_(false),
22       stapled_ocsp_response_received_(false) {
23 }
24 
25 // static
NextProtoFromString(const std::string & proto_string)26 NextProto SSLClientSocket::NextProtoFromString(
27     const std::string& proto_string) {
28   if (proto_string == "http1.1" || proto_string == "http/1.1") {
29     return kProtoHTTP11;
30   } else if (proto_string == "spdy/2") {
31     return kProtoDeprecatedSPDY2;
32   } else if (proto_string == "spdy/3") {
33     return kProtoSPDY3;
34   } else if (proto_string == "spdy/3.1") {
35     return kProtoSPDY31;
36   } else if (proto_string == "h2-14") {
37     // This is the HTTP/2 draft 14 identifier. For internal
38     // consistency, HTTP/2 is named SPDY4 within Chromium.
39     return kProtoSPDY4;
40   } else if (proto_string == "quic/1+spdy/3") {
41     return kProtoQUIC1SPDY3;
42   } else {
43     return kProtoUnknown;
44   }
45 }
46 
47 // static
NextProtoToString(NextProto next_proto)48 const char* SSLClientSocket::NextProtoToString(NextProto next_proto) {
49   switch (next_proto) {
50     case kProtoHTTP11:
51       return "http/1.1";
52     case kProtoDeprecatedSPDY2:
53       return "spdy/2";
54     case kProtoSPDY3:
55       return "spdy/3";
56     case kProtoSPDY31:
57       return "spdy/3.1";
58     case kProtoSPDY4:
59       // This is the HTTP/2 draft 14 identifier. For internal
60       // consistency, HTTP/2 is named SPDY4 within Chromium.
61       return "h2-14";
62     case kProtoQUIC1SPDY3:
63       return "quic/1+spdy/3";
64     case kProtoUnknown:
65       break;
66   }
67   return "unknown";
68 }
69 
70 // static
NextProtoStatusToString(const SSLClientSocket::NextProtoStatus status)71 const char* SSLClientSocket::NextProtoStatusToString(
72     const SSLClientSocket::NextProtoStatus status) {
73   switch (status) {
74     case kNextProtoUnsupported:
75       return "unsupported";
76     case kNextProtoNegotiated:
77       return "negotiated";
78     case kNextProtoNoOverlap:
79       return "no-overlap";
80   }
81   return NULL;
82 }
83 
WasNpnNegotiated() const84 bool SSLClientSocket::WasNpnNegotiated() const {
85   return was_npn_negotiated_;
86 }
87 
GetNegotiatedProtocol() const88 NextProto SSLClientSocket::GetNegotiatedProtocol() const {
89   return protocol_negotiated_;
90 }
91 
IgnoreCertError(int error,int load_flags)92 bool SSLClientSocket::IgnoreCertError(int error, int load_flags) {
93   if (error == OK || load_flags & LOAD_IGNORE_ALL_CERT_ERRORS)
94     return true;
95 
96   if (error == ERR_CERT_COMMON_NAME_INVALID &&
97       (load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID))
98     return true;
99 
100   if (error == ERR_CERT_DATE_INVALID &&
101       (load_flags & LOAD_IGNORE_CERT_DATE_INVALID))
102     return true;
103 
104   if (error == ERR_CERT_AUTHORITY_INVALID &&
105       (load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID))
106     return true;
107 
108   return false;
109 }
110 
set_was_npn_negotiated(bool negotiated)111 bool SSLClientSocket::set_was_npn_negotiated(bool negotiated) {
112   return was_npn_negotiated_ = negotiated;
113 }
114 
was_spdy_negotiated() const115 bool SSLClientSocket::was_spdy_negotiated() const {
116   return was_spdy_negotiated_;
117 }
118 
set_was_spdy_negotiated(bool negotiated)119 bool SSLClientSocket::set_was_spdy_negotiated(bool negotiated) {
120   return was_spdy_negotiated_ = negotiated;
121 }
122 
set_protocol_negotiated(NextProto protocol_negotiated)123 void SSLClientSocket::set_protocol_negotiated(NextProto protocol_negotiated) {
124   protocol_negotiated_ = protocol_negotiated;
125 }
126 
WasChannelIDSent() const127 bool SSLClientSocket::WasChannelIDSent() const {
128   return channel_id_sent_;
129 }
130 
set_channel_id_sent(bool channel_id_sent)131 void SSLClientSocket::set_channel_id_sent(bool channel_id_sent) {
132   channel_id_sent_ = channel_id_sent;
133 }
134 
set_signed_cert_timestamps_received(bool signed_cert_timestamps_received)135 void SSLClientSocket::set_signed_cert_timestamps_received(
136     bool signed_cert_timestamps_received) {
137   signed_cert_timestamps_received_ = signed_cert_timestamps_received;
138 }
139 
set_stapled_ocsp_response_received(bool stapled_ocsp_response_received)140 void SSLClientSocket::set_stapled_ocsp_response_received(
141     bool stapled_ocsp_response_received) {
142   stapled_ocsp_response_received_ = stapled_ocsp_response_received;
143 }
144 
145 // static
RecordChannelIDSupport(ChannelIDService * channel_id_service,bool negotiated_channel_id,bool channel_id_enabled,bool supports_ecc)146 void SSLClientSocket::RecordChannelIDSupport(
147     ChannelIDService* channel_id_service,
148     bool negotiated_channel_id,
149     bool channel_id_enabled,
150     bool supports_ecc) {
151   // Since this enum is used for a histogram, do not change or re-use values.
152   enum {
153     DISABLED = 0,
154     CLIENT_ONLY = 1,
155     CLIENT_AND_SERVER = 2,
156     CLIENT_NO_ECC = 3,
157     CLIENT_BAD_SYSTEM_TIME = 4,
158     CLIENT_NO_CHANNEL_ID_SERVICE = 5,
159     CHANNEL_ID_USAGE_MAX
160   } supported = DISABLED;
161   if (negotiated_channel_id) {
162     supported = CLIENT_AND_SERVER;
163   } else if (channel_id_enabled) {
164     if (!channel_id_service)
165       supported = CLIENT_NO_CHANNEL_ID_SERVICE;
166     else if (!supports_ecc)
167       supported = CLIENT_NO_ECC;
168     else if (!channel_id_service->IsSystemTimeValid())
169       supported = CLIENT_BAD_SYSTEM_TIME;
170     else
171       supported = CLIENT_ONLY;
172   }
173   UMA_HISTOGRAM_ENUMERATION("DomainBoundCerts.Support", supported,
174                             CHANNEL_ID_USAGE_MAX);
175 }
176 
177 // static
IsChannelIDEnabled(const SSLConfig & ssl_config,ChannelIDService * channel_id_service)178 bool SSLClientSocket::IsChannelIDEnabled(
179     const SSLConfig& ssl_config,
180     ChannelIDService* channel_id_service) {
181   if (!ssl_config.channel_id_enabled)
182     return false;
183   if (!channel_id_service) {
184     DVLOG(1) << "NULL channel_id_service_, not enabling channel ID.";
185     return false;
186   }
187   if (!crypto::ECPrivateKey::IsSupported()) {
188     DVLOG(1) << "Elliptic Curve not supported, not enabling channel ID.";
189     return false;
190   }
191   if (!channel_id_service->IsSystemTimeValid()) {
192     DVLOG(1) << "System time is not within the supported range for certificate "
193                 "generation, not enabling channel ID.";
194     return false;
195   }
196   return true;
197 }
198 
199 // static
SerializeNextProtos(const std::vector<std::string> & next_protos)200 std::vector<uint8_t> SSLClientSocket::SerializeNextProtos(
201     const std::vector<std::string>& next_protos) {
202   // Do a first pass to determine the total length.
203   size_t wire_length = 0;
204   for (std::vector<std::string>::const_iterator i = next_protos.begin();
205        i != next_protos.end(); ++i) {
206     if (i->size() > 255) {
207       LOG(WARNING) << "Ignoring overlong NPN/ALPN protocol: " << *i;
208       continue;
209     }
210     if (i->size() == 0) {
211       LOG(WARNING) << "Ignoring empty NPN/ALPN protocol";
212       continue;
213     }
214     wire_length += i->size();
215     wire_length++;
216   }
217 
218   // Allocate memory for the result and fill it in.
219   std::vector<uint8_t> wire_protos;
220   wire_protos.reserve(wire_length);
221   for (std::vector<std::string>::const_iterator i = next_protos.begin();
222        i != next_protos.end(); i++) {
223     if (i->size() == 0 || i->size() > 255)
224       continue;
225     wire_protos.push_back(i->size());
226     wire_protos.resize(wire_protos.size() + i->size());
227     memcpy(&wire_protos[wire_protos.size() - i->size()],
228            i->data(), i->size());
229   }
230   DCHECK_EQ(wire_protos.size(), wire_length);
231 
232   return wire_protos;
233 }
234 
235 }  // namespace net
236