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/ssl/server_bound_cert_service.h"
     11 #include "net/ssl/ssl_config_service.h"
     12 
     13 namespace net {
     14 
     15 SSLClientSocket::SSLClientSocket()
     16     : was_npn_negotiated_(false),
     17       was_spdy_negotiated_(false),
     18       protocol_negotiated_(kProtoUnknown),
     19       channel_id_sent_(false),
     20       signed_cert_timestamps_received_(false),
     21       stapled_ocsp_response_received_(false) {
     22 }
     23 
     24 // static
     25 NextProto SSLClientSocket::NextProtoFromString(
     26     const std::string& proto_string) {
     27   if (proto_string == "http1.1" || proto_string == "http/1.1") {
     28     return kProtoHTTP11;
     29   } else if (proto_string == "spdy/2") {
     30     return kProtoDeprecatedSPDY2;
     31   } else if (proto_string == "spdy/3") {
     32     return kProtoSPDY3;
     33   } else if (proto_string == "spdy/3.1") {
     34     return kProtoSPDY31;
     35   } else if (proto_string == "spdy/4a2") {
     36     return kProtoSPDY4a2;
     37   } else if (proto_string == "HTTP-draft-04/2.0") {
     38     return kProtoHTTP2Draft04;
     39   } else if (proto_string == "quic/1+spdy/3") {
     40     return kProtoQUIC1SPDY3;
     41   } else {
     42     return kProtoUnknown;
     43   }
     44 }
     45 
     46 // static
     47 const char* SSLClientSocket::NextProtoToString(NextProto next_proto) {
     48   switch (next_proto) {
     49     case kProtoHTTP11:
     50       return "http/1.1";
     51     case kProtoDeprecatedSPDY2:
     52       return "spdy/2";
     53     case kProtoSPDY3:
     54       return "spdy/3";
     55     case kProtoSPDY31:
     56       return "spdy/3.1";
     57     case kProtoSPDY4a2:
     58       return "spdy/4a2";
     59     case kProtoHTTP2Draft04:
     60       return "HTTP-draft-04/2.0";
     61     case kProtoQUIC1SPDY3:
     62       return "quic/1+spdy/3";
     63     case kProtoUnknown:
     64       break;
     65   }
     66   return "unknown";
     67 }
     68 
     69 // static
     70 const char* SSLClientSocket::NextProtoStatusToString(
     71     const SSLClientSocket::NextProtoStatus status) {
     72   switch (status) {
     73     case kNextProtoUnsupported:
     74       return "unsupported";
     75     case kNextProtoNegotiated:
     76       return "negotiated";
     77     case kNextProtoNoOverlap:
     78       return "no-overlap";
     79   }
     80   return NULL;
     81 }
     82 
     83 // static
     84 std::string SSLClientSocket::ServerProtosToString(
     85     const std::string& server_protos) {
     86   const char* protos = server_protos.c_str();
     87   size_t protos_len = server_protos.length();
     88   std::vector<std::string> server_protos_with_commas;
     89   for (size_t i = 0; i < protos_len; ) {
     90     const size_t len = protos[i];
     91     std::string proto_str(&protos[i + 1], len);
     92     server_protos_with_commas.push_back(proto_str);
     93     i += len + 1;
     94   }
     95   return JoinString(server_protos_with_commas, ',');
     96 }
     97 
     98 bool SSLClientSocket::WasNpnNegotiated() const {
     99   return was_npn_negotiated_;
    100 }
    101 
    102 NextProto SSLClientSocket::GetNegotiatedProtocol() const {
    103   return protocol_negotiated_;
    104 }
    105 
    106 bool SSLClientSocket::IgnoreCertError(int error, int load_flags) {
    107   if (error == OK || load_flags & LOAD_IGNORE_ALL_CERT_ERRORS)
    108     return true;
    109 
    110   if (error == ERR_CERT_COMMON_NAME_INVALID &&
    111       (load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID))
    112     return true;
    113 
    114   if (error == ERR_CERT_DATE_INVALID &&
    115       (load_flags & LOAD_IGNORE_CERT_DATE_INVALID))
    116     return true;
    117 
    118   if (error == ERR_CERT_AUTHORITY_INVALID &&
    119       (load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID))
    120     return true;
    121 
    122   return false;
    123 }
    124 
    125 bool SSLClientSocket::set_was_npn_negotiated(bool negotiated) {
    126   return was_npn_negotiated_ = negotiated;
    127 }
    128 
    129 bool SSLClientSocket::was_spdy_negotiated() const {
    130   return was_spdy_negotiated_;
    131 }
    132 
    133 bool SSLClientSocket::set_was_spdy_negotiated(bool negotiated) {
    134   return was_spdy_negotiated_ = negotiated;
    135 }
    136 
    137 void SSLClientSocket::set_protocol_negotiated(NextProto protocol_negotiated) {
    138   protocol_negotiated_ = protocol_negotiated;
    139 }
    140 
    141 bool SSLClientSocket::WasChannelIDSent() const {
    142   return channel_id_sent_;
    143 }
    144 
    145 void SSLClientSocket::set_channel_id_sent(bool channel_id_sent) {
    146   channel_id_sent_ = channel_id_sent;
    147 }
    148 
    149 void SSLClientSocket::set_signed_cert_timestamps_received(
    150     bool signed_cert_timestamps_received) {
    151   signed_cert_timestamps_received_ = signed_cert_timestamps_received;
    152 }
    153 
    154 void SSLClientSocket::set_stapled_ocsp_response_received(
    155     bool stapled_ocsp_response_received) {
    156   stapled_ocsp_response_received_ = stapled_ocsp_response_received;
    157 }
    158 
    159 // static
    160 void SSLClientSocket::RecordChannelIDSupport(
    161     ServerBoundCertService* server_bound_cert_service,
    162     bool negotiated_channel_id,
    163     bool channel_id_enabled,
    164     bool supports_ecc) {
    165   // Since this enum is used for a histogram, do not change or re-use values.
    166   enum {
    167     DISABLED = 0,
    168     CLIENT_ONLY = 1,
    169     CLIENT_AND_SERVER = 2,
    170     CLIENT_NO_ECC = 3,
    171     CLIENT_BAD_SYSTEM_TIME = 4,
    172     CLIENT_NO_SERVER_BOUND_CERT_SERVICE = 5,
    173     DOMAIN_BOUND_CERT_USAGE_MAX
    174   } supported = DISABLED;
    175   if (negotiated_channel_id) {
    176     supported = CLIENT_AND_SERVER;
    177   } else if (channel_id_enabled) {
    178     if (!server_bound_cert_service)
    179       supported = CLIENT_NO_SERVER_BOUND_CERT_SERVICE;
    180     else if (!supports_ecc)
    181       supported = CLIENT_NO_ECC;
    182     else if (!server_bound_cert_service->IsSystemTimeValid())
    183       supported = CLIENT_BAD_SYSTEM_TIME;
    184     else
    185       supported = CLIENT_ONLY;
    186   }
    187   UMA_HISTOGRAM_ENUMERATION("DomainBoundCerts.Support", supported,
    188                             DOMAIN_BOUND_CERT_USAGE_MAX);
    189 }
    190 
    191 // static
    192 bool SSLClientSocket::IsChannelIDEnabled(
    193     const SSLConfig& ssl_config,
    194     ServerBoundCertService* server_bound_cert_service) {
    195   if (!ssl_config.channel_id_enabled)
    196     return false;
    197   if (!server_bound_cert_service) {
    198     DVLOG(1) << "NULL server_bound_cert_service_, not enabling channel ID.";
    199     return false;
    200   }
    201   if (!crypto::ECPrivateKey::IsSupported()) {
    202     DVLOG(1) << "Elliptic Curve not supported, not enabling channel ID.";
    203     return false;
    204   }
    205   if (!server_bound_cert_service->IsSystemTimeValid()) {
    206     DVLOG(1) << "System time is not within the supported range for certificate "
    207                 "generation, not enabling channel ID.";
    208     return false;
    209   }
    210   return true;
    211 }
    212 
    213 }  // namespace net
    214