Index: net/http/transport_security_state.cc |
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc |
index 30d352712f27739fb9aecbd9a72e56680e93b60c..5e67d4c4c2e9dcc30a1aeeca762cf80ef077435a 100644 |
--- a/net/http/transport_security_state.cc |
+++ b/net/http/transport_security_state.cc |
@@ -22,6 +22,7 @@ |
#include "base/strings/stringprintf.h" |
#include "base/strings/utf_string_conversions.h" |
#include "base/values.h" |
+#include "build/build_config.h" |
#include "crypto/sha2.h" |
#include "net/base/host_port_pair.h" |
#include "net/cert/ct_policy_status.h" |
@@ -31,10 +32,15 @@ |
#include "net/http/http_security_headers.h" |
#include "net/ssl/ssl_info.h" |
+#if !defined(OS_NACL) |
+#include "base/metrics/field_trial.h" |
+#endif |
+ |
namespace net { |
namespace { |
+#include "net/http/transport_security_state_ct_policies.inc" |
#include "net/http/transport_security_state_static.h" |
const size_t kMaxHPKPReportCacheEntries = 50; |
@@ -47,6 +53,21 @@ const size_t kReportCacheKeyLength = 16; |
// 1: Unless a delegate says otherwise, require CT. |
int g_ct_required_for_testing = 0; |
+// LessThan comparator for use with std::binary_search() in determining |
+// whether a SHA-256 HashValue appears within a sorted array of |
+// SHA256HashValues. |
+struct SHA256ToHashValueComparator { |
+ bool operator()(const SHA256HashValue& lhs, const HashValue& rhs) const { |
+ DCHECK_EQ(HASH_VALUE_SHA256, rhs.tag); |
+ return memcmp(lhs.data, rhs.data(), rhs.size()) < 0; |
+ } |
+ |
+ bool operator()(const HashValue& lhs, const SHA256HashValue& rhs) const { |
+ DCHECK_EQ(HASH_VALUE_SHA256, lhs.tag); |
+ return memcmp(lhs.data(), rhs.data, lhs.size()) < 0; |
+ } |
+}; |
+ |
void RecordUMAForHPKPReportFailure(const GURL& report_uri, int net_error) { |
UMA_HISTOGRAM_SPARSE_SLOWLY("Net.PublicKeyPinReportSendingFailure", |
net_error); |
@@ -722,7 +743,65 @@ bool TransportSecurityState::ShouldRequireCT( |
if (g_ct_required_for_testing) |
return g_ct_required_for_testing == 1; |
- return false; |
+ // Until CT is required for all secure hosts on the Internet, this should |
+ // remain false. It is provided to simplify the various short-circuit |
+ // returns below. |
+ bool default_response = false; |
+ |
+// FieldTrials are not supported in Native Client apps. |
+#if !defined(OS_NACL) |
+ // Emergency escape valve; not to be activated until there's an actual |
+ // emergency (e.g. a weird path-building bug due to a CA's failed |
+ // disclosure of cross-signed sub-CAs). |
+ std::string group_name = |
+ base::FieldTrialList::FindFullName("EnforceCTForProblematicRoots"); |
+ if (base::StartsWith(group_name, "disabled", |
+ base::CompareCase::INSENSITIVE_ASCII)) { |
+ return default_response; |
+ } |
+#endif |
+ |
+ const base::Time epoch = base::Time::UnixEpoch(); |
+ for (const auto& restricted_ca : kCTRequiredPolicies) { |
+ if (epoch + restricted_ca.effective_date > |
+ validated_certificate_chain->valid_start()) { |
+ // The candidate cert is not subject to the CT policy, because it |
+ // was issued before the effective CT date. |
+ continue; |
+ } |
+ |
+ for (const auto& hash : public_key_hashes) { |
+ if (hash.tag != HASH_VALUE_SHA256) |
+ continue; |
+ |
+ // Determine if |hash| is in the set of roots of |restricted_ca|. |
+ if (!std::binary_search(restricted_ca.roots, |
+ restricted_ca.roots + restricted_ca.roots_length, |
+ hash, SHA256ToHashValueComparator())) { |
+ continue; |
+ } |
+ |
+ // Found a match, indicating this certificate is potentially |
+ // restricted. Determine if any of the hashes are on the exclusion |
+ // list as exempt from the CT requirement. |
+ for (const auto& sub_ca_hash : public_key_hashes) { |
+ if (sub_ca_hash.tag != HASH_VALUE_SHA256) |
+ continue; |
+ if (std::binary_search( |
+ restricted_ca.exceptions, |
+ restricted_ca.exceptions + restricted_ca.exceptions_length, |
+ sub_ca_hash, SHA256ToHashValueComparator())) { |
+ // Found an excluded sub-CA; CT is not required. |
+ return default_response; |
+ } |
+ } |
+ |
+ // No exception found. This certificate must conform to the CT policy. |
+ return true; |
+ } |
+ } |
+ |
+ return default_response; |
} |
void TransportSecurityState::SetDelegate( |