| Index: net/base/transport_security_state.cc | 
| =================================================================== | 
| --- net/base/transport_security_state.cc	(revision 80507) | 
| +++ net/base/transport_security_state.cc	(working copy) | 
| @@ -4,6 +4,8 @@ | 
|  | 
| #include "net/base/transport_security_state.h" | 
|  | 
| +#include <set> | 
| + | 
| #include "base/base64.h" | 
| #include "base/json/json_reader.h" | 
| #include "base/json/json_writer.h" | 
| @@ -17,6 +19,8 @@ | 
| #include "base/values.h" | 
| #include "googleurl/src/gurl.h" | 
| #include "net/base/dns_util.h" | 
| +#include "net/base/x509_cert_types.h" | 
| +#include "net/base/x509_certificate.h" | 
|  | 
| namespace net { | 
|  | 
| @@ -32,6 +36,9 @@ | 
| if (canonicalized_host.empty()) | 
| return; | 
|  | 
| +  // TODO(cevans) -- we likely want to permit a host to override a built-in, | 
| +  // for at least the case where the override is stricter (i.e. includes | 
| +  // subdomains, or includes certificate pinning). | 
| bool temp; | 
| if (IsPreloadedSTS(canonicalized_host, &temp)) | 
| return; | 
| @@ -128,6 +135,41 @@ | 
| return false; | 
| } | 
|  | 
| +bool TransportSecurityState::IsAcceptableCertificate(const std::string& host, | 
| +                                                     X509Certificate* cert) { | 
| +  DomainState state; | 
| +  if (!IsEnabledForHost(&state, host)) | 
| +    return true; | 
| + | 
| +  if (state.cert_pins.empty()) | 
| +    return true; | 
| + | 
| +  std::set<std::string> fingerprints; | 
| +  X509Certificate::OSCertHandles cert_chain; | 
| +  X509Certificate::GetCertChainFromCert(cert->os_cert_handle(), &cert_chain); | 
| +  { | 
| +    X509Certificate::OSCertHandles::const_iterator i; | 
| +    for (i = cert_chain.begin(); i != cert_chain.end(); ++i) { | 
| +      // TODO(cevans): we also want to match on fingerprints of various subsets | 
| +      // of the certificate, such as SubjectPublicKeyInfos, to enable a site | 
| +      // to seamlessly add SANs or have multiple pseudo-identical certs with | 
| +      // different expiries. | 
| +      net::SHA1Fingerprint fingerprint = | 
| +          X509Certificate::CalculateFingerprint(*i); | 
| +      fingerprints.insert(fingerprint.GetString()); | 
| +    } | 
| +  } | 
| +  X509Certificate::DestroyCertChain(&cert_chain); | 
| +  std::vector<std::string>::const_iterator pins_iter; | 
| +  for (pins_iter = state.cert_pins.begin(); | 
| +       pins_iter != state.cert_pins.end(); ++pins_iter) { | 
| +    std::string cert_lock = *pins_iter; | 
| +    if (fingerprints.find(cert_lock) != fingerprints.end()) | 
| +      return true; | 
| +  } | 
| +  return false; | 
| +} | 
| + | 
| void TransportSecurityState::DeleteSince(const base::Time& time) { | 
| bool dirtied = false; | 
|  | 
| @@ -312,6 +354,14 @@ | 
| continue; | 
| } | 
|  | 
| +    ListValue* pins = new ListValue; | 
| +    std::vector<std::string>::const_iterator pin_strings; | 
| +    for (pin_strings = i->second.cert_pins.begin(); | 
| +         pin_strings != i->second.cert_pins.end(); | 
| +         ++pin_strings) | 
| +      pins->Append(new StringValue(*pin_strings)); | 
| +    state->Set("cert_pins", pins); | 
| + | 
| toplevel.Set(HashedDomainToExternalString(i->first), state); | 
| } | 
|  | 
| @@ -349,6 +399,17 @@ | 
| continue; | 
| } | 
|  | 
| +    ListValue* pins_list; | 
| +    std::vector<std::string> cert_pins; | 
| +    if (state->GetList("cert_pins", &pins_list)) { | 
| +      size_t num_pins = pins_list->GetSize(); | 
| +      for (size_t i = 0; i < num_pins; ++i) { | 
| +        std::string pin_string; | 
| +        if (pins_list->GetString(i, &pin_string)) | 
| +          cert_pins.push_back(pin_string); | 
| +      } | 
| +    } | 
| + | 
| DomainState::Mode mode; | 
| if (mode_string == "strict") { | 
| mode = DomainState::MODE_STRICT; | 
| @@ -380,14 +441,17 @@ | 
| } | 
|  | 
| std::string hashed = ExternalStringToHashedDomain(*i); | 
| -    if (hashed.empty()) | 
| +    if (hashed.empty()) { | 
| +      dirtied = true; | 
| continue; | 
| +    } | 
|  | 
| DomainState new_state; | 
| new_state.mode = mode; | 
| new_state.created = created_time; | 
| new_state.expiry = expiry_time; | 
| new_state.include_subdomains = include_subdomains; | 
| +    new_state.cert_pins = cert_pins; | 
| enabled_hosts_[hashed] = new_state; | 
| } | 
|  | 
|  |