Index: chrome/browser/ssl/ssl_browser_tests.cc |
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc |
index ee444e10b774b24f561bb50bf656c51b20075a06..e7f082f610e3bfbd71933e6757faf9c38a9d84e2 100644 |
--- a/chrome/browser/ssl/ssl_browser_tests.cc |
+++ b/chrome/browser/ssl/ssl_browser_tests.cc |
@@ -106,6 +106,7 @@ |
#include "net/ssl/ssl_info.h" |
#include "net/test/cert_test_util.h" |
#include "net/test/embedded_test_server/embedded_test_server.h" |
+#include "net/test/embedded_test_server/http_request.h" |
#include "net/test/embedded_test_server/request_handler_util.h" |
#include "net/test/spawned_test_server/spawned_test_server.h" |
#include "net/test/test_certificate_data.h" |
@@ -3603,10 +3604,56 @@ IN_PROC_BROWSER_TEST_F(SSLNetworkTimeBrowserTest, |
TriggerTimeResponse(); |
} |
+namespace { |
+ |
+// Fails with a CHECK for all requests over HTTP except for favicons. This is to |
+// ensure that name mismatch redirect feature's suggest URL ping stops on |
+// redirects and never hits an HTTP URL. |
+class HttpNameMismatchPingInterceptor : public net::URLRequestInterceptor { |
+ public: |
+ HttpNameMismatchPingInterceptor() {} |
+ ~HttpNameMismatchPingInterceptor() override {} |
+ |
+ net::URLRequestJob* MaybeInterceptRequest( |
+ net::URLRequest* request, |
+ net::NetworkDelegate* delegate) const override { |
+ if (request->url().path() == "/favicon.ico") { |
+ // When a page doesn't list a favicon, a favicon request is automatically |
+ // made over HTTP. These are harmless and don't leak the original page's |
+ // URL, so ignore them. |
+ return nullptr; |
+ } |
+ |
+ EXPECT_TRUE(false) |
+ << "Name mismatch pings must never be over HTTP. This request was for " |
+ << request->url(); |
+ return nullptr; |
+ } |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(HttpNameMismatchPingInterceptor); |
+}; |
+ |
+void SetUpHttpNameMismatchPingInterceptorOnIOThread() { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
+ // Add interceptors for HTTP versions of example.org and www.example.org. |
+ // These are the hostnames used in the tests, and we never want them to be |
+ // contacted over HTTP. |
+ net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( |
+ "http", "example.org", |
+ std::unique_ptr<HttpNameMismatchPingInterceptor>( |
+ new HttpNameMismatchPingInterceptor())); |
+ net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( |
+ "http", "www.example.org", |
+ std::unique_ptr<HttpNameMismatchPingInterceptor>( |
+ new HttpNameMismatchPingInterceptor())); |
+} |
+ |
+} // namespace |
+ |
class CommonNameMismatchBrowserTest : public CertVerifierBrowserTest { |
public: |
CommonNameMismatchBrowserTest() : CertVerifierBrowserTest() {} |
- ~CommonNameMismatchBrowserTest() override {} |
void SetUpCommandLine(base::CommandLine* command_line) override { |
// Enable finch experiment for SSL common name mismatch handling. |
@@ -3617,6 +3664,15 @@ class CommonNameMismatchBrowserTest : public CertVerifierBrowserTest { |
void SetUpOnMainThread() override { |
CertVerifierBrowserTest::SetUpOnMainThread(); |
host_resolver()->AddRule("*", "127.0.0.1"); |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&SetUpHttpNameMismatchPingInterceptorOnIOThread)); |
+ } |
+ |
+ void TearDownOnMainThread() override { |
+ content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&CleanUpOnIOThread)); |
+ CertVerifierBrowserTest::TearDownOnMainThread(); |
} |
}; |
@@ -3625,14 +3681,14 @@ class CommonNameMismatchBrowserTest : public CertVerifierBrowserTest { |
// mail.example.com. |
IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
ShouldShowWWWSubdomainMismatchInterstitial) { |
- net::EmbeddedTestServer https_server_example_domain_( |
+ net::EmbeddedTestServer https_server_example_domain( |
net::EmbeddedTestServer::TYPE_HTTPS); |
- https_server_example_domain_.ServeFilesFromSourceDirectory( |
+ https_server_example_domain.ServeFilesFromSourceDirectory( |
base::FilePath(kDocRoot)); |
- ASSERT_TRUE(https_server_example_domain_.Start()); |
+ ASSERT_TRUE(https_server_example_domain.Start()); |
scoped_refptr<net::X509Certificate> cert = |
- https_server_example_domain_.GetCertificate(); |
+ https_server_example_domain.GetCertificate(); |
// Use the "spdy_pooling.pem" cert which has "mail.example.com" |
// as one of its SANs. |
@@ -3656,11 +3712,11 @@ IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
// Use a complex URL to ensure the path, etc., are preserved. The path itself |
// does not matter. |
- GURL https_server_url = |
- https_server_example_domain_.GetURL("/ssl/google.html?a=b#anchor"); |
+ const GURL https_server_url = |
+ https_server_example_domain.GetURL("/ssl/google.html?a=b#anchor"); |
GURL::Replacements replacements; |
replacements.SetHostStr("www.mail.example.com"); |
- GURL https_server_mismatched_url = |
+ const GURL https_server_mismatched_url = |
https_server_url.ReplaceComponents(replacements); |
WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); |
@@ -3685,14 +3741,14 @@ IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
// for www.example.org. Verify that the page redirects to www.example.org. |
IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
CheckWWWSubdomainMismatchInverse) { |
- net::EmbeddedTestServer https_server_example_domain_( |
+ net::EmbeddedTestServer https_server_example_domain( |
net::EmbeddedTestServer::TYPE_HTTPS); |
- https_server_example_domain_.ServeFilesFromSourceDirectory( |
+ https_server_example_domain.ServeFilesFromSourceDirectory( |
base::FilePath(kDocRoot)); |
- ASSERT_TRUE(https_server_example_domain_.Start()); |
+ ASSERT_TRUE(https_server_example_domain.Start()); |
scoped_refptr<net::X509Certificate> cert = |
- https_server_example_domain_.GetCertificate(); |
+ https_server_example_domain.GetCertificate(); |
net::CertVerifyResult verify_result; |
verify_result.verified_cert = |
@@ -3709,11 +3765,11 @@ IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
mock_cert_verifier()->AddResultForCertAndHost(cert.get(), "www.example.org", |
verify_result_valid, net::OK); |
- GURL https_server_url = |
- https_server_example_domain_.GetURL("/ssl/google.html?a=b"); |
+ const GURL https_server_url = |
+ https_server_example_domain.GetURL("/ssl/google.html?a=b"); |
GURL::Replacements replacements; |
replacements.SetHostStr("example.org"); |
- GURL https_server_mismatched_url = |
+ const GURL https_server_mismatched_url = |
https_server_url.ReplaceComponents(replacements); |
WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); |
@@ -3729,6 +3785,85 @@ IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
AuthState::NONE); |
} |
+namespace { |
+// Redirects incoming request to http://example.org. |
+std::unique_ptr<net::test_server::HttpResponse> HTTPSToHTTPRedirectHandler( |
+ const net::EmbeddedTestServer* test_server, |
+ const net::test_server::HttpRequest& request) { |
+ GURL::Replacements replacements; |
+ replacements.SetHostStr("example.org"); |
+ replacements.SetSchemeStr("http"); |
+ const GURL redirect_url = |
+ test_server->base_url().ReplaceComponents(replacements); |
+ |
+ std::unique_ptr<net::test_server::BasicHttpResponse> http_response( |
+ new net::test_server::BasicHttpResponse); |
+ http_response->set_code(net::HTTP_MOVED_PERMANENTLY); |
+ http_response->AddCustomHeader("Location", redirect_url.spec()); |
+ return std::move(http_response); |
+} |
+} // namespace |
+ |
+// Common name mismatch handling feature should ignore redirects when pinging |
+// the suggested hostname. Visit the URL example.org on a server that presents a |
+// valid certificate for www.example.org. In this case, www.example.org |
+// redirects to http://example.org, and the SSL error should not be redirected |
+// to this URL. |
+IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
+ WWWSubdomainMismatch_StopOnRedirects) { |
+ net::EmbeddedTestServer https_server_example_domain( |
+ net::EmbeddedTestServer::TYPE_HTTPS); |
+ |
+ // Redirect all URLs to http://example.org. Since this test will trigger only |
+ // one request to check the suggested URL, redirecting all requests is OK. |
+ // We would normally use content::SetupCrossSiteRedirector here, but that |
+ // function does not support https to http redirects. |
+ // This must be done before ServeFilesFromSourceDirectory(), otherwise the |
+ // test server will serve files instead of redirecting requests to them. |
+ https_server_example_domain.RegisterRequestHandler( |
+ base::Bind(&HTTPSToHTTPRedirectHandler, &https_server_example_domain)); |
+ |
+ https_server_example_domain.ServeFilesFromSourceDirectory( |
+ base::FilePath(kDocRoot)); |
+ |
+ ASSERT_TRUE(https_server_example_domain.Start()); |
+ |
+ scoped_refptr<net::X509Certificate> cert = |
+ https_server_example_domain.GetCertificate(); |
+ |
+ net::CertVerifyResult verify_result; |
+ verify_result.verified_cert = |
+ net::ImportCertFromFile(net::GetTestCertsDirectory(), "spdy_pooling.pem"); |
+ verify_result.cert_status = net::CERT_STATUS_COMMON_NAME_INVALID; |
+ |
+ mock_cert_verifier()->AddResultForCertAndHost( |
+ cert.get(), "example.org", verify_result, |
+ net::ERR_CERT_COMMON_NAME_INVALID); |
+ |
+ net::CertVerifyResult verify_result_valid; |
+ verify_result_valid.verified_cert = |
+ net::ImportCertFromFile(net::GetTestCertsDirectory(), "spdy_pooling.pem"); |
+ mock_cert_verifier()->AddResultForCertAndHost(cert.get(), "www.example.org", |
+ verify_result_valid, net::OK); |
+ |
+ // The user will visit https://example.org:port/ssl/blank.html. |
+ GURL::Replacements replacements; |
+ replacements.SetHostStr("example.org"); |
+ const GURL https_server_mismatched_url = |
+ https_server_example_domain.GetURL("/ssl/blank.html") |
+ .ReplaceComponents(replacements); |
+ |
+ // Should simply show an interstitial, because the suggested URL |
+ // (https://www.example.org) redirected to http://example.org. |
+ WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); |
+ ui_test_utils::NavigateToURL(browser(), https_server_mismatched_url); |
+ WaitForInterstitialAttach(contents); |
+ |
+ CheckSecurityState(contents, net::CERT_STATUS_COMMON_NAME_INVALID, |
+ security_state::DANGEROUS, |
+ AuthState::SHOWING_INTERSTITIAL); |
+} |
+ |
// Tests this scenario: |
// - |CommonNameMismatchHandler| does not give a callback as it's set into the |
// state |IGNORE_REQUESTS_FOR_TESTING|. So no suggested URL check result can |
@@ -3739,14 +3874,14 @@ IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
// - Stopping the page load shouldn't result in any interstitials. |
IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
InterstitialStopNavigationWhileLoading) { |
- net::EmbeddedTestServer https_server_example_domain_( |
+ net::EmbeddedTestServer https_server_example_domain( |
net::EmbeddedTestServer::TYPE_HTTPS); |
- https_server_example_domain_.ServeFilesFromSourceDirectory( |
+ https_server_example_domain.ServeFilesFromSourceDirectory( |
base::FilePath(kDocRoot)); |
- ASSERT_TRUE(https_server_example_domain_.Start()); |
+ ASSERT_TRUE(https_server_example_domain.Start()); |
scoped_refptr<net::X509Certificate> cert = |
- https_server_example_domain_.GetCertificate(); |
+ https_server_example_domain.GetCertificate(); |
net::CertVerifyResult verify_result; |
verify_result.verified_cert = |
@@ -3763,11 +3898,11 @@ IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
mock_cert_verifier()->AddResultForCertAndHost(cert.get(), "mail.example.com", |
verify_result_valid, net::OK); |
- GURL https_server_url = |
- https_server_example_domain_.GetURL("/ssl/google.html?a=b"); |
+ const GURL https_server_url = |
+ https_server_example_domain.GetURL("/ssl/google.html?a=b"); |
GURL::Replacements replacements; |
replacements.SetHostStr("www.mail.example.com"); |
- GURL https_server_mismatched_url = |
+ const GURL https_server_mismatched_url = |
https_server_url.ReplaceComponents(replacements); |
WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); |
@@ -3802,14 +3937,14 @@ IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
// result is the same. (i.e. page load stops, no interstitials shown) |
IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
InterstitialReloadNavigationWhileLoading) { |
- net::EmbeddedTestServer https_server_example_domain_( |
+ net::EmbeddedTestServer https_server_example_domain( |
net::EmbeddedTestServer::TYPE_HTTPS); |
- https_server_example_domain_.ServeFilesFromSourceDirectory( |
+ https_server_example_domain.ServeFilesFromSourceDirectory( |
base::FilePath(kDocRoot)); |
- ASSERT_TRUE(https_server_example_domain_.Start()); |
+ ASSERT_TRUE(https_server_example_domain.Start()); |
scoped_refptr<net::X509Certificate> cert = |
- https_server_example_domain_.GetCertificate(); |
+ https_server_example_domain.GetCertificate(); |
net::CertVerifyResult verify_result; |
verify_result.verified_cert = |
@@ -3826,11 +3961,11 @@ IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
mock_cert_verifier()->AddResultForCertAndHost(cert.get(), "mail.example.com", |
verify_result_valid, net::OK); |
- GURL https_server_url = |
- https_server_example_domain_.GetURL("/ssl/google.html?a=b"); |
+ const GURL https_server_url = |
+ https_server_example_domain.GetURL("/ssl/google.html?a=b"); |
GURL::Replacements replacements; |
replacements.SetHostStr("www.mail.example.com"); |
- GURL https_server_mismatched_url = |
+ const GURL https_server_mismatched_url = |
https_server_url.ReplaceComponents(replacements); |
WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); |
@@ -3863,14 +3998,14 @@ IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
// new page should load, and no interstitials should be shown. |
IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
InterstitialNavigateAwayWhileLoading) { |
- net::EmbeddedTestServer https_server_example_domain_( |
+ net::EmbeddedTestServer https_server_example_domain( |
net::EmbeddedTestServer::TYPE_HTTPS); |
- https_server_example_domain_.ServeFilesFromSourceDirectory( |
+ https_server_example_domain.ServeFilesFromSourceDirectory( |
base::FilePath(kDocRoot)); |
- ASSERT_TRUE(https_server_example_domain_.Start()); |
+ ASSERT_TRUE(https_server_example_domain.Start()); |
scoped_refptr<net::X509Certificate> cert = |
- https_server_example_domain_.GetCertificate(); |
+ https_server_example_domain.GetCertificate(); |
net::CertVerifyResult verify_result; |
verify_result.verified_cert = |
@@ -3887,11 +4022,11 @@ IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest, |
mock_cert_verifier()->AddResultForCertAndHost(cert.get(), "mail.example.com", |
verify_result_valid, net::OK); |
- GURL https_server_url = |
- https_server_example_domain_.GetURL("/ssl/google.html?a=b"); |
+ const GURL https_server_url = |
+ https_server_example_domain.GetURL("/ssl/google.html?a=b"); |
GURL::Replacements replacements; |
replacements.SetHostStr("www.mail.example.com"); |
- GURL https_server_mismatched_url = |
+ const GURL https_server_mismatched_url = |
https_server_url.ReplaceComponents(replacements); |
WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); |