| 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 66f94a795b293bee9c3daa7e7c78cb02a96ca9ac..1320c49be7729ab0f033304a111cbf3b96f06953 100644
|
| --- a/chrome/browser/ssl/ssl_browser_tests.cc
|
| +++ b/chrome/browser/ssl/ssl_browser_tests.cc
|
| @@ -28,7 +28,9 @@
|
| #include "chrome/browser/ssl/certificate_error_report.h"
|
| #include "chrome/browser/ssl/certificate_reporting_test_utils.h"
|
| #include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h"
|
| +#include "chrome/browser/ssl/common_name_mismatch_handler.h"
|
| #include "chrome/browser/ssl/ssl_blocking_page.h"
|
| +#include "chrome/browser/ssl/ssl_error_handler.h"
|
| #include "chrome/browser/ui/browser.h"
|
| #include "chrome/browser/ui/browser_commands.h"
|
| #include "chrome/browser/ui/browser_navigator.h"
|
| @@ -57,6 +59,7 @@
|
| #include "content/public/common/ssl_status.h"
|
| #include "content/public/test/browser_test_utils.h"
|
| #include "content/public/test/download_test_observer.h"
|
| +#include "content/public/test/test_navigation_observer.h"
|
| #include "content/public/test/test_renderer_host.h"
|
| #include "net/base/host_port_pair.h"
|
| #include "net/base/net_errors.h"
|
| @@ -64,8 +67,11 @@
|
| #include "net/cert/cert_status_flags.h"
|
| #include "net/cert/mock_cert_verifier.h"
|
| #include "net/cert/x509_certificate.h"
|
| +#include "net/dns/mock_host_resolver.h"
|
| #include "net/ssl/ssl_info.h"
|
| +#include "net/test/cert_test_util.h"
|
| #include "net/test/spawned_test_server/spawned_test_server.h"
|
| +#include "net/test/test_certificate_data.h"
|
| #include "net/url_request/url_request_context.h"
|
|
|
| #if defined(USE_NSS_CERTS)
|
| @@ -199,6 +205,38 @@ void CheckSecurityState(WebContents* tab,
|
| AuthState::Check(*entry, expected_authentication_state);
|
| }
|
|
|
| +// This observer waits for the SSLErrorHandler to start an interstitial timer
|
| +// for the given web contents.
|
| +class SSLInterstitialTimerObserver {
|
| + public:
|
| + explicit SSLInterstitialTimerObserver(content::WebContents* web_contents)
|
| + : web_contents_(web_contents), message_loop_runner_(new base::RunLoop) {
|
| + callback_ = base::Bind(&SSLInterstitialTimerObserver::OnTimerStarted,
|
| + base::Unretained(this));
|
| + SSLErrorHandler::SetInterstitialTimerStartedCallbackForTest(&callback_);
|
| + }
|
| +
|
| + ~SSLInterstitialTimerObserver() {
|
| + SSLErrorHandler::SetInterstitialTimerStartedCallbackForTest(nullptr);
|
| + }
|
| +
|
| + // Waits until the interstitial delay timer in SSLErrorHandler is started.
|
| + void WaitForTimerStarted() { message_loop_runner_->Run(); }
|
| +
|
| + private:
|
| + void OnTimerStarted(content::WebContents* web_contents) {
|
| + if (web_contents_ == web_contents)
|
| + message_loop_runner_->Quit();
|
| + }
|
| +
|
| + const content::WebContents* web_contents_;
|
| + SSLErrorHandler::TimerStartedCallback callback_;
|
| +
|
| + scoped_ptr<base::RunLoop> message_loop_runner_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(SSLInterstitialTimerObserver);
|
| +};
|
| +
|
| } // namespace
|
|
|
| class SSLUITest
|
| @@ -2267,6 +2305,330 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, BadCertFollowedByGoodCert) {
|
| EXPECT_FALSE(state->HasAllowException(https_server_host));
|
| }
|
|
|
| +using CommonNameMismatchBrowserTest = CertVerifierBrowserTest;
|
| +
|
| +// Visit the URL www.mail.example.com on a server that presents a valid
|
| +// certificate for mail.example.com. Verify that the page navigates to
|
| +// mail.example.com.
|
| +IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest,
|
| + ShouldShowWWWSubdomainMismatchInterstitial) {
|
| + net::SpawnedTestServer https_server_example_domain_(
|
| + net::SpawnedTestServer::TYPE_HTTPS,
|
| + net::SpawnedTestServer::SSLOptions(
|
| + net::SpawnedTestServer::SSLOptions::CERT_OK),
|
| + base::FilePath(kDocRoot));
|
| + ASSERT_TRUE(https_server_example_domain_.Start());
|
| +
|
| + host_resolver()->AddRule(
|
| + "mail.example.com", https_server_example_domain_.host_port_pair().host());
|
| + host_resolver()->AddRule(
|
| + "www.mail.example.com",
|
| + https_server_example_domain_.host_port_pair().host());
|
| +
|
| + scoped_refptr<net::X509Certificate> cert =
|
| + https_server_example_domain_.GetCertificate();
|
| +
|
| + // Use the "spdy_pooling.pem" cert which has "mail.example.com"
|
| + // as one of its SANs.
|
| + 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;
|
| +
|
| + // Request to "www.mail.example.com" should result in
|
| + // |net::ERR_CERT_COMMON_NAME_INVALID| error.
|
| + mock_cert_verifier()->AddResultForCertAndHost(
|
| + cert.get(), "www.mail.example.com", 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");
|
| + // Request to "www.mail.example.com" should not result in any error.
|
| + mock_cert_verifier()->AddResultForCertAndHost(cert.get(), "mail.example.com",
|
| + verify_result_valid, net::OK);
|
| +
|
| + // 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("files/ssl/google.html?a=b#anchor");
|
| + GURL::Replacements replacements;
|
| + replacements.SetHostStr("www.mail.example.com");
|
| + GURL https_server_mismatched_url =
|
| + https_server_url.ReplaceComponents(replacements);
|
| +
|
| + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
|
| + content::TestNavigationObserver observer(contents, 2);
|
| + ui_test_utils::NavigateToURL(browser(), https_server_mismatched_url);
|
| + observer.Wait();
|
| +
|
| + CheckSecurityState(contents, CertError::NONE,
|
| + content::SECURITY_STYLE_AUTHENTICATED, AuthState::NONE);
|
| + replacements.SetHostStr("mail.example.com");
|
| + GURL https_server_new_url = https_server_url.ReplaceComponents(replacements);
|
| + // Verify that the current URL is the suggested URL.
|
| + EXPECT_EQ(https_server_new_url.spec(),
|
| + contents->GetLastCommittedURL().spec());
|
| +}
|
| +
|
| +// Visit the URL example.org on a server that presents a valid certificate
|
| +// for www.example.org. Verify that the page redirects to www.example.org.
|
| +IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest,
|
| + CheckWWWSubdomainMismatchInverse) {
|
| + net::SpawnedTestServer https_server_example_domain_(
|
| + net::SpawnedTestServer::TYPE_HTTPS,
|
| + net::SpawnedTestServer::SSLOptions(
|
| + net::SpawnedTestServer::SSLOptions::CERT_OK),
|
| + base::FilePath(kDocRoot));
|
| + ASSERT_TRUE(https_server_example_domain_.Start());
|
| +
|
| + host_resolver()->AddRule(
|
| + "www.example.org", https_server_example_domain_.host_port_pair().host());
|
| + host_resolver()->AddRule(
|
| + "example.org", https_server_example_domain_.host_port_pair().host());
|
| +
|
| + 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);
|
| +
|
| + GURL https_server_url =
|
| + https_server_example_domain_.GetURL("files/ssl/google.html?a=b");
|
| + GURL::Replacements replacements;
|
| + replacements.SetHostStr("example.org");
|
| + GURL https_server_mismatched_url =
|
| + https_server_url.ReplaceComponents(replacements);
|
| +
|
| + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
|
| + content::TestNavigationObserver observer(contents, 2);
|
| + ui_test_utils::NavigateToURL(browser(), https_server_mismatched_url);
|
| + observer.Wait();
|
| +
|
| + CheckSecurityState(contents, CertError::NONE,
|
| + content::SECURITY_STYLE_AUTHENTICATED, AuthState::NONE);
|
| +}
|
| +
|
| +// 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
|
| +// arrive.
|
| +// - A cert error triggers an interstitial timer with a very long timeout.
|
| +// - No suggested URL check results arrive, causing the tab to appear as loading
|
| +// indefinitely (also because the timer has a long timeout).
|
| +// - Stopping the page load shouldn't result in any interstitials.
|
| +IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest,
|
| + InterstitialStopNavigationWhileLoading) {
|
| + net::SpawnedTestServer https_server_example_domain_(
|
| + net::SpawnedTestServer::TYPE_HTTPS,
|
| + net::SpawnedTestServer::SSLOptions(
|
| + net::SpawnedTestServer::SSLOptions::CERT_OK),
|
| + base::FilePath(kDocRoot));
|
| + ASSERT_TRUE(https_server_example_domain_.Start());
|
| +
|
| + host_resolver()->AddRule(
|
| + "mail.example.com", https_server_example_domain_.host_port_pair().host());
|
| + host_resolver()->AddRule(
|
| + "www.mail.example.com",
|
| + https_server_example_domain_.host_port_pair().host());
|
| +
|
| + 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(), "www.mail.example.com", 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(), "mail.example.com",
|
| + verify_result_valid, net::OK);
|
| +
|
| + GURL https_server_url =
|
| + https_server_example_domain_.GetURL("files/ssl/google.html?a=b");
|
| + GURL::Replacements replacements;
|
| + replacements.SetHostStr("www.mail.example.com");
|
| + GURL https_server_mismatched_url =
|
| + https_server_url.ReplaceComponents(replacements);
|
| +
|
| + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
|
| + CommonNameMismatchHandler::set_state_for_testing(
|
| + CommonNameMismatchHandler::IGNORE_REQUESTS_FOR_TESTING);
|
| + SSLErrorHandler::SetInterstitialDelayTypeForTest(SSLErrorHandler::LONG);
|
| + SSLInterstitialTimerObserver interstitial_timer_observer(contents);
|
| +
|
| + ui_test_utils::NavigateToURLWithDisposition(
|
| + browser(), https_server_mismatched_url, CURRENT_TAB,
|
| + ui_test_utils::BROWSER_TEST_NONE);
|
| + interstitial_timer_observer.WaitForTimerStarted();
|
| +
|
| + EXPECT_TRUE(contents->IsLoading());
|
| + content::WindowedNotificationObserver observer(
|
| + content::NOTIFICATION_LOAD_STOP,
|
| + content::NotificationService::AllSources());
|
| + contents->Stop();
|
| + observer.Wait();
|
| +
|
| + SSLErrorHandler* ssl_error_handler =
|
| + SSLErrorHandler::FromWebContents(contents);
|
| + // Make sure that the |SSLErrorHandler| is deleted.
|
| + EXPECT_FALSE(ssl_error_handler);
|
| + EXPECT_FALSE(contents->ShowingInterstitialPage());
|
| + EXPECT_FALSE(contents->IsLoading());
|
| +}
|
| +
|
| +// Same as above, but instead of stopping, the loading page is reloaded. The end
|
| +// result is the same. (i.e. page load stops, no interstitials shown)
|
| +IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest,
|
| + InterstitialReloadNavigationWhileLoading) {
|
| + net::SpawnedTestServer https_server_example_domain_(
|
| + net::SpawnedTestServer::TYPE_HTTPS,
|
| + net::SpawnedTestServer::SSLOptions(
|
| + net::SpawnedTestServer::SSLOptions::CERT_OK),
|
| + base::FilePath(kDocRoot));
|
| + ASSERT_TRUE(https_server_example_domain_.Start());
|
| +
|
| + host_resolver()->AddRule(
|
| + "mail.example.com", https_server_example_domain_.host_port_pair().host());
|
| + host_resolver()->AddRule(
|
| + "www.mail.example.com",
|
| + https_server_example_domain_.host_port_pair().host());
|
| +
|
| + 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(), "www.mail.example.com", 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(), "mail.example.com",
|
| + verify_result_valid, net::OK);
|
| +
|
| + GURL https_server_url =
|
| + https_server_example_domain_.GetURL("files/ssl/google.html?a=b");
|
| + GURL::Replacements replacements;
|
| + replacements.SetHostStr("www.mail.example.com");
|
| + GURL https_server_mismatched_url =
|
| + https_server_url.ReplaceComponents(replacements);
|
| +
|
| + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
|
| + CommonNameMismatchHandler::set_state_for_testing(
|
| + CommonNameMismatchHandler::IGNORE_REQUESTS_FOR_TESTING);
|
| + SSLErrorHandler::SetInterstitialDelayTypeForTest(SSLErrorHandler::LONG);
|
| + SSLInterstitialTimerObserver interstitial_timer_observer(contents);
|
| +
|
| + ui_test_utils::NavigateToURLWithDisposition(
|
| + browser(), https_server_mismatched_url, CURRENT_TAB,
|
| + ui_test_utils::BROWSER_TEST_NONE);
|
| + interstitial_timer_observer.WaitForTimerStarted();
|
| +
|
| + EXPECT_TRUE(contents->IsLoading());
|
| + content::TestNavigationObserver observer(contents, 1);
|
| + chrome::Reload(browser(), CURRENT_TAB);
|
| + observer.Wait();
|
| +
|
| + SSLErrorHandler* ssl_error_handler =
|
| + SSLErrorHandler::FromWebContents(contents);
|
| + // Make sure that the |SSLErrorHandler| is deleted.
|
| + EXPECT_FALSE(ssl_error_handler);
|
| + EXPECT_FALSE(contents->ShowingInterstitialPage());
|
| + EXPECT_FALSE(contents->IsLoading());
|
| +}
|
| +
|
| +// Same as above, but instead of reloading, the page is navigated away. The
|
| +// new page should load, and no interstitials should be shown.
|
| +IN_PROC_BROWSER_TEST_F(CommonNameMismatchBrowserTest,
|
| + InterstitialNavigateAwayWhileLoading) {
|
| + net::SpawnedTestServer https_server_example_domain_(
|
| + net::SpawnedTestServer::TYPE_HTTPS,
|
| + net::SpawnedTestServer::SSLOptions(
|
| + net::SpawnedTestServer::SSLOptions::CERT_OK),
|
| + base::FilePath(kDocRoot));
|
| + ASSERT_TRUE(https_server_example_domain_.Start());
|
| +
|
| + host_resolver()->AddRule(
|
| + "mail.example.com", https_server_example_domain_.host_port_pair().host());
|
| + host_resolver()->AddRule(
|
| + "www.mail.example.com",
|
| + https_server_example_domain_.host_port_pair().host());
|
| +
|
| + 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(), "www.mail.example.com", 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(), "mail.example.com",
|
| + verify_result_valid, net::OK);
|
| +
|
| + GURL https_server_url =
|
| + https_server_example_domain_.GetURL("files/ssl/google.html?a=b");
|
| + GURL::Replacements replacements;
|
| + replacements.SetHostStr("www.mail.example.com");
|
| + GURL https_server_mismatched_url =
|
| + https_server_url.ReplaceComponents(replacements);
|
| +
|
| + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
|
| + CommonNameMismatchHandler::set_state_for_testing(
|
| + CommonNameMismatchHandler::IGNORE_REQUESTS_FOR_TESTING);
|
| + SSLErrorHandler::SetInterstitialDelayTypeForTest(SSLErrorHandler::LONG);
|
| + SSLInterstitialTimerObserver interstitial_timer_observer(contents);
|
| +
|
| + ui_test_utils::NavigateToURLWithDisposition(
|
| + browser(), https_server_mismatched_url, CURRENT_TAB,
|
| + ui_test_utils::BROWSER_TEST_NONE);
|
| + interstitial_timer_observer.WaitForTimerStarted();
|
| +
|
| + EXPECT_TRUE(contents->IsLoading());
|
| + content::TestNavigationObserver observer(contents, 1);
|
| + browser()->OpenURL(content::OpenURLParams(GURL("https://google.com"),
|
| + content::Referrer(), CURRENT_TAB,
|
| + ui::PAGE_TRANSITION_TYPED, false));
|
| + observer.Wait();
|
| +
|
| + SSLErrorHandler* ssl_error_handler =
|
| + SSLErrorHandler::FromWebContents(contents);
|
| + // Make sure that the |SSLErrorHandler| is deleted.
|
| + EXPECT_FALSE(ssl_error_handler);
|
| + EXPECT_FALSE(contents->ShowingInterstitialPage());
|
| + EXPECT_FALSE(contents->IsLoading());
|
| +}
|
| +
|
| class SSLBlockingPageIDNTest : public SecurityInterstitialIDNTest {
|
| protected:
|
| // SecurityInterstitialIDNTest implementation
|
|
|