Index: chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc |
diff --git a/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc b/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc |
index ffcfc3b0b3209dc30218c6fe1c99398733898c50..16f035093dba4a31ffa29c57a376313799994a79 100644 |
--- a/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc |
+++ b/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc |
@@ -110,6 +110,7 @@ void CheckBrokenSecurityStyle(const SecurityStyleTestObserver& observer, |
observer.latest_explanations(); |
EXPECT_EQ(0u, expired_explanation.unauthenticated_explanations.size()); |
ASSERT_EQ(1u, expired_explanation.broken_explanations.size()); |
+ EXPECT_FALSE(expired_explanation.pkp_bypassed); |
// Check that the summary and description are as expected. |
EXPECT_EQ(l10n_util::GetStringUTF8(IDS_CERTIFICATE_CHAIN_ERROR), |
@@ -165,6 +166,7 @@ void CheckSecurityInfoForSecure( |
SecurityStateModel::SecurityLevel expect_security_level, |
SecurityStateModel::SHA1DeprecationStatus expect_sha1_status, |
SecurityStateModel::MixedContentStatus expect_mixed_content_status, |
+ bool pkp_bypassed, |
bool expect_cert_error) { |
ASSERT_TRUE(contents); |
@@ -178,6 +180,7 @@ void CheckSecurityInfoForSecure( |
EXPECT_EQ(expect_mixed_content_status, security_info.mixed_content_status); |
EXPECT_TRUE(security_info.sct_verify_statuses.empty()); |
EXPECT_TRUE(security_info.scheme_is_cryptographic); |
+ EXPECT_EQ(pkp_bypassed, security_info.pkp_bypassed); |
EXPECT_EQ(expect_cert_error, |
net::IsCertStatusError(security_info.cert_status)); |
EXPECT_GT(security_info.security_bits, 0); |
@@ -315,7 +318,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, HttpsPage) { |
CheckSecurityInfoForSecure( |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURE, SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::NO_MIXED_CONTENT, |
+ SecurityStateModel::NO_MIXED_CONTENT, false, |
false /* expect cert status error */); |
} |
@@ -333,7 +336,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, SHA1Broken) { |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURITY_ERROR, |
SecurityStateModel::DEPRECATED_SHA1_MAJOR, |
- SecurityStateModel::NO_MIXED_CONTENT, |
+ SecurityStateModel::NO_MIXED_CONTENT, false, |
false /* expect cert status error */); |
} |
@@ -357,7 +360,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, MixedContent) { |
CheckSecurityInfoForSecure( |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::NONE, SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::DISPLAYED_MIXED_CONTENT, |
+ SecurityStateModel::DISPLAYED_MIXED_CONTENT, false, |
false /* expect cert status error */); |
// Navigate to an HTTPS page that displays mixed content dynamically. |
@@ -369,7 +372,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, MixedContent) { |
CheckSecurityInfoForSecure( |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURE, SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::NO_MIXED_CONTENT, |
+ SecurityStateModel::NO_MIXED_CONTENT, false, |
false /* expect cert status error */); |
// Load the insecure image. |
bool js_result = false; |
@@ -380,7 +383,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, MixedContent) { |
CheckSecurityInfoForSecure( |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::NONE, SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::DISPLAYED_MIXED_CONTENT, |
+ SecurityStateModel::DISPLAYED_MIXED_CONTENT, false, |
false /* expect cert status error */); |
// Navigate to an HTTPS page that runs mixed content. |
@@ -393,7 +396,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, MixedContent) { |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURITY_ERROR, |
SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::RAN_MIXED_CONTENT, |
+ SecurityStateModel::RAN_MIXED_CONTENT, false, |
false /* expect cert status error */); |
// Navigate to an HTTPS page that runs and displays mixed content. |
@@ -406,7 +409,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, MixedContent) { |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURITY_ERROR, |
SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT, |
+ SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT, false, |
false /* expect cert status error */); |
// Navigate to an HTTPS page that runs mixed content in an iframe. |
@@ -426,7 +429,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, MixedContent) { |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURITY_ERROR, |
SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::RAN_MIXED_CONTENT, |
+ SecurityStateModel::RAN_MIXED_CONTENT, false, |
false /* expect cert status error */); |
} |
@@ -458,7 +461,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURITY_ERROR, |
SecurityStateModel::DEPRECATED_SHA1_MAJOR, |
- SecurityStateModel::DISPLAYED_MIXED_CONTENT, |
+ SecurityStateModel::DISPLAYED_MIXED_CONTENT, false, |
false /* expect cert status error */); |
// Navigate to an HTTPS page that displays mixed content dynamically. |
@@ -471,7 +474,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURITY_ERROR, |
SecurityStateModel::DEPRECATED_SHA1_MAJOR, |
- SecurityStateModel::NO_MIXED_CONTENT, |
+ SecurityStateModel::NO_MIXED_CONTENT, false, |
false /* expect cert status error */); |
// Load the insecure image. |
bool js_result = false; |
@@ -483,7 +486,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURITY_ERROR, |
SecurityStateModel::DEPRECATED_SHA1_MAJOR, |
- SecurityStateModel::DISPLAYED_MIXED_CONTENT, |
+ SecurityStateModel::DISPLAYED_MIXED_CONTENT, false, |
false /* expect cert status error */); |
// Navigate to an HTTPS page that runs mixed content. |
@@ -496,7 +499,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURITY_ERROR, |
SecurityStateModel::DEPRECATED_SHA1_MAJOR, |
- SecurityStateModel::RAN_MIXED_CONTENT, |
+ SecurityStateModel::RAN_MIXED_CONTENT, false, |
false /* expect cert status error */); |
// Navigate to an HTTPS page that runs and displays mixed content. |
@@ -509,7 +512,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURITY_ERROR, |
SecurityStateModel::DEPRECATED_SHA1_MAJOR, |
- SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT, |
+ SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT, false, |
false /* expect cert status error */); |
} |
@@ -536,7 +539,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, |
CheckSecurityInfoForSecure( |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURE, SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::NO_MIXED_CONTENT, |
+ SecurityStateModel::NO_MIXED_CONTENT, false, |
false /* expect cert status error */); |
} |
@@ -552,7 +555,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, BrokenHTTPS) { |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURITY_ERROR, |
SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::NO_MIXED_CONTENT, |
+ SecurityStateModel::NO_MIXED_CONTENT, false, |
true /* expect cert status error */); |
ProceedThroughInterstitial( |
@@ -562,7 +565,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, BrokenHTTPS) { |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURITY_ERROR, |
SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::NO_MIXED_CONTENT, |
+ SecurityStateModel::NO_MIXED_CONTENT, false, |
true /* expect cert status error */); |
// Navigate to a broken HTTPS page that displays mixed content. |
@@ -576,10 +579,95 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, BrokenHTTPS) { |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURITY_ERROR, |
SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::DISPLAYED_MIXED_CONTENT, |
+ SecurityStateModel::DISPLAYED_MIXED_CONTENT, false, |
true /* expect cert status error */); |
} |
+const char kReportURI[] = "https://report-hpkp.test"; |
+ |
+class PKPModelClientTest : public ChromeSecurityStateModelClientTest { |
+ public: |
+ void SetUpOnMainThread() override { |
+ ASSERT_TRUE(https_server_.Start()); |
+ url_request_context_getter_ = browser()->profile()->GetRequestContext(); |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&PKPModelClientTest::SetUpOnIOThread, this)); |
+ } |
+ |
+ void SetUpOnIOThread() { |
+ net::URLRequestContext* request_context = |
+ url_request_context_getter_->GetURLRequestContext(); |
+ net::TransportSecurityState* security_state = |
+ request_context->transport_security_state(); |
+ |
+ base::Time expiration = |
+ base::Time::Now() + base::TimeDelta::FromSeconds(10000); |
+ |
+ net::HashValue hash(net::HASH_VALUE_SHA256); |
+ memset(hash.data(), 0x99, hash.size()); |
+ net::HashValueVector hashes; |
+ hashes.push_back(hash); |
+ |
+ security_state->AddHPKP(https_server_.host_port_pair().host(), expiration, |
+ true, hashes, GURL(kReportURI)); |
+ } |
+ |
+ protected: |
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; |
+}; |
+ |
+IN_PROC_BROWSER_TEST_F(PKPModelClientTest, PKPBypass) { |
+ content::WebContents* web_contents = |
+ browser()->tab_strip_model()->GetActiveWebContents(); |
+ SecurityStyleTestObserver observer(web_contents); |
+ |
+ scoped_refptr<net::X509Certificate> cert(https_server_.GetCertificate()); |
+ net::CertVerifyResult verify_result; |
+ // PKP is bypassed when |is_issued_by_known_root| is false. |
+ verify_result.is_issued_by_known_root = false; |
+ verify_result.verified_cert = cert; |
+ net::HashValue hash(net::HASH_VALUE_SHA256); |
+ memset(hash.data(), 1, hash.size()); |
+ verify_result.public_key_hashes.push_back(hash); |
+ |
+ mock_cert_verifier()->AddResultForCert(cert.get(), verify_result, net::OK); |
+ |
+ ui_test_utils::NavigateToURL(browser(), |
+ https_server_.GetURL("/ssl/google.html")); |
+ |
+ CheckSecurityInfoForSecure( |
+ browser()->tab_strip_model()->GetActiveWebContents(), |
+ SecurityStateModel::SECURE, SecurityStateModel::NO_DEPRECATED_SHA1, |
+ SecurityStateModel::NO_MIXED_CONTENT, true, false); |
+ |
+ const content::SecurityStyleExplanations& explanation = |
+ observer.latest_explanations(); |
+ EXPECT_TRUE(explanation.pkp_bypassed); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PKPModelClientTest, PKPEnforced) { |
+ content::WebContents* web_contents = |
+ browser()->tab_strip_model()->GetActiveWebContents(); |
+ SecurityStyleTestObserver observer(web_contents); |
+ |
+ scoped_refptr<net::X509Certificate> cert(https_server_.GetCertificate()); |
+ net::CertVerifyResult verify_result; |
+ // PKP requires |is_issued_by_known_root| to be true. |
+ verify_result.is_issued_by_known_root = true; |
+ verify_result.verified_cert = cert; |
+ net::HashValue hash(net::HASH_VALUE_SHA256); |
+ memset(hash.data(), 1, hash.size()); |
+ verify_result.public_key_hashes.push_back(hash); |
+ |
+ mock_cert_verifier()->AddResultForCert(cert.get(), verify_result, net::OK); |
+ |
+ ui_test_utils::NavigateToURL(browser(), |
+ https_server_.GetURL("/ssl/google.html")); |
+ CheckBrokenSecurityStyle(observer, net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN, |
+ browser()); |
+} |
+ |
// Fails requests with ERR_IO_PENDING. Can be used to simulate a navigation |
// that never stops loading. |
class PendingJobInterceptor : public net::URLRequestInterceptor { |
@@ -637,7 +725,7 @@ IN_PROC_BROWSER_TEST_F(SecurityStateModelLoadingTest, NavigationStateChanges) { |
CheckSecurityInfoForSecure( |
browser()->tab_strip_model()->GetActiveWebContents(), |
SecurityStateModel::SECURE, SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::NO_MIXED_CONTENT, |
+ SecurityStateModel::NO_MIXED_CONTENT, false, |
false /* expect cert status error */); |
// Navigate to a page that doesn't finish loading. Test that the |
@@ -669,14 +757,14 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, AddedTab) { |
EXPECT_TRUE(content::WaitForLoadStop(new_contents)); |
CheckSecurityInfoForSecure(new_contents, SecurityStateModel::SECURE, |
SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::NO_MIXED_CONTENT, |
+ SecurityStateModel::NO_MIXED_CONTENT, false, |
false /* expect cert status error */); |
browser()->tab_strip_model()->InsertWebContentsAt(0, new_contents, |
TabStripModel::ADD_NONE); |
CheckSecurityInfoForSecure(new_contents, SecurityStateModel::SECURE, |
SecurityStateModel::NO_DEPRECATED_SHA1, |
- SecurityStateModel::NO_MIXED_CONTENT, |
+ SecurityStateModel::NO_MIXED_CONTENT, false, |
false /* expect cert status error */); |
} |
@@ -707,6 +795,7 @@ IN_PROC_BROWSER_TEST_F(SecurityStyleChangedTest, SecurityStyleChangedObserver) { |
EXPECT_EQ(0u, observer.latest_explanations().broken_explanations.size()); |
EXPECT_EQ(0u, observer.latest_explanations().secure_explanations.size()); |
EXPECT_FALSE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); |
EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
@@ -728,6 +817,7 @@ IN_PROC_BROWSER_TEST_F(SecurityStyleChangedTest, SecurityStyleChangedObserver) { |
CheckSecureExplanations(mixed_content_explanation.secure_explanations, |
VALID_CERTIFICATE, browser()); |
EXPECT_TRUE(mixed_content_explanation.scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); |
EXPECT_TRUE(mixed_content_explanation.displayed_insecure_content); |
EXPECT_FALSE(mixed_content_explanation.ran_insecure_content); |
EXPECT_EQ(content::SECURITY_STYLE_UNAUTHENTICATED, |
@@ -747,6 +837,7 @@ IN_PROC_BROWSER_TEST_F(SecurityStyleChangedTest, SecurityStyleChangedObserver) { |
CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
INVALID_CERTIFICATE, browser()); |
EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); |
EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
@@ -762,6 +853,7 @@ IN_PROC_BROWSER_TEST_F(SecurityStyleChangedTest, SecurityStyleChangedObserver) { |
CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
VALID_CERTIFICATE, browser()); |
EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); |
EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
@@ -774,6 +866,7 @@ IN_PROC_BROWSER_TEST_F(SecurityStyleChangedTest, SecurityStyleChangedObserver) { |
CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
INVALID_CERTIFICATE, browser()); |
EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); |
EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
@@ -790,6 +883,7 @@ IN_PROC_BROWSER_TEST_F(SecurityStyleChangedTest, SecurityStyleChangedObserver) { |
CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
INVALID_CERTIFICATE, browser()); |
EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); |
EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
} |
@@ -822,6 +916,7 @@ IN_PROC_BROWSER_TEST_F(SecurityStyleChangedTest, |
CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
VALID_CERTIFICATE, browser()); |
EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); |
EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
@@ -846,6 +941,7 @@ IN_PROC_BROWSER_TEST_F(SecurityStyleChangedTest, |
CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
INVALID_CERTIFICATE, browser()); |
EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); |
EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
@@ -864,6 +960,7 @@ IN_PROC_BROWSER_TEST_F(SecurityStyleChangedTest, |
CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
VALID_CERTIFICATE, browser()); |
EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); |
EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
} |