summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-08 21:22:45 +0000
committerrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-08 21:24:05 +0000
commit8d60aa54abe0517d756c9d625ece75feabed613a (patch)
tree2f37ad4a17f64323835d78ce33cb756b82c7326b
parenteb7b4aac673321aee0731cf5fecfeda34ac07317 (diff)
downloadchromium_src-8d60aa54abe0517d756c9d625ece75feabed613a.zip
chromium_src-8d60aa54abe0517d756c9d625ece75feabed613a.tar.gz
chromium_src-8d60aa54abe0517d756c9d625ece75feabed613a.tar.bz2
Centralize the logic for checking public key pins from ClientSocketNSS
and ProofVerifierChromium to TransportSecurityState::CheckPublicKeyPins. This required adding an is_issued_by_known_root argument to this method. In addition, CheckPublicKeyPins now only checks static pins if the TransportSecurityState's enable_static_pins_ member is true. This defaults to true only for official desktop builds. This also means that dynamic pins are now checked on mobile and on non-official builds. BUG=398925,391033 Review URL: https://codereview.chromium.org/433123003 Cr-Commit-Position: refs/heads/master@{#288435} git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288435 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/http/http_security_headers_unittest.cc32
-rw-r--r--net/http/transport_security_state.cc124
-rw-r--r--net/http/transport_security_state.h23
-rw-r--r--net/http/transport_security_state_unittest.cc123
-rw-r--r--net/quic/crypto/proof_verifier_chromium.cc54
-rw-r--r--net/socket/ssl_client_socket_nss.cc51
6 files changed, 233 insertions, 174 deletions
diff --git a/net/http/http_security_headers_unittest.cc b/net/http/http_security_headers_unittest.cc
index ce919ff..240e76d 100644
--- a/net/http/http_security_headers_unittest.cc
+++ b/net/http/http_security_headers_unittest.cc
@@ -506,6 +506,7 @@ TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPOnly) {
// docs.google.com has preloaded pins.
const bool sni_enabled = true;
std::string domain = "docs.google.com";
+ state.enable_static_pins_ = true;
EXPECT_TRUE(
state.GetStaticDomainState(domain, sni_enabled, &static_domain_state));
EXPECT_GT(static_domain_state.pkp.spki_hashes.size(), 1UL);
@@ -554,8 +555,9 @@ TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPOnly) {
HashValueVector hashes;
hashes.push_back(good_hash);
std::string failure_log;
- EXPECT_TRUE(
- state.CheckPublicKeyPins(domain, sni_enabled, hashes, &failure_log));
+ const bool is_issued_by_known_root = true;
+ EXPECT_TRUE(state.CheckPublicKeyPins(
+ domain, sni_enabled, is_issued_by_known_root, hashes, &failure_log));
TransportSecurityState::DomainState new_dynamic_domain_state;
EXPECT_TRUE(state.GetDynamicDomainState(domain, &new_dynamic_domain_state));
@@ -585,6 +587,7 @@ TEST_F(HttpSecurityHeadersTest, MAYBE_UpdateDynamicPKPMaxAge0) {
// docs.google.com has preloaded pins.
const bool sni_enabled = true;
std::string domain = "docs.google.com";
+ state.enable_static_pins_ = true;
ASSERT_TRUE(
state.GetStaticDomainState(domain, sni_enabled, &static_domain_state));
EXPECT_GT(static_domain_state.pkp.spki_hashes.size(), 1UL);
@@ -648,8 +651,13 @@ TEST_F(HttpSecurityHeadersTest, MAYBE_UpdateDynamicPKPMaxAge0) {
// 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));
+ const bool is_issued_by_known_root = true;
+ EXPECT_FALSE(
+ state.CheckPublicKeyPins(domain,
+ true,
+ is_issued_by_known_root,
+ new_static_domain_state2.pkp.spki_hashes,
+ &failure_log));
EXPECT_NE(0UL, failure_log.length());
}
#undef MAYBE_UpdateDynamicPKPMaxAge0
@@ -663,6 +671,7 @@ TEST_F(HttpSecurityHeadersTest, NoClobberPins) {
// accounts.google.com has preloaded pins.
std::string domain = "accounts.google.com";
+ state.enable_static_pins_ = true;
// Retrieve the DomainState as it is by default, including its known good
// pins.
@@ -680,8 +689,12 @@ TEST_F(HttpSecurityHeadersTest, NoClobberPins) {
EXPECT_TRUE(state.AddHSTSHeader(domain, "includesubdomains; max-age=10000"));
EXPECT_TRUE(state.ShouldUpgradeToSSL(domain, sni_enabled));
std::string failure_log;
- EXPECT_TRUE(state.CheckPublicKeyPins(
- domain, sni_enabled, saved_hashes, &failure_log));
+ const bool is_issued_by_known_root = true;
+ EXPECT_TRUE(state.CheckPublicKeyPins(domain,
+ sni_enabled,
+ is_issued_by_known_root,
+ saved_hashes,
+ &failure_log));
// Add an HPKP header, which should only update the dynamic state.
HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA1);
@@ -701,8 +714,11 @@ TEST_F(HttpSecurityHeadersTest, NoClobberPins) {
EXPECT_TRUE(state.ShouldUpgradeToSSL(domain, sni_enabled));
// The dynamic pins, which do not match |saved_hashes|, should take
// precedence over the static pins and cause the check to fail.
- EXPECT_FALSE(state.CheckPublicKeyPins(
- domain, sni_enabled, saved_hashes, &failure_log));
+ EXPECT_FALSE(state.CheckPublicKeyPins(domain,
+ sni_enabled,
+ is_issued_by_known_root,
+ saved_hashes,
+ &failure_log));
}
}; // namespace net
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc
index 0b209b3..508784e 100644
--- a/net/http/transport_security_state.cc
+++ b/net/http/transport_security_state.cc
@@ -84,7 +84,12 @@ bool AddHash(const char* sha1_hash,
} // namespace
TransportSecurityState::TransportSecurityState()
- : delegate_(NULL) {
+ : delegate_(NULL), enable_static_pins_(true) {
+// 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(OFFICIAL_BUILD) || defined(OS_ANDROID) || defined(OS_IOS)
+ enable_static_pins_ = false;
+#endif
DCHECK(CalledOnValidThread());
}
@@ -118,21 +123,36 @@ bool TransportSecurityState::ShouldUpgradeToSSL(const std::string& host,
return false;
}
-bool TransportSecurityState::CheckPublicKeyPins(const std::string& host,
- bool sni_enabled,
- const HashValueVector& hashes,
- std::string* failure_log) {
- DomainState dynamic_state;
- if (GetDynamicDomainState(host, &dynamic_state))
- return dynamic_state.CheckPublicKeyPins(hashes, failure_log);
+bool TransportSecurityState::CheckPublicKeyPins(
+ const std::string& host,
+ bool sni_available,
+ bool is_issued_by_known_root,
+ const HashValueVector& public_key_hashes,
+ std::string* pinning_failure_log) {
+ // Perform pin validation if, and only if, all these conditions obtain:
+ //
+ // * the server's certificate chain chains up to a known root (i.e. not a
+ // user-installed trust anchor); and
+ // * the build is recent (very old builds should fail open so that users
+ // have some chance to recover).
+ // * the server actually has public key pins.
+ //
+ // TODO(rsleevi): http://crbug.com/391032 - Only disable static HPKP if the
+ // build is not timely.
+ if (!is_issued_by_known_root || !IsBuildTimely() ||
+ !HasPublicKeyPins(host, sni_available)) {
+ return true;
+ }
- DomainState static_state;
- if (GetStaticDomainState(host, sni_enabled, &static_state) &&
- static_state.CheckPublicKeyPins(hashes, failure_log)) {
- return true;
+ bool pins_are_valid = CheckPublicKeyPinsImpl(
+ host, sni_available, public_key_hashes, pinning_failure_log);
+ if (!pins_are_valid) {
+ LOG(ERROR) << *pinning_failure_log;
+ ReportUMAOnPinFailure(host);
}
- return false;
+ UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid);
+ return pins_are_valid;
}
bool TransportSecurityState::HasPublicKeyPins(const std::string& host,
@@ -549,9 +569,13 @@ struct HSTSPreload {
SecondLevelDomainName second_level_domain_name;
};
-static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries,
- const std::string& canonicalized_host, size_t i,
- TransportSecurityState::DomainState* out, bool* ret) {
+static bool HasPreload(const struct HSTSPreload* entries,
+ size_t num_entries,
+ const std::string& canonicalized_host,
+ size_t i,
+ bool enable_static_pins,
+ TransportSecurityState::DomainState* out,
+ bool* ret) {
for (size_t j = 0; j < num_entries; j++) {
if (entries[j].length == canonicalized_host.size() - i &&
memcmp(entries[j].dns_name, &canonicalized_host[i],
@@ -561,26 +585,29 @@ static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries,
} else {
out->sts.include_subdomains = entries[j].include_subdomains;
out->sts.last_observed = base::GetBuildTime();
- out->pkp.include_subdomains = entries[j].include_subdomains;
- out->pkp.last_observed = base::GetBuildTime();
*ret = true;
out->sts.upgrade_mode =
TransportSecurityState::DomainState::MODE_FORCE_HTTPS;
if (!entries[j].https_required)
out->sts.upgrade_mode =
TransportSecurityState::DomainState::MODE_DEFAULT;
- if (entries[j].pins.required_hashes) {
- const char* const* sha1_hash = entries[j].pins.required_hashes;
- while (*sha1_hash) {
- AddHash(*sha1_hash, &out->pkp.spki_hashes);
- sha1_hash++;
+
+ if (enable_static_pins) {
+ out->pkp.include_subdomains = entries[j].include_subdomains;
+ out->pkp.last_observed = base::GetBuildTime();
+ if (entries[j].pins.required_hashes) {
+ const char* const* sha1_hash = entries[j].pins.required_hashes;
+ while (*sha1_hash) {
+ AddHash(*sha1_hash, &out->pkp.spki_hashes);
+ sha1_hash++;
+ }
}
- }
- if (entries[j].pins.excluded_hashes) {
- const char* const* sha1_hash = entries[j].pins.excluded_hashes;
- while (*sha1_hash) {
- AddHash(*sha1_hash, &out->pkp.bad_spki_hashes);
- sha1_hash++;
+ if (entries[j].pins.excluded_hashes) {
+ const char* const* sha1_hash = entries[j].pins.excluded_hashes;
+ while (*sha1_hash) {
+ AddHash(*sha1_hash, &out->pkp.bad_spki_hashes);
+ sha1_hash++;
+ }
}
}
}
@@ -763,6 +790,24 @@ bool TransportSecurityState::IsBuildTimely() {
return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
}
+bool TransportSecurityState::CheckPublicKeyPinsImpl(
+ const std::string& host,
+ bool sni_enabled,
+ const HashValueVector& hashes,
+ std::string* failure_log) {
+ DomainState dynamic_state;
+ if (GetDynamicDomainState(host, &dynamic_state))
+ return dynamic_state.CheckPublicKeyPins(hashes, failure_log);
+
+ DomainState static_state;
+ if (GetStaticDomainState(host, sni_enabled, &static_state))
+ return static_state.CheckPublicKeyPins(hashes, failure_log);
+
+ // HasPublicKeyPins should have returned true in order for this method
+ // to have been called, so if we fall through to here, it's an error.
+ return false;
+}
+
bool TransportSecurityState::GetStaticDomainState(const std::string& host,
bool sni_enabled,
DomainState* out) const {
@@ -781,15 +826,22 @@ bool TransportSecurityState::GetStaticDomainState(const std::string& host,
canonicalized_host.size() - i);
out->domain = DNSDomainToString(host_sub_chunk);
bool ret;
- if (is_build_timely &&
- HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out,
- &ret)) {
+ if (is_build_timely && HasPreload(kPreloadedSTS,
+ kNumPreloadedSTS,
+ canonicalized_host,
+ i,
+ enable_static_pins_,
+ out,
+ &ret)) {
return ret;
}
- if (sni_enabled &&
- is_build_timely &&
- HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i,
- out, &ret)) {
+ if (sni_enabled && is_build_timely && HasPreload(kPreloadedSNISTS,
+ kNumPreloadedSNISTS,
+ canonicalized_host,
+ i,
+ enable_static_pins_,
+ out,
+ &ret)) {
return ret;
}
}
diff --git a/net/http/transport_security_state.h b/net/http/transport_security_state.h
index 3645937..4d49da1 100644
--- a/net/http/transport_security_state.h
+++ b/net/http/transport_security_state.h
@@ -163,6 +163,7 @@ class NET_EXPORT TransportSecurityState
bool ShouldUpgradeToSSL(const std::string& host, bool sni_enabled);
bool CheckPublicKeyPins(const std::string& host,
bool sni_enabled,
+ bool is_issued_by_known_root,
const HashValueVector& hashes,
std::string* failure_log);
bool HasPublicKeyPins(const std::string& host, bool sni_enabled);
@@ -267,6 +268,14 @@ class NET_EXPORT TransportSecurityState
// The maximum number of seconds for which we'll cache an HSTS request.
static const long int kMaxHSTSAgeSecs;
+ private:
+ friend class TransportSecurityStateTest;
+ FRIEND_TEST_ALL_PREFIXES(HttpSecurityHeadersTest, UpdateDynamicPKPOnly);
+ FRIEND_TEST_ALL_PREFIXES(HttpSecurityHeadersTest, UpdateDynamicPKPMaxAge0);
+ FRIEND_TEST_ALL_PREFIXES(HttpSecurityHeadersTest, NoClobberPins);
+
+ typedef std::map<std::string, DomainState> DomainStateMap;
+
// Send an UMA report on pin validation failure, if the host is in a
// statically-defined list of domains.
//
@@ -282,12 +291,11 @@ class NET_EXPORT TransportSecurityState
// information) is timely.
static bool IsBuildTimely();
- private:
- friend class TransportSecurityStateTest;
- FRIEND_TEST_ALL_PREFIXES(HttpSecurityHeadersTest,
- UpdateDynamicPKPOnly);
-
- typedef std::map<std::string, DomainState> DomainStateMap;
+ // Helper method for actually checking pins.
+ bool CheckPublicKeyPinsImpl(const std::string& host,
+ bool sni_enabled,
+ const HashValueVector& hashes,
+ std::string* failure_log);
// If a Delegate is present, notify it that the internal state has
// changed.
@@ -309,6 +317,9 @@ class NET_EXPORT TransportSecurityState
Delegate* delegate_;
+ // True if static pins should be used.
+ bool enable_static_pins_;
+
DISALLOW_COPY_AND_ASSIGN(TransportSecurityState);
};
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc
index 476ae94..dfbc753 100644
--- a/net/http/transport_security_state_unittest.cc
+++ b/net/http/transport_security_state_unittest.cc
@@ -37,6 +37,7 @@
namespace net {
class TransportSecurityStateTest : public testing::Test {
+ public:
virtual void SetUp() {
#if defined(USE_OPENSSL)
crypto::EnsureOpenSSLInit();
@@ -45,6 +46,14 @@ class TransportSecurityStateTest : public testing::Test {
#endif
}
+ static void DisableStaticPins(TransportSecurityState* state) {
+ state->enable_static_pins_ = false;
+ }
+
+ static void EnableStaticPins(TransportSecurityState* state) {
+ state->enable_static_pins_ = true;
+ }
+
protected:
bool GetStaticDomainState(TransportSecurityState* state,
const std::string& host,
@@ -162,6 +171,27 @@ TEST_F(TransportSecurityStateTest, DeleteDynamicDataForHost) {
EXPECT_FALSE(state.GetDynamicDomainState("yahoo.com", &domain_state));
}
+TEST_F(TransportSecurityStateTest, EnableStaticPins) {
+ TransportSecurityState state;
+ TransportSecurityState::DomainState domain_state;
+
+ EnableStaticPins(&state);
+
+ EXPECT_TRUE(
+ state.GetStaticDomainState("chrome.google.com", true, &domain_state));
+ EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
+}
+
+TEST_F(TransportSecurityStateTest, DisableStaticPins) {
+ TransportSecurityState state;
+ TransportSecurityState::DomainState domain_state;
+
+ DisableStaticPins(&state);
+ EXPECT_TRUE(
+ state.GetStaticDomainState("chrome.google.com", true, &domain_state));
+ EXPECT_TRUE(domain_state.pkp.spki_hashes.empty());
+}
+
TEST_F(TransportSecurityStateTest, IsPreloaded) {
const std::string paypal = "paypal.com";
const std::string www_paypal = "www.paypal.com";
@@ -177,7 +207,6 @@ TEST_F(TransportSecurityStateTest, IsPreloaded) {
EXPECT_TRUE(GetStaticDomainState(&state, paypal, true, &domain_state));
EXPECT_TRUE(GetStaticDomainState(&state, www_paypal, true, &domain_state));
EXPECT_FALSE(domain_state.sts.include_subdomains);
- EXPECT_FALSE(domain_state.pkp.include_subdomains);
EXPECT_FALSE(GetStaticDomainState(&state, a_www_paypal, true, &domain_state));
EXPECT_FALSE(GetStaticDomainState(&state, abc_paypal, true, &domain_state));
EXPECT_FALSE(GetStaticDomainState(&state, example, true, &domain_state));
@@ -214,6 +243,7 @@ static bool HasStaticState(const char* hostname) {
static bool HasStaticPublicKeyPins(const char* hostname, bool sni_enabled) {
TransportSecurityState state;
+ TransportSecurityStateTest::EnableStaticPins(&state);
TransportSecurityState::DomainState domain_state;
if (!state.GetStaticDomainState(hostname, sni_enabled, &domain_state))
return false;
@@ -227,6 +257,7 @@ static bool HasStaticPublicKeyPins(const char* hostname) {
static bool OnlyPinningInStaticState(const char* hostname) {
TransportSecurityState state;
+ TransportSecurityStateTest::EnableStaticPins(&state);
TransportSecurityState::DomainState domain_state;
if (!state.GetStaticDomainState(hostname, true /* SNI ok */, &domain_state))
return false;
@@ -285,24 +316,6 @@ TEST_F(TransportSecurityStateTest, Preloaded) {
EXPECT_FALSE(HasStaticState("m.gmail.com"));
EXPECT_FALSE(HasStaticState("m.googlemail.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("www.google.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("foo.google.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("google.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("www.youtube.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("youtube.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("i.ytimg.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("ytimg.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("googleusercontent.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("www.googleusercontent.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("www.google-analytics.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("googleapis.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("googleadservices.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("googlecode.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("appspot.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("googlesyndication.com"));
- EXPECT_TRUE(OnlyPinningInStaticState("doubleclick.net"));
- EXPECT_TRUE(OnlyPinningInStaticState("googlegroups.com"));
-
// Tests for domains that don't work without SNI.
EXPECT_FALSE(state.GetStaticDomainState("gmail.com", false, &domain_state));
EXPECT_FALSE(
@@ -407,28 +420,12 @@ TEST_F(TransportSecurityStateTest, Preloaded) {
EXPECT_TRUE(StaticShouldRedirect("www.dropcam.com"));
EXPECT_FALSE(HasStaticState("foo.dropcam.com"));
- EXPECT_TRUE(
- state.GetStaticDomainState("torproject.org", false, &domain_state));
- EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
- EXPECT_TRUE(
- state.GetStaticDomainState("www.torproject.org", false, &domain_state));
- EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
- EXPECT_TRUE(
- state.GetStaticDomainState("check.torproject.org", false, &domain_state));
- EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
- EXPECT_TRUE(
- state.GetStaticDomainState("blog.torproject.org", false, &domain_state));
- EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
EXPECT_TRUE(StaticShouldRedirect("ebanking.indovinabank.com.vn"));
EXPECT_TRUE(StaticShouldRedirect("foo.ebanking.indovinabank.com.vn"));
EXPECT_TRUE(StaticShouldRedirect("epoxate.com"));
EXPECT_FALSE(HasStaticState("foo.epoxate.com"));
- EXPECT_TRUE(HasStaticPublicKeyPins("torproject.org"));
- EXPECT_TRUE(HasStaticPublicKeyPins("www.torproject.org"));
- EXPECT_TRUE(HasStaticPublicKeyPins("check.torproject.org"));
- EXPECT_TRUE(HasStaticPublicKeyPins("blog.torproject.org"));
EXPECT_FALSE(HasStaticState("foo.torproject.org"));
EXPECT_TRUE(StaticShouldRedirect("www.moneybookers.com"));
@@ -478,6 +475,57 @@ TEST_F(TransportSecurityStateTest, Preloaded) {
EXPECT_TRUE(StaticShouldRedirect("crate.io"));
EXPECT_TRUE(StaticShouldRedirect("foo.crate.io"));
+}
+
+TEST_F(TransportSecurityStateTest, PreloadedPins) {
+ TransportSecurityState state;
+ EnableStaticPins(&state);
+ TransportSecurityState::DomainState domain_state;
+
+ // We do more extensive checks for the first domain.
+ EXPECT_TRUE(
+ state.GetStaticDomainState("www.paypal.com", true, &domain_state));
+ EXPECT_EQ(domain_state.sts.upgrade_mode,
+ TransportSecurityState::DomainState::MODE_FORCE_HTTPS);
+ EXPECT_FALSE(domain_state.sts.include_subdomains);
+ EXPECT_FALSE(domain_state.pkp.include_subdomains);
+
+ EXPECT_TRUE(OnlyPinningInStaticState("www.google.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("foo.google.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("google.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("www.youtube.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("youtube.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("i.ytimg.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("ytimg.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("googleusercontent.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("www.googleusercontent.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("www.google-analytics.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("googleapis.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("googleadservices.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("googlecode.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("appspot.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("googlesyndication.com"));
+ EXPECT_TRUE(OnlyPinningInStaticState("doubleclick.net"));
+ EXPECT_TRUE(OnlyPinningInStaticState("googlegroups.com"));
+
+ EXPECT_TRUE(HasStaticPublicKeyPins("torproject.org"));
+ EXPECT_TRUE(HasStaticPublicKeyPins("www.torproject.org"));
+ EXPECT_TRUE(HasStaticPublicKeyPins("check.torproject.org"));
+ EXPECT_TRUE(HasStaticPublicKeyPins("blog.torproject.org"));
+ EXPECT_FALSE(HasStaticState("foo.torproject.org"));
+
+ EXPECT_TRUE(
+ state.GetStaticDomainState("torproject.org", false, &domain_state));
+ EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
+ EXPECT_TRUE(
+ state.GetStaticDomainState("www.torproject.org", false, &domain_state));
+ EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
+ EXPECT_TRUE(
+ state.GetStaticDomainState("check.torproject.org", false, &domain_state));
+ EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
+ EXPECT_TRUE(
+ state.GetStaticDomainState("blog.torproject.org", false, &domain_state));
+ EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
EXPECT_TRUE(HasStaticPublicKeyPins("www.twitter.com"));
}
@@ -495,6 +543,7 @@ TEST_F(TransportSecurityStateTest, LongNames) {
TEST_F(TransportSecurityStateTest, BuiltinCertPins) {
TransportSecurityState state;
+ EnableStaticPins(&state);
TransportSecurityState::DomainState domain_state;
EXPECT_TRUE(
@@ -534,7 +583,6 @@ TEST_F(TransportSecurityStateTest, BuiltinCertPins) {
EXPECT_TRUE(HasStaticPublicKeyPins("ssl.google-analytics.com"));
EXPECT_TRUE(HasStaticPublicKeyPins("www.googleplex.com"));
- // Disabled in order to help track down pinning failures --agl
EXPECT_TRUE(HasStaticPublicKeyPins("twitter.com"));
EXPECT_FALSE(HasStaticPublicKeyPins("foo.twitter.com"));
EXPECT_TRUE(HasStaticPublicKeyPins("www.twitter.com"));
@@ -585,6 +633,8 @@ TEST_F(TransportSecurityStateTest, PinValidationWithoutRejectedCerts) {
}
TransportSecurityState state;
+ EnableStaticPins(&state);
+
TransportSecurityState::DomainState domain_state;
EXPECT_TRUE(
state.GetStaticDomainState("blog.torproject.org", true, &domain_state));
@@ -597,6 +647,7 @@ TEST_F(TransportSecurityStateTest, PinValidationWithoutRejectedCerts) {
TEST_F(TransportSecurityStateTest, OptionalHSTSCertPins) {
TransportSecurityState state;
+ EnableStaticPins(&state);
TransportSecurityState::DomainState domain_state;
EXPECT_FALSE(StaticShouldRedirect("www.google-analytics.com"));
diff --git a/net/quic/crypto/proof_verifier_chromium.cc b/net/quic/crypto/proof_verifier_chromium.cc
index 90e03fe..9ed83db 100644
--- a/net/quic/crypto/proof_verifier_chromium.cc
+++ b/net/quic/crypto/proof_verifier_chromium.cc
@@ -236,58 +236,20 @@ int ProofVerifierChromium::Job::DoVerifyCert(int result) {
int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) {
verifier_.reset();
-#if defined(OFFICIAL_BUILD) && !defined(OS_ANDROID) && !defined(OS_IOS)
- // TODO(wtc): The following code was copied from ssl_client_socket_nss.cc.
- // Convert it to a new function that can be called by both files. These
- // variables simulate the arguments to the new function.
const CertVerifyResult& cert_verify_result =
verify_details_->cert_verify_result;
- bool sni_available = true;
- const std::string& host = hostname_;
- TransportSecurityState* transport_security_state = transport_security_state_;
- std::string* pinning_failure_log = &verify_details_->pinning_failure_log;
-
- // Take care of any mandates for public key pinning.
- //
- // Pinning is only enabled for official builds to make sure that others don't
- // end up with pins that cannot be easily updated.
- //
- // TODO(agl): We might have an issue here where a request for foo.example.com
- // merges into a SPDY connection to www.example.com, and gets a different
- // certificate.
-
- // Perform pin validation if, and only if, all these conditions obtain:
- //
- // * a TransportSecurityState object is available;
- // * the server's certificate chain is valid (or suffers from only a minor
- // error);
- // * the server's certificate chain chains up to a known root (i.e. not a
- // user-installed trust anchor); and
- // * the build is recent (very old builds should fail open so that users
- // have some chance to recover).
- //
const CertStatus cert_status = cert_verify_result.cert_status;
- if (transport_security_state &&
+ if (transport_security_state_ &&
(result == OK ||
(IsCertificateError(result) && IsCertStatusMinorError(cert_status))) &&
- cert_verify_result.is_issued_by_known_root &&
- TransportSecurityState::IsBuildTimely()) {
- if (transport_security_state->HasPublicKeyPins(host, sni_available)) {
- if (!transport_security_state->CheckPublicKeyPins(
- host,
- sni_available,
- cert_verify_result.public_key_hashes,
- pinning_failure_log)) {
- LOG(ERROR) << *pinning_failure_log;
- result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
- UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", false);
- TransportSecurityState::ReportUMAOnPinFailure(host);
- } else {
- UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", true);
- }
- }
+ !transport_security_state_->CheckPublicKeyPins(
+ hostname_,
+ true, /* sni_available */
+ cert_verify_result.is_issued_by_known_root,
+ cert_verify_result.public_key_hashes,
+ &verify_details_->pinning_failure_log)) {
+ result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
}
-#endif
if (result != OK) {
std::string error_string = ErrorToString(result);
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 0d3c53d..92af627 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -3427,53 +3427,20 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
if (result == OK)
LogConnectionTypeMetrics();
-#if defined(OFFICIAL_BUILD) && !defined(OS_ANDROID) && !defined(OS_IOS)
- // Take care of any mandates for public key pinning.
- //
- // Pinning is only enabled for official builds to make sure that others don't
- // end up with pins that cannot be easily updated.
- //
- // TODO(agl): We might have an issue here where a request for foo.example.com
- // merges into a SPDY connection to www.example.com, and gets a different
- // certificate.
-
- // Perform pin validation if, and only if, all these conditions obtain:
- //
- // * a TransportSecurityState object is available;
- // * the server's certificate chain is valid (or suffers from only a minor
- // error);
- // * the server's certificate chain chains up to a known root (i.e. not a
- // user-installed trust anchor); and
- // * the build is recent (very old builds should fail open so that users
- // have some chance to recover).
- //
+ bool sni_available = ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1 ||
+ ssl_config_.version_fallback;
const CertStatus cert_status = server_cert_verify_result_.cert_status;
if (transport_security_state_ &&
(result == OK ||
(IsCertificateError(result) && IsCertStatusMinorError(cert_status))) &&
- server_cert_verify_result_.is_issued_by_known_root &&
- TransportSecurityState::IsBuildTimely()) {
- bool sni_available =
- ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1 ||
- ssl_config_.version_fallback;
- const std::string& host = host_and_port_.host();
-
- if (transport_security_state_->HasPublicKeyPins(host, sni_available)) {
- if (!transport_security_state_->CheckPublicKeyPins(
- host,
- sni_available,
- server_cert_verify_result_.public_key_hashes,
- &pinning_failure_log_)) {
- LOG(ERROR) << pinning_failure_log_;
- result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
- UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", false);
- TransportSecurityState::ReportUMAOnPinFailure(host);
- } else {
- UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", true);
- }
- }
+ !transport_security_state_->CheckPublicKeyPins(
+ host_and_port_.host(),
+ sni_available,
+ server_cert_verify_result_.is_issued_by_known_root,
+ server_cert_verify_result_.public_key_hashes,
+ &pinning_failure_log_)) {
+ result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
}
-#endif
if (result == OK) {
// Only check Certificate Transparency if there were no other errors with