Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <utility> | 5 #include <utility> |
| 6 | 6 |
| 7 #include "base/base_switches.h" | 7 #include "base/base_switches.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/location.h" | 12 #include "base/location.h" |
| 13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/metrics/field_trial.h" | 14 #include "base/metrics/field_trial.h" |
| 15 #include "base/single_thread_task_runner.h" | 15 #include "base/single_thread_task_runner.h" |
| 16 #include "base/strings/string_split.h" | 16 #include "base/strings/string_split.h" |
| 17 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
| 18 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
| 19 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
| 20 #include "base/test/histogram_tester.h" | 20 #include "base/test/histogram_tester.h" |
| 21 #include "base/test/scoped_feature_list.h" | |
| 21 #include "base/test/simple_test_clock.h" | 22 #include "base/test/simple_test_clock.h" |
| 22 #include "base/threading/thread_task_runner_handle.h" | 23 #include "base/threading/thread_task_runner_handle.h" |
| 23 #include "base/time/default_clock.h" | 24 #include "base/time/default_clock.h" |
| 24 #include "base/time/default_tick_clock.h" | 25 #include "base/time/default_tick_clock.h" |
| 25 #include "base/time/time.h" | 26 #include "base/time/time.h" |
| 26 #include "build/build_config.h" | 27 #include "build/build_config.h" |
| 27 #include "chrome/app/chrome_command_ids.h" | 28 #include "chrome/app/chrome_command_ids.h" |
| 28 #include "chrome/browser/browser_process.h" | 29 #include "chrome/browser/browser_process.h" |
| 29 #include "chrome/browser/chrome_notification_types.h" | 30 #include "chrome/browser/chrome_notification_types.h" |
| 30 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" | 31 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
| 31 #include "chrome/browser/interstitials/security_interstitial_page_test_utils.h" | 32 #include "chrome/browser/interstitials/security_interstitial_page_test_utils.h" |
| 32 #include "chrome/browser/profiles/profile.h" | 33 #include "chrome/browser/profiles/profile.h" |
| 33 #include "chrome/browser/ssl/bad_clock_blocking_page.h" | 34 #include "chrome/browser/ssl/bad_clock_blocking_page.h" |
| 34 #include "chrome/browser/ssl/cert_report_helper.h" | 35 #include "chrome/browser/ssl/cert_report_helper.h" |
| 35 #include "chrome/browser/ssl/cert_verifier_browser_test.h" | 36 #include "chrome/browser/ssl/cert_verifier_browser_test.h" |
| 36 #include "chrome/browser/ssl/certificate_reporting_test_utils.h" | 37 #include "chrome/browser/ssl/certificate_reporting_test_utils.h" |
| 37 #include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h" | 38 #include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h" |
| 38 #include "chrome/browser/ssl/common_name_mismatch_handler.h" | 39 #include "chrome/browser/ssl/common_name_mismatch_handler.h" |
| 39 #include "chrome/browser/ssl/security_state_tab_helper.h" | 40 #include "chrome/browser/ssl/security_state_tab_helper.h" |
| 40 #include "chrome/browser/ssl/ssl_blocking_page.h" | 41 #include "chrome/browser/ssl/ssl_blocking_page.h" |
| 42 #include "chrome/browser/ssl/ssl_error_assistant.pb.h" | |
| 41 #include "chrome/browser/ssl/ssl_error_handler.h" | 43 #include "chrome/browser/ssl/ssl_error_handler.h" |
| 42 #include "chrome/browser/ui/browser.h" | 44 #include "chrome/browser/ui/browser.h" |
| 43 #include "chrome/browser/ui/browser_commands.h" | 45 #include "chrome/browser/ui/browser_commands.h" |
| 44 #include "chrome/browser/ui/browser_finder.h" | 46 #include "chrome/browser/ui/browser_finder.h" |
| 45 #include "chrome/browser/ui/browser_navigator.h" | 47 #include "chrome/browser/ui/browser_navigator.h" |
| 46 #include "chrome/browser/ui/browser_navigator_params.h" | 48 #include "chrome/browser/ui/browser_navigator_params.h" |
| 47 #include "chrome/browser/ui/browser_tabstrip.h" | 49 #include "chrome/browser/ui/browser_tabstrip.h" |
| 48 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 50 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 49 #include "chrome/common/chrome_paths.h" | 51 #include "chrome/common/chrome_paths.h" |
| 50 #include "chrome/common/chrome_switches.h" | 52 #include "chrome/common/chrome_switches.h" |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 103 #include "net/url_request/url_request_filter.h" | 105 #include "net/url_request/url_request_filter.h" |
| 104 #include "net/url_request/url_request_job.h" | 106 #include "net/url_request/url_request_job.h" |
| 105 #include "net/url_request/url_request_test_util.h" | 107 #include "net/url_request/url_request_test_util.h" |
| 106 | 108 |
| 107 #if defined(USE_NSS_CERTS) | 109 #if defined(USE_NSS_CERTS) |
| 108 #include "chrome/browser/net/nss_context.h" | 110 #include "chrome/browser/net/nss_context.h" |
| 109 #include "net/base/crypto_module.h" | 111 #include "net/base/crypto_module.h" |
| 110 #include "net/cert/nss_cert_database.h" | 112 #include "net/cert/nss_cert_database.h" |
| 111 #endif // defined(USE_NSS_CERTS) | 113 #endif // defined(USE_NSS_CERTS) |
| 112 | 114 |
| 115 #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
| 116 #include "chrome/browser/ssl/captive_portal_blocking_page.h" | |
| 117 #endif | |
| 118 | |
| 113 using base::ASCIIToUTF16; | 119 using base::ASCIIToUTF16; |
| 114 using chrome_browser_interstitials::SecurityInterstitialIDNTest; | 120 using chrome_browser_interstitials::SecurityInterstitialIDNTest; |
| 115 using content::InterstitialPage; | 121 using content::InterstitialPage; |
| 116 using content::NavigationController; | 122 using content::NavigationController; |
| 117 using content::NavigationEntry; | 123 using content::NavigationEntry; |
| 118 using content::SSLStatus; | 124 using content::SSLStatus; |
| 119 using content::WebContents; | 125 using content::WebContents; |
| 120 using web_modal::WebContentsModalDialogManager; | 126 using web_modal::WebContentsModalDialogManager; |
| 121 | 127 |
| 122 const base::FilePath::CharType kDocRoot[] = | 128 const base::FilePath::CharType kDocRoot[] = |
| 123 FILE_PATH_LITERAL("chrome/test/data"); | 129 FILE_PATH_LITERAL("chrome/test/data"); |
| 124 | 130 |
| 125 namespace { | 131 namespace { |
| 126 | 132 |
| 133 #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
| 134 // Sha256 fingerprint of okay.pem's Subject Public Key Information. | |
|
Ryan Sleevi
2017/02/01 22:06:06
s/okay.pem/ok_cert.pem/
Hardcoding to ok_cert.pem
meacer
2017/02/02 01:56:05
estark mentioned this too. I'm now computing this
| |
| 135 // Compute the hash as follows: | |
| 136 // openssl x509 -noout -in net/data/ssl/certificates/ok_cert.pem -pubkey | \ | |
| 137 // openssl asn1parse -noout -inform pem -out public.key; \ | |
| 138 // openssl dgst -sha256 -binary public.key | openssl enc -base64 | |
| 139 const char kOkayPemSPKI[] = | |
| 140 "sha256/2zCMVDKgnKec0721Sp1zVh2yiHeW/LJK4STkNnEa1og="; | |
| 141 | |
| 142 // A hostname that will trigger a captive portal interstitial. The actual value | |
| 143 // isn't important. | |
| 144 const char kCaptivePortalHostname[] = "captive-portal.test"; | |
| 145 #endif | |
| 146 | |
| 127 enum ProceedDecision { | 147 enum ProceedDecision { |
| 128 SSL_INTERSTITIAL_PROCEED, | 148 SSL_INTERSTITIAL_PROCEED, |
| 129 SSL_INTERSTITIAL_DO_NOT_PROCEED | 149 SSL_INTERSTITIAL_DO_NOT_PROCEED |
| 130 }; | 150 }; |
| 131 | 151 |
| 132 namespace AuthState { | 152 namespace AuthState { |
| 133 | 153 |
| 134 enum AuthStateFlags { | 154 enum AuthStateFlags { |
| 135 NONE = 0, | 155 NONE = 0, |
| 136 DISPLAYED_INSECURE_CONTENT = 1 << 0, | 156 DISPLAYED_INSECURE_CONTENT = 1 << 0, |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 219 SSLErrorHandler::SetInterstitialTimerStartedCallbackForTesting(&callback_); | 239 SSLErrorHandler::SetInterstitialTimerStartedCallbackForTesting(&callback_); |
| 220 } | 240 } |
| 221 | 241 |
| 222 ~SSLInterstitialTimerObserver() { | 242 ~SSLInterstitialTimerObserver() { |
| 223 SSLErrorHandler::SetInterstitialTimerStartedCallbackForTesting(nullptr); | 243 SSLErrorHandler::SetInterstitialTimerStartedCallbackForTesting(nullptr); |
| 224 } | 244 } |
| 225 | 245 |
| 226 // Waits until the interstitial delay timer in SSLErrorHandler is started. | 246 // Waits until the interstitial delay timer in SSLErrorHandler is started. |
| 227 void WaitForTimerStarted() { message_loop_runner_->Run(); } | 247 void WaitForTimerStarted() { message_loop_runner_->Run(); } |
| 228 | 248 |
| 249 // Returns true if the interstitial delay timer has been started. | |
| 250 bool timer_started() const { return timer_started_; } | |
| 251 | |
| 229 private: | 252 private: |
| 230 void OnTimerStarted(content::WebContents* web_contents) { | 253 void OnTimerStarted(content::WebContents* web_contents) { |
| 254 timer_started_ = true; | |
| 231 if (web_contents_ == web_contents) | 255 if (web_contents_ == web_contents) |
| 232 message_loop_runner_->Quit(); | 256 message_loop_runner_->Quit(); |
| 233 } | 257 } |
| 234 | 258 |
| 259 bool timer_started_ = false; | |
| 235 const content::WebContents* web_contents_; | 260 const content::WebContents* web_contents_; |
| 236 SSLErrorHandler::TimerStartedCallback callback_; | 261 SSLErrorHandler::TimerStartedCallback callback_; |
| 237 | 262 |
| 238 std::unique_ptr<base::RunLoop> message_loop_runner_; | 263 std::unique_ptr<base::RunLoop> message_loop_runner_; |
| 239 | 264 |
| 240 DISALLOW_COPY_AND_ASSIGN(SSLInterstitialTimerObserver); | 265 DISALLOW_COPY_AND_ASSIGN(SSLInterstitialTimerObserver); |
| 241 }; | 266 }; |
| 242 | 267 |
| 243 class HungJob : public net::URLRequestJob { | 268 class HungJob : public net::URLRequestJob { |
| 244 public: | 269 public: |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 301 // authentication state. To avoid this non-determinism, add an | 326 // authentication state. To avoid this non-determinism, add an |
| 302 // interceptor to hang all favicon requests. | 327 // interceptor to hang all favicon requests. |
| 303 std::unique_ptr<net::URLRequestInterceptor> interceptor(new FaviconFilter); | 328 std::unique_ptr<net::URLRequestInterceptor> interceptor(new FaviconFilter); |
| 304 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( | 329 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( |
| 305 "https", "127.0.0.1", std::move(interceptor)); | 330 "https", "127.0.0.1", std::move(interceptor)); |
| 306 interceptor.reset(new FaviconFilter); | 331 interceptor.reset(new FaviconFilter); |
| 307 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( | 332 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( |
| 308 "https", "localhost", std::move(interceptor)); | 333 "https", "localhost", std::move(interceptor)); |
| 309 } | 334 } |
| 310 | 335 |
| 336 void SetUp() override { | |
| 337 InProcessBrowserTest::SetUp(); | |
| 338 SSLErrorHandler::ResetConfigForTesting(); | |
| 339 } | |
| 340 | |
| 311 void SetUpCommandLine(base::CommandLine* command_line) override { | 341 void SetUpCommandLine(base::CommandLine* command_line) override { |
| 312 // Browser will both run and display insecure content. | 342 // Browser will both run and display insecure content. |
| 313 command_line->AppendSwitch(switches::kAllowRunningInsecureContent); | 343 command_line->AppendSwitch(switches::kAllowRunningInsecureContent); |
| 314 // Use process-per-site so that navigating to a same-site page in a | 344 // Use process-per-site so that navigating to a same-site page in a |
| 315 // new tab will use the same process. | 345 // new tab will use the same process. |
| 316 command_line->AppendSwitch(switches::kProcessPerSite); | 346 command_line->AppendSwitch(switches::kProcessPerSite); |
| 317 } | 347 } |
| 318 | 348 |
| 319 void CheckAuthenticatedState(WebContents* tab, | 349 void CheckAuthenticatedState(WebContents* tab, |
| 320 int expected_authentication_state) { | 350 int expected_authentication_state) { |
| (...skipping 3557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3878 IN_PROC_BROWSER_TEST_F(SSLUITestIgnoreLocalhostCertErrors, | 3908 IN_PROC_BROWSER_TEST_F(SSLUITestIgnoreLocalhostCertErrors, |
| 3879 NoCrashOnLoadWithNoNavigationEntry) { | 3909 NoCrashOnLoadWithNoNavigationEntry) { |
| 3880 ASSERT_TRUE(embedded_test_server()->Start()); | 3910 ASSERT_TRUE(embedded_test_server()->Start()); |
| 3881 | 3911 |
| 3882 ui_test_utils::NavigateToURL( | 3912 ui_test_utils::NavigateToURL( |
| 3883 browser(), embedded_test_server()->GetURL("/ssl/google.html")); | 3913 browser(), embedded_test_server()->GetURL("/ssl/google.html")); |
| 3884 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); | 3914 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); |
| 3885 ASSERT_TRUE(content::ExecuteScript(tab, "window.open()")); | 3915 ASSERT_TRUE(content::ExecuteScript(tab, "window.open()")); |
| 3886 } | 3916 } |
| 3887 | 3917 |
| 3918 #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
| 3919 | |
| 3920 IN_PROC_BROWSER_TEST_F(SSLUITest, CaptivePortalCertificateList_Disabled) { | |
| 3921 base::test::ScopedFeatureList scoped_feature_list; | |
| 3922 scoped_feature_list.InitFromCommandLine( | |
| 3923 "" /* enabled */, "CaptivePortalCertificateList" /* disabled */); | |
| 3924 | |
| 3925 ASSERT_TRUE(https_server_mismatched_.Start()); | |
| 3926 base::HistogramTester histograms; | |
| 3927 | |
| 3928 // Mark the server's cert as a captive portal cert. | |
| 3929 chrome_browser_ssl::SSLErrorAssistantConfig config_proto; | |
| 3930 config_proto.add_captive_portal_cert()->set_sha256_hash(kOkayPemSPKI); | |
| 3931 SSLErrorHandler::SetErrorAssistantProtoForTesting(config_proto); | |
| 3932 | |
| 3933 // Navigate to an unsafe page on the server. A normal SSL interstitial should | |
| 3934 // be displayed since CaptivePortalCertificateList feature is disabled. | |
| 3935 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); | |
| 3936 SSLInterstitialTimerObserver interstitial_timer_observer(tab); | |
| 3937 ui_test_utils::NavigateToURL( | |
| 3938 browser(), https_server_mismatched_.GetURL("/ssl/blank_page.html")); | |
| 3939 content::WaitForInterstitialAttach(tab); | |
| 3940 | |
| 3941 InterstitialPage* interstitial_page = tab->GetInterstitialPage(); | |
| 3942 ASSERT_EQ(SSLBlockingPage::kTypeForTesting, | |
| 3943 interstitial_page->GetDelegateForTesting()->GetTypeForTesting()); | |
| 3944 EXPECT_TRUE(interstitial_timer_observer.timer_started()); | |
| 3945 | |
| 3946 // Check that the histogram for the SSL interstitial was recorded. | |
| 3947 histograms.ExpectTotalCount(SSLErrorHandler::GetHistogramNameForTesting(), 2); | |
| 3948 histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), | |
| 3949 SSLErrorHandler::HANDLE_ALL, 1); | |
| 3950 histograms.ExpectBucketCount( | |
| 3951 SSLErrorHandler::GetHistogramNameForTesting(), | |
| 3952 SSLErrorHandler::SHOW_SSL_INTERSTITIAL_OVERRIDABLE, 1); | |
| 3953 histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), | |
| 3954 SSLErrorHandler::CAPTIVE_PORTAL_CERT_FOUND, 0); | |
| 3955 } | |
| 3956 | |
| 3957 IN_PROC_BROWSER_TEST_F(SSLUITest, | |
| 3958 CaptivePortalCertificateList_Enabled_FromProto) { | |
| 3959 base::test::ScopedFeatureList scoped_feature_list; | |
| 3960 scoped_feature_list.InitFromCommandLine( | |
| 3961 "CaptivePortalCertificateList" /* enabled */, "" /* disabled */); | |
| 3962 | |
| 3963 ASSERT_TRUE(https_server_mismatched_.Start()); | |
| 3964 base::HistogramTester histograms; | |
| 3965 | |
| 3966 // Mark the server's cert as a captive portal cert. | |
| 3967 chrome_browser_ssl::SSLErrorAssistantConfig config_proto; | |
| 3968 config_proto.add_captive_portal_cert()->set_sha256_hash(kOkayPemSPKI); | |
| 3969 SSLErrorHandler::SetErrorAssistantProtoForTesting(config_proto); | |
| 3970 | |
| 3971 // Navigate to an unsafe page on the server. The captive portal interstitial | |
| 3972 // should be displayed since CaptivePortalCertificateList feature is enabled. | |
| 3973 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); | |
| 3974 SSLInterstitialTimerObserver interstitial_timer_observer(tab); | |
| 3975 ui_test_utils::NavigateToURL( | |
| 3976 browser(), https_server_mismatched_.GetURL("/ssl/blank_page.html")); | |
| 3977 content::WaitForInterstitialAttach(tab); | |
| 3978 | |
| 3979 InterstitialPage* interstitial_page = tab->GetInterstitialPage(); | |
| 3980 ASSERT_EQ(CaptivePortalBlockingPage::kTypeForTesting, | |
| 3981 interstitial_page->GetDelegateForTesting()->GetTypeForTesting()); | |
| 3982 EXPECT_FALSE(interstitial_timer_observer.timer_started()); | |
| 3983 | |
| 3984 // Check that the histogram for the captive portal cert was recorded. | |
| 3985 histograms.ExpectTotalCount(SSLErrorHandler::GetHistogramNameForTesting(), 3); | |
| 3986 histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), | |
| 3987 SSLErrorHandler::HANDLE_ALL, 1); | |
| 3988 histograms.ExpectBucketCount( | |
| 3989 SSLErrorHandler::GetHistogramNameForTesting(), | |
| 3990 SSLErrorHandler::SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE, 1); | |
| 3991 histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), | |
| 3992 SSLErrorHandler::CAPTIVE_PORTAL_CERT_FOUND, 1); | |
| 3993 } | |
| 3994 | |
| 3995 namespace { | |
| 3996 | |
| 3997 // Test class that mimics a URL request with a certificate whose SPKI hash is in | |
| 3998 // ssl_error_assistant.asciipb resource. A better way of testing the SPKI hashes | |
| 3999 // inside the resource bundle would be to serve the actual certificate from the | |
| 4000 // embeded test server, but the test server can only serve a limited number of | |
| 4001 // predefined certificates. | |
| 4002 template <int kNetError> | |
| 4003 class SSLUICaptivePortalTest : public InProcessBrowserTest { | |
| 4004 public: | |
| 4005 SSLUICaptivePortalTest() : InProcessBrowserTest(), cert_(nullptr) {} | |
| 4006 | |
| 4007 void SetUpOnMainThread() override { | |
| 4008 cert_ = | |
| 4009 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem"); | |
| 4010 ASSERT_TRUE(cert_); | |
| 4011 content::BrowserThread::PostTask( | |
| 4012 content::BrowserThread::IO, FROM_HERE, | |
| 4013 base::Bind(&SSLUICaptivePortalTest::AddUrlHandler, cert_)); | |
| 4014 } | |
| 4015 | |
| 4016 static void AddUrlHandler(scoped_refptr<net::X509Certificate> cert) { | |
| 4017 net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); | |
| 4018 filter->AddHostnameInterceptor("https", kCaptivePortalHostname, | |
| 4019 std::unique_ptr<net::URLRequestInterceptor>( | |
| 4020 new CaptivePortalInterceptor(cert))); | |
| 4021 } | |
| 4022 | |
| 4023 private: | |
| 4024 // A URLRequestJob that mocks a TLS connection with a certificate whose SPKI | |
| 4025 // hash is marked as a known captive portal certificate SPKI. | |
| 4026 class CaptivePortalURLRequestJob : public net::URLRequestJob { | |
| 4027 public: | |
| 4028 CaptivePortalURLRequestJob(net::URLRequest* request, | |
| 4029 net::NetworkDelegate* network_delegate, | |
| 4030 scoped_refptr<net::X509Certificate> cert) | |
| 4031 : net::URLRequestJob(request, network_delegate), | |
| 4032 cert_(std::move(cert)), | |
| 4033 weak_factory_(this) {} | |
| 4034 | |
| 4035 // net::URLRequestJob method: | |
| 4036 void Start() override { | |
| 4037 net::SSLInfo ssl_info; | |
| 4038 ssl_info.SetCertError(kNetError); | |
| 4039 ssl_info.cert = cert_; | |
| 4040 | |
| 4041 // Set the SPKI hash to captive-portal.badssl.com leaf certificate. This | |
| 4042 // doesn't match the actual cert (ok_cert.pem) but is good enough for | |
| 4043 // testing. | |
| 4044 net::HashValue hash; | |
| 4045 ASSERT_TRUE(hash.FromString( | |
| 4046 "sha256/fjZPHewEHTrMDX3I1ecEIeoy3WFxHyGplOLv28kIbtI=")); | |
| 4047 ssl_info.public_key_hashes.push_back(hash); | |
| 4048 | |
| 4049 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 4050 FROM_HERE, | |
| 4051 base::Bind(&CaptivePortalURLRequestJob::NotifySSLCertificateError, | |
| 4052 weak_factory_.GetWeakPtr(), ssl_info, false)); | |
| 4053 } | |
| 4054 | |
| 4055 protected: | |
| 4056 ~CaptivePortalURLRequestJob() override {} | |
| 4057 | |
| 4058 private: | |
| 4059 const scoped_refptr<net::X509Certificate> cert_; | |
| 4060 base::WeakPtrFactory<CaptivePortalURLRequestJob> weak_factory_; | |
| 4061 | |
| 4062 DISALLOW_COPY_AND_ASSIGN(CaptivePortalURLRequestJob); | |
| 4063 }; | |
| 4064 | |
| 4065 // A URLRequestInterceptor that handles requests with | |
| 4066 // CaptivePortalURLRequestJob jobs. | |
| 4067 class CaptivePortalInterceptor : public net::URLRequestInterceptor { | |
| 4068 public: | |
| 4069 CaptivePortalInterceptor(scoped_refptr<net::X509Certificate> cert) | |
| 4070 : cert_(std::move(cert)) {} | |
| 4071 | |
| 4072 ~CaptivePortalInterceptor() override {} | |
| 4073 | |
| 4074 // net::URLRequestInterceptor method: | |
| 4075 net::URLRequestJob* MaybeInterceptRequest( | |
| 4076 net::URLRequest* request, | |
| 4077 net::NetworkDelegate* network_delegate) const override { | |
| 4078 return new CaptivePortalURLRequestJob(request, network_delegate, cert_); | |
| 4079 } | |
| 4080 | |
| 4081 private: | |
| 4082 const scoped_refptr<net::X509Certificate> cert_; | |
| 4083 | |
| 4084 DISALLOW_COPY_AND_ASSIGN(CaptivePortalInterceptor); | |
| 4085 }; | |
| 4086 | |
| 4087 scoped_refptr<net::X509Certificate> cert_; | |
| 4088 }; | |
| 4089 | |
| 4090 using SSLUICaptivePortalNameMismatchTest = | |
| 4091 SSLUICaptivePortalTest<net::ERR_CERT_COMMON_NAME_INVALID>; | |
| 4092 using SSLUICaptivePortalAuthorityInvalidTest = | |
| 4093 SSLUICaptivePortalTest<net::ERR_CERT_AUTHORITY_INVALID>; | |
| 4094 | |
| 4095 } // namespace | |
| 4096 | |
| 4097 // Same as CaptivePortalCertificateList_Enabled_FromProto, but this time the | |
| 4098 // cert's SPKI hash is listed in ssl_error_assistant.asciipb. | |
| 4099 IN_PROC_BROWSER_TEST_F(SSLUICaptivePortalNameMismatchTest, | |
| 4100 CaptivePortalCertificateList_Enabled_FromResource) { | |
| 4101 base::test::ScopedFeatureList scoped_feature_list; | |
| 4102 scoped_feature_list.InitFromCommandLine( | |
| 4103 "CaptivePortalCertificateList" /* enabled */, "" /* disabled */); | |
| 4104 | |
| 4105 base::HistogramTester histograms; | |
| 4106 | |
| 4107 // Navigate to an unsafe page on the server. The captive portal interstitial | |
| 4108 // should be displayed since CaptivePortalCertificateList feature is enabled. | |
| 4109 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); | |
| 4110 SSLInterstitialTimerObserver interstitial_timer_observer(tab); | |
| 4111 ui_test_utils::NavigateToURL( | |
| 4112 browser(), GURL(std::string("https://") + kCaptivePortalHostname)); | |
| 4113 content::WaitForInterstitialAttach(tab); | |
| 4114 | |
| 4115 InterstitialPage* interstitial_page = tab->GetInterstitialPage(); | |
| 4116 ASSERT_EQ(CaptivePortalBlockingPage::kTypeForTesting, | |
| 4117 interstitial_page->GetDelegateForTesting()->GetTypeForTesting()); | |
| 4118 EXPECT_FALSE(interstitial_timer_observer.timer_started()); | |
| 4119 | |
| 4120 // Check that the histogram for the captive portal cert was recorded. | |
| 4121 histograms.ExpectTotalCount(SSLErrorHandler::GetHistogramNameForTesting(), 3); | |
| 4122 histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), | |
| 4123 SSLErrorHandler::HANDLE_ALL, 1); | |
| 4124 histograms.ExpectBucketCount( | |
| 4125 SSLErrorHandler::GetHistogramNameForTesting(), | |
| 4126 SSLErrorHandler::SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE, 1); | |
| 4127 histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), | |
| 4128 SSLErrorHandler::CAPTIVE_PORTAL_CERT_FOUND, 1); | |
| 4129 } | |
| 4130 | |
| 4131 // Same as SSLUICaptivePortalNameMismatchTest, but this time the error is | |
| 4132 // authority-invalid. Captive portal interstitial should not be shown. | |
| 4133 IN_PROC_BROWSER_TEST_F(SSLUICaptivePortalAuthorityInvalidTest, | |
| 4134 CaptivePortalCertificateList_Enabled_FromResource) { | |
| 4135 base::test::ScopedFeatureList scoped_feature_list; | |
| 4136 scoped_feature_list.InitFromCommandLine( | |
| 4137 "CaptivePortalCertificateList" /* enabled */, "" /* disabled */); | |
| 4138 | |
| 4139 // Set interstitial delay to zero. | |
| 4140 SSLErrorHandler::SetInterstitialDelayForTesting(base::TimeDelta()); | |
| 4141 | |
| 4142 base::HistogramTester histograms; | |
| 4143 // Navigate to an unsafe page on the server. CaptivePortalCertificateList | |
| 4144 // feature is enabled but the error is not a name mismatch, so a generic SSL | |
| 4145 // interstitial should be displayed. | |
| 4146 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); | |
| 4147 SSLInterstitialTimerObserver interstitial_timer_observer(tab); | |
| 4148 ui_test_utils::NavigateToURL( | |
| 4149 browser(), GURL(std::string("https://") + kCaptivePortalHostname)); | |
| 4150 content::WaitForInterstitialAttach(tab); | |
| 4151 | |
| 4152 InterstitialPage* interstitial_page = tab->GetInterstitialPage(); | |
| 4153 ASSERT_EQ(SSLBlockingPage::kTypeForTesting, | |
| 4154 interstitial_page->GetDelegateForTesting()->GetTypeForTesting()); | |
| 4155 EXPECT_TRUE(interstitial_timer_observer.timer_started()); | |
| 4156 | |
| 4157 // Check that the histogram for the captive portal cert was recorded. | |
| 4158 histograms.ExpectTotalCount(SSLErrorHandler::GetHistogramNameForTesting(), 2); | |
| 4159 histograms.ExpectBucketCount(SSLErrorHandler::GetHistogramNameForTesting(), | |
| 4160 SSLErrorHandler::HANDLE_ALL, 1); | |
| 4161 histograms.ExpectBucketCount( | |
| 4162 SSLErrorHandler::GetHistogramNameForTesting(), | |
| 4163 SSLErrorHandler::SHOW_SSL_INTERSTITIAL_OVERRIDABLE, 1); | |
| 4164 } | |
| 4165 | |
| 4166 #endif // BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
| 4167 | |
| 3888 // TODO(jcampan): more tests to do below. | 4168 // TODO(jcampan): more tests to do below. |
| 3889 | 4169 |
| 3890 // Visit a page over https that contains a frame with a redirect. | 4170 // Visit a page over https that contains a frame with a redirect. |
| 3891 | 4171 |
| 3892 // XMLHttpRequest insecure content in synchronous mode. | 4172 // XMLHttpRequest insecure content in synchronous mode. |
| 3893 | 4173 |
| 3894 // XMLHttpRequest insecure content in asynchronous mode. | 4174 // XMLHttpRequest insecure content in asynchronous mode. |
| 3895 | 4175 |
| 3896 // XMLHttpRequest over bad ssl in synchronous mode. | 4176 // XMLHttpRequest over bad ssl in synchronous mode. |
| 3897 | 4177 |
| 3898 // XMLHttpRequest over OK ssl in synchronous mode. | 4178 // XMLHttpRequest over OK ssl in synchronous mode. |
| OLD | NEW |