Index: net/base/transport_security_state_unittest.cc |
=================================================================== |
--- net/base/transport_security_state_unittest.cc (revision 163343) |
+++ net/base/transport_security_state_unittest.cc (working copy) |
@@ -45,399 +45,7 @@ |
} |
}; |
-TEST_F(TransportSecurityStateTest, BogusHeaders) { |
- TransportSecurityState::DomainState state; |
- base::Time now = base::Time::Now(); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, " ")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "abc")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, " abc")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, " abc ")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, " max-age")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, " max-age ")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, " max-age=")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, " max-age =")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, " max-age= ")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, " max-age = ")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, " max-age = xy")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, " max-age = 3488a923")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488a923 ")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-ag=3488923")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-aged=3488923")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age==3488923")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "amax-age=3488923")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=-3488923")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923;")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923 e")); |
- EXPECT_FALSE(state.ParseSTSHeader( |
- now, "max-age=3488923 includesubdomain")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923includesubdomains")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923=includesubdomains")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923 includesubdomainx")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923 includesubdomain=")); |
- EXPECT_FALSE(state.ParseSTSHeader( |
- now, "max-age=3488923 includesubdomain=true")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923 includesubdomainsx")); |
- EXPECT_FALSE(state.ParseSTSHeader( |
- now, "max-age=3488923 includesubdomains x")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=34889.23 includesubdomains")); |
- EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=34889 includesubdomains")); |
- |
- // Check that |state| was not updated by expecting the default |
- // values for its predictable fields. |
- EXPECT_EQ(state.upgrade_mode, |
- TransportSecurityState::DomainState::MODE_FORCE_HTTPS); |
- EXPECT_FALSE(state.include_subdomains); |
-} |
- |
-static bool GetPublicKeyHash(const net::X509Certificate::OSCertHandle& cert, |
- HashValue* hash) { |
- std::string der_bytes; |
- if (!net::X509Certificate::GetDEREncoded(cert, &der_bytes)) |
- return false; |
- |
- base::StringPiece spki; |
- if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) |
- return false; |
- |
- switch (hash->tag) { |
- case HASH_VALUE_SHA1: |
- base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(spki.data()), |
- spki.size(), hash->data()); |
- break; |
- case HASH_VALUE_SHA256: |
- crypto::SHA256HashString(spki, hash->data(), crypto::kSHA256Length); |
- break; |
- default: |
- NOTREACHED() << "Unknown HashValueTag " << hash->tag; |
- } |
- |
- return true; |
-} |
- |
-static std::string GetPinFromCert(X509Certificate* cert, HashValueTag tag) { |
- HashValue spki_hash(tag); |
- EXPECT_TRUE(GetPublicKeyHash(cert->os_cert_handle(), &spki_hash)); |
- |
- std::string base64; |
- base::Base64Encode(base::StringPiece( |
- reinterpret_cast<char*>(spki_hash.data()), spki_hash.size()), &base64); |
- |
- std::string label; |
- switch (tag) { |
- case HASH_VALUE_SHA1: |
- label = "pin-sha1="; |
- break; |
- case HASH_VALUE_SHA256: |
- label = "pin-sha256="; |
- break; |
- default: |
- NOTREACHED() << "Unknown HashValueTag " << tag; |
- } |
- |
- return label + HttpUtil::Quote(base64); |
-} |
- |
-static void TestBogusPinsHeaders(HashValueTag tag) { |
- TransportSecurityState::DomainState state; |
- SSLInfo ssl_info; |
- ssl_info.cert = |
- ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); |
- std::string good_pin = GetPinFromCert(ssl_info.cert, tag); |
- base::Time now = base::Time::Now(); |
- |
- // The backup pin is fake --- it just has to not be in the chain. |
- std::string backup_pin = "pin-sha1=" + |
- HttpUtil::Quote("6dcfXufJLW3J6S/9rRe4vUlBj5g="); |
- |
- EXPECT_FALSE(state.ParsePinsHeader(now, "", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, " ", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, "abc", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, " abc", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, " abc ", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, "max-age", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, " max-age", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, " max-age ", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, " max-age=", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, " max-age =", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, " max-age= ", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, " max-age = ", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, " max-age = xy", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader( |
- now, |
- " max-age = 3488a923", |
- ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=3488a923 ", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, |
- "max-ag=3488923pins=" + good_pin + "," + backup_pin, |
- ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, "max-aged=3488923" + backup_pin, |
- ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, "max-aged=3488923; " + backup_pin, |
- ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, |
- "max-aged=3488923; " + backup_pin + ";" + backup_pin, |
- ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, |
- "max-aged=3488923; " + good_pin + ";" + good_pin, |
- ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, "max-aged=3488923; " + good_pin, |
- ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, "max-age==3488923", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, "amax-age=3488923", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=-3488923", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=3488923;", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=3488923 e", ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader( |
- now, |
- "max-age=3488923 includesubdomain", |
- ssl_info)); |
- EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=34889.23", ssl_info)); |
- |
- // Check that |state| was not updated by expecting the default |
- // values for its predictable fields. |
- EXPECT_EQ(state.upgrade_mode, |
- TransportSecurityState::DomainState::MODE_FORCE_HTTPS); |
- EXPECT_FALSE(state.include_subdomains); |
-} |
- |
-TEST_F(TransportSecurityStateTest, BogusPinsHeadersSHA1) { |
- TestBogusPinsHeaders(HASH_VALUE_SHA1); |
-} |
- |
-TEST_F(TransportSecurityStateTest, BogusPinsHeadersSHA256) { |
- TestBogusPinsHeaders(HASH_VALUE_SHA256); |
-} |
- |
-TEST_F(TransportSecurityStateTest, ValidSTSHeaders) { |
- TransportSecurityState::DomainState state; |
- base::Time expiry; |
- base::Time now = base::Time::Now(); |
- |
- EXPECT_TRUE(state.ParseSTSHeader(now, "max-age=243")); |
- expiry = now + base::TimeDelta::FromSeconds(243); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_FALSE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader(now, " Max-agE = 567")); |
- expiry = now + base::TimeDelta::FromSeconds(567); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_FALSE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader(now, " mAx-aGe = 890 ")); |
- expiry = now + base::TimeDelta::FromSeconds(890); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_FALSE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader(now, "max-age=123;incLudesUbdOmains")); |
- expiry = now + base::TimeDelta::FromSeconds(123); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_TRUE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader(now, "incLudesUbdOmains; max-age=123")); |
- expiry = now + base::TimeDelta::FromSeconds(123); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_TRUE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader(now, " incLudesUbdOmains; max-age=123")); |
- expiry = now + base::TimeDelta::FromSeconds(123); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_TRUE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader(now, |
- " incLudesUbdOmains; max-age=123; pumpkin=kitten")); |
- expiry = now + base::TimeDelta::FromSeconds(123); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_TRUE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader(now, |
- " pumpkin=894; incLudesUbdOmains; max-age=123 ")); |
- expiry = now + base::TimeDelta::FromSeconds(123); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_TRUE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader(now, |
- " pumpkin; incLudesUbdOmains; max-age=123 ")); |
- expiry = now + base::TimeDelta::FromSeconds(123); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_TRUE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader(now, |
- " pumpkin; incLudesUbdOmains; max-age=\"123\" ")); |
- expiry = now + base::TimeDelta::FromSeconds(123); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_TRUE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader(now, |
- "animal=\"squirrel; distinguished\"; incLudesUbdOmains; max-age=123")); |
- expiry = now + base::TimeDelta::FromSeconds(123); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_TRUE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader(now, "max-age=394082; incLudesUbdOmains")); |
- expiry = now + base::TimeDelta::FromSeconds(394082); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_TRUE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader( |
- now, "max-age=39408299 ;incLudesUbdOmains")); |
- expiry = now + base::TimeDelta::FromSeconds( |
- std::min(TransportSecurityState::kMaxHSTSAgeSecs, 39408299l)); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_TRUE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader( |
- now, "max-age=394082038 ; incLudesUbdOmains")); |
- expiry = now + base::TimeDelta::FromSeconds( |
- std::min(TransportSecurityState::kMaxHSTSAgeSecs, 394082038l)); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_TRUE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader( |
- now, " max-age=0 ; incLudesUbdOmains ")); |
- expiry = now + base::TimeDelta::FromSeconds(0); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_TRUE(state.include_subdomains); |
- |
- EXPECT_TRUE(state.ParseSTSHeader( |
- now, |
- " max-age=999999999999999999999999999999999999999999999 ;" |
- " incLudesUbdOmains ")); |
- expiry = now + base::TimeDelta::FromSeconds( |
- TransportSecurityState::kMaxHSTSAgeSecs); |
- EXPECT_EQ(expiry, state.upgrade_expiry); |
- EXPECT_TRUE(state.include_subdomains); |
-} |
- |
-static void TestValidPinsHeaders(HashValueTag tag) { |
- TransportSecurityState::DomainState state; |
- base::Time expiry; |
- base::Time now = base::Time::Now(); |
- |
- // Set up a realistic SSLInfo with a realistic cert chain. |
- FilePath certs_dir = GetTestCertsDirectory(); |
- scoped_refptr<X509Certificate> ee_cert = |
- ImportCertFromFile(certs_dir, "2048-rsa-ee-by-2048-rsa-intermediate.pem"); |
- ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_cert); |
- scoped_refptr<X509Certificate> intermediate = |
- ImportCertFromFile(certs_dir, "2048-rsa-intermediate.pem"); |
- ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate); |
- X509Certificate::OSCertHandles intermediates; |
- intermediates.push_back(intermediate->os_cert_handle()); |
- SSLInfo ssl_info; |
- ssl_info.cert = X509Certificate::CreateFromHandle(ee_cert->os_cert_handle(), |
- intermediates); |
- |
- // Add the root that signed the intermediate for this test. |
- scoped_refptr<X509Certificate> root_cert = |
- ImportCertFromFile(certs_dir, "2048-rsa-root.pem"); |
- ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert); |
- ScopedTestRoot scoped_root(root_cert); |
- |
- // Verify has the side-effect of populating public_key_hashes, which |
- // ParsePinsHeader needs. (It wants to check pins against the validated |
- // chain, not just the presented chain.) |
- int rv = ERR_FAILED; |
- CertVerifyResult result; |
- scoped_ptr<CertVerifier> verifier(CertVerifier::CreateDefault()); |
- TestCompletionCallback callback; |
- CertVerifier::RequestHandle handle = NULL; |
- rv = verifier->Verify(ssl_info.cert, "127.0.0.1", 0, NULL, &result, |
- callback.callback(), &handle, BoundNetLog()); |
- rv = callback.GetResult(rv); |
- ASSERT_EQ(OK, rv); |
- // Normally, ssl_client_socket_nss would do this, but for a unit test we |
- // fake it. |
- ssl_info.public_key_hashes = result.public_key_hashes; |
- std::string good_pin = GetPinFromCert(ssl_info.cert, /*tag*/HASH_VALUE_SHA1); |
- DLOG(WARNING) << "good pin: " << good_pin; |
- |
- // The backup pin is fake --- we just need an SPKI hash that does not match |
- // the hash of any SPKI in the certificate chain. |
- std::string backup_pin = "pin-sha1=" + |
- HttpUtil::Quote("6dcfXufJLW3J6S/9rRe4vUlBj5g="); |
- |
- EXPECT_TRUE(state.ParsePinsHeader( |
- now, |
- "max-age=243; " + good_pin + ";" + backup_pin, |
- ssl_info)); |
- expiry = now + base::TimeDelta::FromSeconds(243); |
- EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); |
- |
- EXPECT_TRUE(state.ParsePinsHeader( |
- now, |
- " " + good_pin + "; " + backup_pin + " ; Max-agE = 567", |
- ssl_info)); |
- expiry = now + base::TimeDelta::FromSeconds(567); |
- EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); |
- |
- EXPECT_TRUE(state.ParsePinsHeader( |
- now, |
- good_pin + ";" + backup_pin + " ; mAx-aGe = 890 ", |
- ssl_info)); |
- expiry = now + base::TimeDelta::FromSeconds(890); |
- EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); |
- |
- EXPECT_TRUE(state.ParsePinsHeader( |
- now, |
- good_pin + ";" + backup_pin + "; max-age=123;IGNORED;", |
- ssl_info)); |
- expiry = now + base::TimeDelta::FromSeconds(123); |
- EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); |
- |
- EXPECT_TRUE(state.ParsePinsHeader( |
- now, |
- "max-age=394082;" + backup_pin + ";" + good_pin + "; ", |
- ssl_info)); |
- expiry = now + base::TimeDelta::FromSeconds(394082); |
- EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); |
- |
- EXPECT_TRUE(state.ParsePinsHeader( |
- now, |
- "max-age=39408299 ;" + backup_pin + ";" + good_pin + "; ", |
- ssl_info)); |
- expiry = now + base::TimeDelta::FromSeconds( |
- std::min(TransportSecurityState::kMaxHSTSAgeSecs, 39408299l)); |
- EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); |
- |
- EXPECT_TRUE(state.ParsePinsHeader( |
- now, |
- "max-age=39408038 ; cybers=39408038 ; " + |
- good_pin + ";" + backup_pin + "; ", |
- ssl_info)); |
- expiry = now + base::TimeDelta::FromSeconds( |
- std::min(TransportSecurityState::kMaxHSTSAgeSecs, 394082038l)); |
- EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); |
- |
- EXPECT_TRUE(state.ParsePinsHeader( |
- now, |
- " max-age=0 ; " + good_pin + ";" + backup_pin, |
- ssl_info)); |
- expiry = now + base::TimeDelta::FromSeconds(0); |
- EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); |
- |
- EXPECT_TRUE(state.ParsePinsHeader( |
- now, |
- " max-age=999999999999999999999999999999999999999999999 ; " + |
- backup_pin + ";" + good_pin + "; ", |
- ssl_info)); |
- expiry = now + |
- base::TimeDelta::FromSeconds(TransportSecurityState::kMaxHSTSAgeSecs); |
- EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); |
-} |
- |
-TEST_F(TransportSecurityStateTest, ValidPinsHeadersSHA1) { |
- TestValidPinsHeaders(HASH_VALUE_SHA1); |
-} |
- |
-TEST_F(TransportSecurityStateTest, ValidPinsHeadersSHA256) { |
- TestValidPinsHeaders(HASH_VALUE_SHA256); |
-} |
- |
TEST_F(TransportSecurityStateTest, SimpleMatches) { |
TransportSecurityState state; |
TransportSecurityState::DomainState domain_state; |
@@ -913,8 +521,7 @@ |
static bool AddHash(const std::string& type_and_base64, |
HashValueVector* out) { |
HashValue hash; |
- |
- if (!TransportSecurityState::ParsePin(type_and_base64, &hash)) |
+ if (!hash.ParseBase64String(type_and_base64)) |
return false; |
out->push_back(hash); |