Home | History | Annotate | Download | only in socket
      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 
     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
     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
     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
     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 
     84 bool SSLClientSocket::WasNpnNegotiated() const {
     85   return was_npn_negotiated_;
     86 }
     87 
     88 NextProto SSLClientSocket::GetNegotiatedProtocol() const {
     89   return protocol_negotiated_;
     90 }
     91 
     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 
    111 bool SSLClientSocket::set_was_npn_negotiated(bool negotiated) {
    112   return was_npn_negotiated_ = negotiated;
    113 }
    114 
    115 bool SSLClientSocket::was_spdy_negotiated() const {
    116   return was_spdy_negotiated_;
    117 }
    118 
    119 bool SSLClientSocket::set_was_spdy_negotiated(bool negotiated) {
    120   return was_spdy_negotiated_ = negotiated;
    121 }
    122 
    123 void SSLClientSocket::set_protocol_negotiated(NextProto protocol_negotiated) {
    124   protocol_negotiated_ = protocol_negotiated;
    125 }
    126 
    127 bool SSLClientSocket::WasChannelIDSent() const {
    128   return channel_id_sent_;
    129 }
    130 
    131 void SSLClientSocket::set_channel_id_sent(bool channel_id_sent) {
    132   channel_id_sent_ = channel_id_sent;
    133 }
    134 
    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 
    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
    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
    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
    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