Index: net/http/transport_security_state.cc |
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc |
index bc45c63f9182c1271ceba6e68b964821e18e0e26..499e2447fb49cd63efdb2593a1385caec1054924 100644 |
--- a/net/http/transport_security_state.cc |
+++ b/net/http/transport_security_state.cc |
@@ -43,8 +43,9 @@ namespace { |
#include "net/http/transport_security_state_ct_policies.inc" |
#include "net/http/transport_security_state_static.h" |
-const size_t kMaxHPKPReportCacheEntries = 50; |
-const int kTimeToRememberHPKPReportsMins = 60; |
+// Parameters for remembering sent HPKP and Expect-CT reports. |
+const size_t kMaxReportCacheEntries = 50; |
+const int kTimeToRememberReportsMins = 60; |
const size_t kReportCacheKeyLength = 16; |
// Points to the active transport security state source. |
@@ -742,7 +743,8 @@ TransportSecurityState::TransportSecurityState() |
enable_static_expect_ct_(true), |
enable_static_expect_staple_(true), |
enable_pkp_bypass_for_local_trust_anchors_(true), |
- sent_reports_cache_(kMaxHPKPReportCacheEntries) { |
+ sent_hpkp_reports_cache_(kMaxReportCacheEntries), |
+ sent_expect_ct_reports_cache_(kMaxReportCacheEntries) { |
// Static pinning is only enabled for official builds to make sure that |
// others don't end up with pins that cannot be easily updated. |
#if !defined(GOOGLE_CHROME_BUILD) || defined(OS_ANDROID) || defined(OS_IOS) |
@@ -890,7 +892,7 @@ TransportSecurityState::CheckCTRequirements( |
GetDynamicExpectCTState(hostname, &state)) { |
if (expect_ct_reporter_ && !state.report_uri.is_empty() && |
report_status == ENABLE_EXPECT_CT_REPORTS) { |
- expect_ct_reporter_->OnExpectCTFailed( |
+ MaybeNotifyExpectCTFailed( |
host_port_pair, state.report_uri, validated_certificate_chain, |
served_certificate_chain, signed_certificate_timestamps); |
} |
@@ -1167,15 +1169,15 @@ TransportSecurityState::CheckPinsAndMaybeSendReport( |
// Limit the rate at which duplicate reports are sent to the same |
// report URI. The same report will not be sent within |
- // |kTimeToRememberHPKPReportsMins|, which reduces load on servers and |
+ // |kTimeToRememberReportsMins|, which reduces load on servers and |
// also prevents accidental loops (a.com triggers a report to b.com |
// which triggers a report to a.com). See section 2.1.4 of RFC 7469. |
- if (sent_reports_cache_.Get(report_cache_key, base::TimeTicks::Now())) |
+ if (sent_hpkp_reports_cache_.Get(report_cache_key, base::TimeTicks::Now())) |
return PKPStatus::VIOLATED; |
- sent_reports_cache_.Put( |
+ sent_hpkp_reports_cache_.Put( |
report_cache_key, true, base::TimeTicks::Now(), |
base::TimeTicks::Now() + |
- base::TimeDelta::FromMinutes(kTimeToRememberHPKPReportsMins)); |
+ base::TimeDelta::FromMinutes(kTimeToRememberReportsMins)); |
report_sender_->Send(pkp_state.report_uri, "application/json; charset=utf-8", |
serialized_report, base::Callback<void()>(), |
@@ -1204,6 +1206,33 @@ bool TransportSecurityState::GetStaticExpectCTState( |
return true; |
} |
+void TransportSecurityState::MaybeNotifyExpectCTFailed( |
+ const HostPortPair& host_port_pair, |
+ const GURL& report_uri, |
+ const X509Certificate* validated_certificate_chain, |
+ const X509Certificate* served_certificate_chain, |
+ const SignedCertificateTimestampAndStatusList& |
+ signed_certificate_timestamps) { |
+ // Do not send repeated reports to the same host/port pair within |
+ // |kTimeToRememberReportsMins|. Theoretically, there could be scenarios in |
+ // which the same host/port generates different reports and it would be useful |
+ // to the server operator to receive those different reports, but such |
+ // scenarios are not expected to arise very often in practice. |
+ const std::string report_cache_key(host_port_pair.ToString()); |
+ if (sent_expect_ct_reports_cache_.Get(report_cache_key, |
+ base::TimeTicks::Now())) { |
+ return; |
+ } |
+ sent_expect_ct_reports_cache_.Put( |
+ report_cache_key, true, base::TimeTicks::Now(), |
+ base::TimeTicks::Now() + |
+ base::TimeDelta::FromMinutes(kTimeToRememberReportsMins)); |
+ |
+ expect_ct_reporter_->OnExpectCTFailed( |
+ host_port_pair, report_uri, validated_certificate_chain, |
+ served_certificate_chain, signed_certificate_timestamps); |
+} |
+ |
bool TransportSecurityState::GetStaticExpectStapleState( |
const std::string& host, |
ExpectStapleState* expect_staple_state) const { |
@@ -1448,10 +1477,10 @@ void TransportSecurityState::ProcessExpectCTHeader( |
return; |
ExpectCTState state; |
if (GetStaticExpectCTState(host_port_pair.host(), &state)) { |
- expect_ct_reporter_->OnExpectCTFailed( |
- host_port_pair, state.report_uri, ssl_info.cert.get(), |
- ssl_info.unverified_cert.get(), |
- ssl_info.signed_certificate_timestamps); |
+ MaybeNotifyExpectCTFailed(host_port_pair, state.report_uri, |
+ ssl_info.cert.get(), |
+ ssl_info.unverified_cert.get(), |
+ ssl_info.signed_certificate_timestamps); |
} |
return; |
} |
@@ -1484,10 +1513,9 @@ void TransportSecurityState::ProcessExpectCTHeader( |
// processing the header. |
if (expect_ct_reporter_ && !report_uri.is_empty() && |
!GetDynamicExpectCTState(host_port_pair.host(), &state)) { |
- expect_ct_reporter_->OnExpectCTFailed( |
- host_port_pair, report_uri, ssl_info.cert.get(), |
- ssl_info.unverified_cert.get(), |
- ssl_info.signed_certificate_timestamps); |
+ MaybeNotifyExpectCTFailed(host_port_pair, report_uri, ssl_info.cert.get(), |
+ ssl_info.unverified_cert.get(), |
+ ssl_info.signed_certificate_timestamps); |
} |
return; |
} |
@@ -1504,6 +1532,11 @@ void TransportSecurityState::SetShouldRequireCTForTesting(bool* required) { |
g_ct_required_for_testing = *required ? 1 : -1; |
} |
+void TransportSecurityState::ClearReportCachesForTesting() { |
+ sent_hpkp_reports_cache_.Clear(); |
+ sent_expect_ct_reports_cache_.Clear(); |
+} |
+ |
// static |
bool TransportSecurityState::IsBuildTimely() { |
const base::Time build_time = base::GetBuildTime(); |