summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorpalmer@chromium.org <palmer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-15 17:30:44 +0000
committerpalmer@chromium.org <palmer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-15 17:30:44 +0000
commit2590cbb39144fec19f67e86493392123ea67d90f (patch)
tree0f25989157b81345ac13a9af7e7e5a0adee7fa4b /net
parent04197088ff675b6bb72dd2b415d6da883544b058 (diff)
downloadchromium_src-2590cbb39144fec19f67e86493392123ea67d90f.zip
chromium_src-2590cbb39144fec19f67e86493392123ea67d90f.tar.gz
chromium_src-2590cbb39144fec19f67e86493392123ea67d90f.tar.bz2
Handle max-age in HPKP.
BUG=243865 Review URL: https://codereview.chromium.org/282873003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@270716 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/http/http_security_headers_unittest.cc75
-rw-r--r--net/http/transport_security_state.cc6
2 files changed, 79 insertions, 2 deletions
diff --git a/net/http/http_security_headers_unittest.cc b/net/http/http_security_headers_unittest.cc
index b6fa4ef..bf1bcfb 100644
--- a/net/http/http_security_headers_unittest.cc
+++ b/net/http/http_security_headers_unittest.cc
@@ -572,6 +572,81 @@ TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPOnly) {
EXPECT_NE(new_dynamic_domain_state.pkp.spki_hashes.end(), hash);
}
+TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPMaxAge0) {
+ TransportSecurityState state;
+ TransportSecurityState::DomainState static_domain_state;
+
+ // docs.google.com has preloaded pins.
+ const bool sni_enabled = true;
+ std::string domain = "docs.google.com";
+ ASSERT_TRUE(
+ state.GetStaticDomainState(domain, sni_enabled, &static_domain_state));
+ EXPECT_GT(static_domain_state.pkp.spki_hashes.size(), 1UL);
+ HashValueVector saved_hashes = static_domain_state.pkp.spki_hashes;
+
+ // Add a header, which should only update the dynamic state.
+ HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA1);
+ std::string good_pin = GetTestPin(1, HASH_VALUE_SHA1);
+ std::string backup_pin = GetTestPin(2, HASH_VALUE_SHA1);
+ std::string header = "max-age = 10000; " + good_pin + "; " + backup_pin;
+
+ // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
+ SSLInfo ssl_info;
+ ssl_info.public_key_hashes.push_back(good_hash);
+ ssl_info.public_key_hashes.push_back(saved_hashes[0]);
+ EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info));
+
+ // Expect the static state to remain unchanged.
+ TransportSecurityState::DomainState new_static_domain_state;
+ EXPECT_TRUE(state.GetStaticDomainState(
+ domain, sni_enabled, &new_static_domain_state));
+ EXPECT_EQ(saved_hashes.size(),
+ new_static_domain_state.pkp.spki_hashes.size());
+ for (size_t i = 0; i < saved_hashes.size(); ++i) {
+ EXPECT_TRUE(HashValuesEqual(saved_hashes[i])(
+ new_static_domain_state.pkp.spki_hashes[i]));
+ }
+
+ // Expect the dynamic state to have pins.
+ TransportSecurityState::DomainState new_dynamic_domain_state;
+ EXPECT_TRUE(state.GetDynamicDomainState(domain, &new_dynamic_domain_state));
+ EXPECT_EQ(2UL, new_dynamic_domain_state.pkp.spki_hashes.size());
+ EXPECT_TRUE(new_dynamic_domain_state.HasPublicKeyPins());
+
+ // Now set another header with max-age=0, and check that the pins are
+ // cleared in the dynamic state only.
+ header = "max-age = 0; " + good_pin + "; " + backup_pin;
+ EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info));
+
+ // Expect the static state to remain unchanged.
+ TransportSecurityState::DomainState new_static_domain_state2;
+ EXPECT_TRUE(state.GetStaticDomainState(
+ domain, sni_enabled, &new_static_domain_state2));
+ EXPECT_EQ(saved_hashes.size(),
+ new_static_domain_state2.pkp.spki_hashes.size());
+ for (size_t i = 0; i < saved_hashes.size(); ++i) {
+ EXPECT_TRUE(HashValuesEqual(saved_hashes[i])(
+ new_static_domain_state2.pkp.spki_hashes[i]));
+ }
+
+ // Expect the dynamic pins to be gone.
+ TransportSecurityState::DomainState new_dynamic_domain_state2;
+ EXPECT_FALSE(state.GetDynamicDomainState(domain, &new_dynamic_domain_state2));
+
+ // Expect the exact-matching static policy to continue to apply, even
+ // though dynamic policy has been removed. (This policy may change in the
+ // future, in which case this test must be updated.)
+ EXPECT_TRUE(state.HasPublicKeyPins(domain, true));
+ EXPECT_TRUE(state.ShouldSSLErrorsBeFatal(domain, true));
+ std::string failure_log;
+ // Damage the hashes to cause a pin validation failure.
+ new_static_domain_state2.pkp.spki_hashes[0].data()[0] ^= 0x80;
+ new_static_domain_state2.pkp.spki_hashes[1].data()[0] ^= 0x80;
+ EXPECT_FALSE(state.CheckPublicKeyPins(
+ domain, true, new_static_domain_state2.pkp.spki_hashes, &failure_log));
+ EXPECT_NE(0UL, failure_log.length());
+}
+
// Tests that when a static HSTS and a static HPKP entry are present, adding a
// dynamic HSTS header does not clobber the static HPKP entry. Further, adding a
// dynamic HPKP entry could not affect the HSTS entry for the site.
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc
index e967c65..f50b264 100644
--- a/net/http/transport_security_state.cc
+++ b/net/http/transport_security_state.cc
@@ -626,7 +626,7 @@ bool TransportSecurityState::AddHSTSHeader(const std::string& host,
TransportSecurityState::DomainState domain_state;
GetDynamicDomainState(host, &domain_state);
if (ParseHSTSHeader(value, &max_age, &domain_state.sts.include_subdomains)) {
- // Handle max-age == 0
+ // Handle max-age == 0.
if (max_age.InSeconds() == 0)
domain_state.sts.upgrade_mode = DomainState::MODE_DEFAULT;
else
@@ -653,7 +653,9 @@ bool TransportSecurityState::AddHPKPHeader(const std::string& host,
&max_age,
&domain_state.pkp.include_subdomains,
&domain_state.pkp.spki_hashes)) {
- // TODO(palmer): http://crbug.com/243865 handle max-age == 0.
+ // Handle max-age == 0.
+ if (max_age.InSeconds() == 0)
+ domain_state.pkp.spki_hashes.clear();
domain_state.pkp.last_observed = now;
domain_state.pkp.expiry = now + max_age;
EnableHost(host, domain_state);