diff options
author | palmer@chromium.org <palmer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-29 13:13:27 +0000 |
---|---|---|
committer | palmer@chromium.org <palmer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-29 13:13:27 +0000 |
commit | 37fd55fb8f9763f0e87a4b100d9e825612d6806a (patch) | |
tree | d7ae44108c1f79e01795397c6e324ef389e6deef /net/http/http_security_headers_unittest.cc | |
parent | 6a86a4d0ec41fe9a35f08e9b18ff6cd38815e725 (diff) | |
download | chromium_src-37fd55fb8f9763f0e87a4b100d9e825612d6806a.zip chromium_src-37fd55fb8f9763f0e87a4b100d9e825612d6806a.tar.gz chromium_src-37fd55fb8f9763f0e87a4b100d9e825612d6806a.tar.bz2 |
More tests for handling HSTS and HPKP headers.
Fix state management bugs that the tests exposed:
* HPKP and HSTS include_subdomains should be distinct
* HSTS processing should not clobber HPKP data
* Multiple HPKP headers should ignore all but the first
BUG=248678, 156152
TBR=ananta
Review URL: https://chromiumcodereview.appspot.com/16912003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@209290 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http/http_security_headers_unittest.cc')
-rw-r--r-- | net/http/http_security_headers_unittest.cc | 194 |
1 files changed, 148 insertions, 46 deletions
diff --git a/net/http/http_security_headers_unittest.cc b/net/http/http_security_headers_unittest.cc index 0dd286b..0cc81b5 100644 --- a/net/http/http_security_headers_unittest.cc +++ b/net/http/http_security_headers_unittest.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <algorithm> + #include "base/base64.h" #include "base/sha1.h" #include "base/strings/string_piece.h" @@ -10,6 +12,8 @@ #include "net/base/test_completion_callback.h" #include "net/http/http_security_headers.h" #include "net/http/http_util.h" +#include "net/http/transport_security_state.h" +#include "net/ssl/ssl_info.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -119,6 +123,7 @@ TEST_F(HttpSecurityHeadersTest, BogusHeaders) { static void TestBogusPinsHeaders(HashValueTag tag) { base::TimeDelta max_age; + bool include_subdomains; HashValueVector hashes; HashValueVector chain_hashes; @@ -131,64 +136,75 @@ static void TestBogusPinsHeaders(HashValueTag tag) { std::string good_pin = GetTestPin(2, tag); std::string backup_pin = GetTestPin(4, tag); - EXPECT_FALSE( - ParseHPKPHeader(std::string(), chain_hashes, &max_age, &hashes)); - EXPECT_FALSE(ParseHPKPHeader(" ", chain_hashes, &max_age, &hashes)); - EXPECT_FALSE(ParseHPKPHeader("abc", chain_hashes, &max_age, &hashes)); - EXPECT_FALSE(ParseHPKPHeader(" abc", chain_hashes, &max_age, &hashes)); + EXPECT_FALSE(ParseHPKPHeader(std::string(), chain_hashes, &max_age, + &include_subdomains, &hashes)); + EXPECT_FALSE(ParseHPKPHeader(" ", chain_hashes, &max_age, + &include_subdomains, &hashes)); + EXPECT_FALSE(ParseHPKPHeader("abc", chain_hashes, &max_age, + &include_subdomains, &hashes)); + EXPECT_FALSE(ParseHPKPHeader(" abc", chain_hashes, &max_age, + &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader(" abc ", chain_hashes, &max_age, - &hashes)); + &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader("max-age", chain_hashes, &max_age, - &hashes)); + &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader(" max-age", chain_hashes, &max_age, - &hashes)); + &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader(" max-age ", chain_hashes, &max_age, - &hashes)); + &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader("max-age=", chain_hashes, &max_age, - &hashes)); + &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader(" max-age=", chain_hashes, &max_age, - &hashes)); + &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader(" max-age =", chain_hashes, &max_age, - &hashes)); + &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader(" max-age= ", chain_hashes, &max_age, - &hashes)); + &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader(" max-age = ", chain_hashes, - &max_age, &hashes)); + &max_age, &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader(" max-age = xy", chain_hashes, - &max_age, &hashes)); + &max_age, &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader(" max-age = 3488a923", - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, + &hashes)); EXPECT_FALSE(ParseHPKPHeader("max-age=3488a923 ", chain_hashes, - &max_age, &hashes)); + &max_age, &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader("max-ag=3488923pins=" + good_pin + "," + backup_pin, - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, + &hashes)); EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923" + backup_pin, - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, + &hashes)); EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + backup_pin, - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, + &hashes)); EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + backup_pin + ";" + backup_pin, - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, + &hashes)); EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + good_pin + ";" + good_pin, - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, + &hashes)); EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + good_pin, - chain_hashes, &max_age, &hashes)); - EXPECT_FALSE(ParseHPKPHeader("max-age==3488923", chain_hashes, &max_age, + chain_hashes, &max_age, &include_subdomains, &hashes)); + EXPECT_FALSE(ParseHPKPHeader("max-age==3488923", chain_hashes, &max_age, + &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader("amax-age=3488923", chain_hashes, &max_age, - &hashes)); + &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader("max-age=-3488923", chain_hashes, &max_age, - &hashes)); + &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader("max-age=3488923;", chain_hashes, &max_age, - &hashes)); + &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader("max-age=3488923 e", chain_hashes, - &max_age, &hashes)); + &max_age, &include_subdomains, &hashes)); EXPECT_FALSE(ParseHPKPHeader("max-age=3488923 includesubdomain", - chain_hashes, &max_age, &hashes)); - EXPECT_FALSE(ParseHPKPHeader("max-age=34889.23", chain_hashes, &max_age, + chain_hashes, &max_age, &include_subdomains, &hashes)); + EXPECT_FALSE(ParseHPKPHeader("max-age=34889.23", chain_hashes, &max_age, + &include_subdomains, &hashes)); // Check the out args were not updated by checking the default // values for its predictable fields. @@ -310,9 +326,10 @@ TEST_F(HttpSecurityHeadersTest, ValidSTSHeaders) { EXPECT_TRUE(include_subdomains); } -static void TestValidPinsHeaders(HashValueTag tag) { +static void TestValidPKPHeaders(HashValueTag tag) { base::TimeDelta max_age; base::TimeDelta expect_max_age; + bool include_subdomains; HashValueVector hashes; HashValueVector chain_hashes; @@ -327,61 +344,78 @@ static void TestValidPinsHeaders(HashValueTag tag) { EXPECT_TRUE(ParseHPKPHeader( "max-age=243; " + good_pin + ";" + backup_pin, - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, &hashes)); expect_max_age = base::TimeDelta::FromSeconds(243); EXPECT_EQ(expect_max_age, max_age); + EXPECT_FALSE(include_subdomains); EXPECT_TRUE(ParseHPKPHeader( " " + good_pin + "; " + backup_pin + " ; Max-agE = 567", - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, &hashes)); expect_max_age = base::TimeDelta::FromSeconds(567); EXPECT_EQ(expect_max_age, max_age); + EXPECT_FALSE(include_subdomains); EXPECT_TRUE(ParseHPKPHeader( - good_pin + ";" + backup_pin + " ; mAx-aGe = 890 ", - chain_hashes, &max_age, &hashes)); + "includeSubDOMAINS;" + good_pin + ";" + backup_pin + + " ; mAx-aGe = 890 ", + chain_hashes, &max_age, &include_subdomains, &hashes)); expect_max_age = base::TimeDelta::FromSeconds(890); EXPECT_EQ(expect_max_age, max_age); + EXPECT_TRUE(include_subdomains); EXPECT_TRUE(ParseHPKPHeader( good_pin + ";" + backup_pin + "; max-age=123;IGNORED;", - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, &hashes)); expect_max_age = base::TimeDelta::FromSeconds(123); EXPECT_EQ(expect_max_age, max_age); + EXPECT_FALSE(include_subdomains); EXPECT_TRUE(ParseHPKPHeader( "max-age=394082;" + backup_pin + ";" + good_pin + "; ", - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, &hashes)); expect_max_age = base::TimeDelta::FromSeconds(394082); EXPECT_EQ(expect_max_age, max_age); + EXPECT_FALSE(include_subdomains); EXPECT_TRUE(ParseHPKPHeader( "max-age=39408299 ;" + backup_pin + ";" + good_pin + "; ", - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, &hashes)); expect_max_age = base::TimeDelta::FromSeconds( std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(39408299)))); EXPECT_EQ(expect_max_age, max_age); + EXPECT_FALSE(include_subdomains); EXPECT_TRUE(ParseHPKPHeader( - "max-age=39408038 ; cybers=39408038 ; " + + "max-age=39408038 ; cybers=39408038 ; includeSubdomains; " + good_pin + ";" + backup_pin + "; ", - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, &hashes)); expect_max_age = base::TimeDelta::FromSeconds( std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(394082038)))); EXPECT_EQ(expect_max_age, max_age); + EXPECT_TRUE(include_subdomains); EXPECT_TRUE(ParseHPKPHeader( " max-age=0 ; " + good_pin + ";" + backup_pin, - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, &hashes)); + expect_max_age = base::TimeDelta::FromSeconds(0); + EXPECT_EQ(expect_max_age, max_age); + EXPECT_FALSE(include_subdomains); + + EXPECT_TRUE(ParseHPKPHeader( + " max-age=0 ; includeSubdomains; " + good_pin + ";" + backup_pin, + chain_hashes, &max_age, &include_subdomains, &hashes)); expect_max_age = base::TimeDelta::FromSeconds(0); EXPECT_EQ(expect_max_age, max_age); + EXPECT_TRUE(include_subdomains); EXPECT_TRUE(ParseHPKPHeader( " max-age=999999999999999999999999999999999999999999999 ; " + backup_pin + ";" + good_pin + "; ", - chain_hashes, &max_age, &hashes)); + chain_hashes, &max_age, &include_subdomains, &hashes)); expect_max_age = base::TimeDelta::FromSeconds(kMaxHSTSAgeSecs); EXPECT_EQ(expect_max_age, max_age); + EXPECT_FALSE(include_subdomains); } TEST_F(HttpSecurityHeadersTest, BogusPinsHeadersSHA1) { @@ -392,12 +426,80 @@ TEST_F(HttpSecurityHeadersTest, BogusPinsHeadersSHA256) { TestBogusPinsHeaders(HASH_VALUE_SHA256); } -TEST_F(HttpSecurityHeadersTest, ValidPinsHeadersSHA1) { - TestValidPinsHeaders(HASH_VALUE_SHA1); +TEST_F(HttpSecurityHeadersTest, ValidPKPHeadersSHA1) { + TestValidPKPHeaders(HASH_VALUE_SHA1); +} + +TEST_F(HttpSecurityHeadersTest, ValidPKPHeadersSHA256) { + TestValidPKPHeaders(HASH_VALUE_SHA256); } -TEST_F(HttpSecurityHeadersTest, ValidPinsHeadersSHA256) { - TestValidPinsHeaders(HASH_VALUE_SHA256); +TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPOnly) { + TransportSecurityState state; + TransportSecurityState::DomainState domain_state; + + // docs.google.com has preloaded pins. + std::string domain = "docs.google.com"; + EXPECT_TRUE(state.GetDomainState(domain, true, &domain_state)); + EXPECT_GT(domain_state.static_spki_hashes.size(), 1UL); + HashValueVector saved_hashes = domain_state.static_spki_hashes; + + // Add a header, which should only update the dynamic state. + HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA1); + HashValue backup_hash = GetTestHashValue(2, 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 preloaded state to remain unchanged. + std::string canonicalized_host = TransportSecurityState::CanonicalizeHost( + domain); + TransportSecurityState::DomainState static_domain_state; + EXPECT_TRUE(state.GetStaticDomainState(canonicalized_host, + true, + &static_domain_state)); + for (size_t i = 0; i < saved_hashes.size(); ++i) { + EXPECT_TRUE(HashValuesEqual( + saved_hashes[i])(static_domain_state.static_spki_hashes[i])); + } + + // Expect the dynamic state to reflect the header. + TransportSecurityState::DomainState dynamic_domain_state; + EXPECT_TRUE(state.GetDynamicDomainState(domain, &dynamic_domain_state)); + EXPECT_EQ(2UL, dynamic_domain_state.dynamic_spki_hashes.size()); + + HashValueVector::const_iterator hash = std::find_if( + dynamic_domain_state.dynamic_spki_hashes.begin(), + dynamic_domain_state.dynamic_spki_hashes.end(), + HashValuesEqual(good_hash)); + EXPECT_NE(dynamic_domain_state.dynamic_spki_hashes.end(), hash); + + hash = std::find_if( + dynamic_domain_state.dynamic_spki_hashes.begin(), + dynamic_domain_state.dynamic_spki_hashes.end(), + HashValuesEqual(backup_hash)); + EXPECT_NE(dynamic_domain_state.dynamic_spki_hashes.end(), hash); + + // Expect the overall state to reflect the header, too. + EXPECT_TRUE(state.GetDomainState(domain, true, &domain_state)); + EXPECT_EQ(2UL, domain_state.dynamic_spki_hashes.size()); + + hash = std::find_if(domain_state.dynamic_spki_hashes.begin(), + domain_state.dynamic_spki_hashes.end(), + HashValuesEqual(good_hash)); + EXPECT_NE(domain_state.dynamic_spki_hashes.end(), hash); + + hash = std::find_if( + domain_state.dynamic_spki_hashes.begin(), + domain_state.dynamic_spki_hashes.end(), + HashValuesEqual(backup_hash)); + EXPECT_NE(domain_state.dynamic_spki_hashes.end(), hash); } }; // namespace net |