Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "chrome/browser/ssl/ssl_error_handler.h" | 5 #include "chrome/browser/ssl/ssl_error_handler.h" |
| 6 | 6 |
| 7 #include "base/callback_helpers.h" | 7 #include "base/callback_helpers.h" |
| 8 #include "base/metrics/field_trial.h" | 8 #include "base/metrics/field_trial.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| 11 #include "base/time/clock.h" | |
| 11 #include "base/time/time.h" | 12 #include "base/time/time.h" |
| 12 #include "chrome/browser/profiles/profile.h" | 13 #include "chrome/browser/profiles/profile.h" |
| 14 #include "chrome/browser/ssl/bad_clock_blocking_page.h" | |
| 13 #include "chrome/browser/ssl/ssl_blocking_page.h" | 15 #include "chrome/browser/ssl/ssl_blocking_page.h" |
| 14 #include "chrome/browser/ssl/ssl_cert_reporter.h" | 16 #include "chrome/browser/ssl/ssl_cert_reporter.h" |
| 15 #include "chrome/browser/ssl/ssl_error_classification.h" | 17 #include "chrome/browser/ssl/ssl_error_classification.h" |
| 18 #include "chrome/browser/ssl/ssl_error_info.h" | |
| 16 #include "content/public/browser/notification_service.h" | 19 #include "content/public/browser/notification_service.h" |
| 17 #include "content/public/browser/notification_source.h" | 20 #include "content/public/browser/notification_source.h" |
| 18 #include "content/public/browser/render_frame_host.h" | 21 #include "content/public/browser/render_frame_host.h" |
| 19 #include "content/public/browser/web_contents.h" | 22 #include "content/public/browser/web_contents.h" |
| 20 #include "net/base/net_errors.h" | 23 #include "net/base/net_errors.h" |
| 21 | 24 |
| 22 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | 25 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 23 #include "chrome/browser/captive_portal/captive_portal_service.h" | 26 #include "chrome/browser/captive_portal/captive_portal_service.h" |
| 24 #include "chrome/browser/captive_portal/captive_portal_service_factory.h" | 27 #include "chrome/browser/captive_portal/captive_portal_service_factory.h" |
| 25 #include "chrome/browser/captive_portal/captive_portal_tab_helper.h" | 28 #include "chrome/browser/captive_portal/captive_portal_tab_helper.h" |
| 26 #include "chrome/browser/ssl/captive_portal_blocking_page.h" | 29 #include "chrome/browser/ssl/captive_portal_blocking_page.h" |
| 27 #endif | 30 #endif |
| 28 | 31 |
| 29 namespace { | 32 namespace { |
| 30 | 33 |
| 31 // The delay in milliseconds before displaying the SSL interstitial. | 34 // The delay in milliseconds before displaying the SSL interstitial. |
| 32 // This can be changed in tests. | 35 // This can be changed in tests. |
| 33 // - If there is a name mismatch and a suggested URL available result arrives | 36 // - If there is a name mismatch and a suggested URL available result arrives |
| 34 // during this time, the user is redirected to the suggester URL. | 37 // during this time, the user is redirected to the suggester URL. |
| 35 // - If a "captive portal detected" result arrives during this time, | 38 // - If a "captive portal detected" result arrives during this time, |
| 36 // a captive portal interstitial is displayed. | 39 // a captive portal interstitial is displayed. |
| 37 // - Otherwise, an SSL interstitial is displayed. | 40 // - Otherwise, an SSL interstitial is displayed. |
| 38 int64 g_interstitial_delay_in_milliseconds = 2000; | 41 int64 g_interstitial_delay_in_milliseconds = 2000; |
| 39 | 42 |
| 40 // Callback to call when the interstitial timer is started. Used for testing. | 43 // Callback to call when the interstitial timer is started. Used for testing. |
| 41 SSLErrorHandler::TimerStartedCallback* g_timer_started_callback = nullptr; | 44 SSLErrorHandler::TimerStartedCallback* g_timer_started_callback = nullptr; |
| 42 | 45 |
| 46 // The clock to use when deciding which error type to display. Used for testing. | |
| 47 base::Clock* g_testing_clock = nullptr; | |
| 48 | |
| 43 // Events for UMA. | 49 // Events for UMA. |
| 44 enum SSLErrorHandlerEvent { | 50 enum SSLErrorHandlerEvent { |
| 45 HANDLE_ALL, | 51 HANDLE_ALL, |
| 46 SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE, | 52 SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE, |
| 47 SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE, | 53 SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE, |
| 48 SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE, | 54 SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE, |
| 49 SHOW_SSL_INTERSTITIAL_OVERRIDABLE, | 55 SHOW_SSL_INTERSTITIAL_OVERRIDABLE, |
| 50 WWW_MISMATCH_FOUND, | 56 WWW_MISMATCH_FOUND, |
| 51 WWW_MISMATCH_URL_AVAILABLE, | 57 WWW_MISMATCH_URL_AVAILABLE, |
| 52 WWW_MISMATCH_URL_NOT_AVAILABLE, | 58 WWW_MISMATCH_URL_NOT_AVAILABLE, |
| 59 SHOW_BAD_CLOCK, | |
| 53 SSL_ERROR_HANDLER_EVENT_COUNT | 60 SSL_ERROR_HANDLER_EVENT_COUNT |
| 54 }; | 61 }; |
| 55 | 62 |
| 56 // Adds a message to console after navigation commits and then, deletes itself. | 63 // Adds a message to console after navigation commits and then, deletes itself. |
| 57 // Also deletes itself if the navigation is stopped. | 64 // Also deletes itself if the navigation is stopped. |
| 58 class CommonNameMismatchRedirectObserver | 65 class CommonNameMismatchRedirectObserver |
| 59 : public content::WebContentsObserver, | 66 : public content::WebContentsObserver, |
| 60 public content::WebContentsUserData<CommonNameMismatchRedirectObserver> { | 67 public content::WebContentsUserData<CommonNameMismatchRedirectObserver> { |
| 61 public: | 68 public: |
| 62 static void AddToConsoleAfterNavigation( | 69 static void AddToConsoleAfterNavigation( |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 118 return base::FieldTrialList::FindFullName("CaptivePortalInterstitial") == | 125 return base::FieldTrialList::FindFullName("CaptivePortalInterstitial") == |
| 119 "Enabled"; | 126 "Enabled"; |
| 120 } | 127 } |
| 121 #endif | 128 #endif |
| 122 | 129 |
| 123 bool IsSSLCommonNameMismatchHandlingEnabled() { | 130 bool IsSSLCommonNameMismatchHandlingEnabled() { |
| 124 return base::FieldTrialList::FindFullName("SSLCommonNameMismatchHandling") == | 131 return base::FieldTrialList::FindFullName("SSLCommonNameMismatchHandling") == |
| 125 "Enabled"; | 132 "Enabled"; |
| 126 } | 133 } |
| 127 | 134 |
| 135 bool IsErrorDueToBadClock(const base::Time& now, int error) { | |
| 136 if (SSLErrorInfo::NetErrorToErrorType(error) != | |
| 137 SSLErrorInfo::CERT_DATE_INVALID) { | |
| 138 return false; | |
| 139 } | |
| 140 if (g_testing_clock) { | |
| 141 SSLErrorClassification::SetBuildTimeForTesting( | |
|
estark
2015/09/01 13:28:28
nit: I'm curious if you considered calling this fr
felt
2015/09/01 15:49:41
Moved into the test.
| |
| 142 base::Time::NowFromSystemTime()); | |
| 143 } | |
| 144 return SSLErrorClassification::IsUserClockInThePast(now) || | |
| 145 SSLErrorClassification::IsUserClockInTheFuture(now); | |
| 146 } | |
| 147 | |
| 128 } // namespace | 148 } // namespace |
| 129 | 149 |
| 130 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SSLErrorHandler); | 150 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SSLErrorHandler); |
| 131 DEFINE_WEB_CONTENTS_USER_DATA_KEY(CommonNameMismatchRedirectObserver); | 151 DEFINE_WEB_CONTENTS_USER_DATA_KEY(CommonNameMismatchRedirectObserver); |
| 132 | 152 |
| 133 void SSLErrorHandler::HandleSSLError( | 153 void SSLErrorHandler::HandleSSLError( |
| 134 content::WebContents* web_contents, | 154 content::WebContents* web_contents, |
| 135 int cert_error, | 155 int cert_error, |
| 136 const net::SSLInfo& ssl_info, | 156 const net::SSLInfo& ssl_info, |
| 137 const GURL& request_url, | 157 const GURL& request_url, |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 151 g_interstitial_delay_in_milliseconds = delay.InMilliseconds(); | 171 g_interstitial_delay_in_milliseconds = delay.InMilliseconds(); |
| 152 } | 172 } |
| 153 | 173 |
| 154 // static | 174 // static |
| 155 void SSLErrorHandler::SetInterstitialTimerStartedCallbackForTest( | 175 void SSLErrorHandler::SetInterstitialTimerStartedCallbackForTest( |
| 156 TimerStartedCallback* callback) { | 176 TimerStartedCallback* callback) { |
| 157 DCHECK(!callback || !callback->is_null()); | 177 DCHECK(!callback || !callback->is_null()); |
| 158 g_timer_started_callback = callback; | 178 g_timer_started_callback = callback; |
| 159 } | 179 } |
| 160 | 180 |
| 181 // static | |
| 182 void SSLErrorHandler::SetClockForTest(base::Clock* testing_clock) { | |
| 183 g_testing_clock = testing_clock; | |
| 184 } | |
| 185 | |
| 161 SSLErrorHandler::SSLErrorHandler(content::WebContents* web_contents, | 186 SSLErrorHandler::SSLErrorHandler(content::WebContents* web_contents, |
| 162 int cert_error, | 187 int cert_error, |
| 163 const net::SSLInfo& ssl_info, | 188 const net::SSLInfo& ssl_info, |
| 164 const GURL& request_url, | 189 const GURL& request_url, |
| 165 int options_mask, | 190 int options_mask, |
| 166 scoped_ptr<SSLCertReporter> ssl_cert_reporter, | 191 scoped_ptr<SSLCertReporter> ssl_cert_reporter, |
| 167 const base::Callback<void(bool)>& callback) | 192 const base::Callback<void(bool)>& callback) |
| 168 : content::WebContentsObserver(web_contents), | 193 : content::WebContentsObserver(web_contents), |
| 169 web_contents_(web_contents), | 194 web_contents_(web_contents), |
| 170 cert_error_(cert_error), | 195 cert_error_(cert_error), |
| 171 ssl_info_(ssl_info), | 196 ssl_info_(ssl_info), |
| 172 request_url_(request_url), | 197 request_url_(request_url), |
| 173 options_mask_(options_mask), | 198 options_mask_(options_mask), |
| 174 callback_(callback), | 199 callback_(callback), |
| 175 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), | 200 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), |
| 176 ssl_cert_reporter_(ssl_cert_reporter.Pass()) {} | 201 ssl_cert_reporter_(ssl_cert_reporter.Pass()) {} |
| 177 | 202 |
| 178 SSLErrorHandler::~SSLErrorHandler() { | 203 SSLErrorHandler::~SSLErrorHandler() { |
| 179 } | 204 } |
| 180 | 205 |
| 181 void SSLErrorHandler::StartHandlingError() { | 206 void SSLErrorHandler::StartHandlingError() { |
| 182 RecordUMA(HANDLE_ALL); | 207 RecordUMA(HANDLE_ALL); |
| 183 | 208 |
| 209 const base::Time now = g_testing_clock == nullptr | |
| 210 ? base::Time::NowFromSystemTime() | |
| 211 : g_testing_clock->Now(); | |
| 212 if (IsErrorDueToBadClock(now, cert_error_)) { | |
| 213 ShowBadClockInterstitial(now); | |
| 214 return; // |this| is deleted after showing the interstitial. | |
| 215 } | |
| 216 | |
| 184 std::vector<std::string> dns_names; | 217 std::vector<std::string> dns_names; |
| 185 ssl_info_.cert->GetDNSNames(&dns_names); | 218 ssl_info_.cert->GetDNSNames(&dns_names); |
| 186 DCHECK(!dns_names.empty()); | 219 DCHECK(!dns_names.empty()); |
| 187 GURL suggested_url; | 220 GURL suggested_url; |
| 188 if (IsSSLCommonNameMismatchHandlingEnabled() && | 221 if (IsSSLCommonNameMismatchHandlingEnabled() && |
| 189 cert_error_ == net::ERR_CERT_COMMON_NAME_INVALID && | 222 cert_error_ == net::ERR_CERT_COMMON_NAME_INVALID && |
| 190 IsErrorOverridable() && GetSuggestedUrl(dns_names, &suggested_url)) { | 223 IsErrorOverridable() && GetSuggestedUrl(dns_names, &suggested_url)) { |
| 191 RecordUMA(WWW_MISMATCH_FOUND); | 224 RecordUMA(WWW_MISMATCH_FOUND); |
| 192 net::CertStatus extra_cert_errors = | 225 net::CertStatus extra_cert_errors = |
| 193 ssl_info_.cert_status ^ net::CERT_STATUS_COMMON_NAME_INVALID; | 226 ssl_info_.cert_status ^ net::CERT_STATUS_COMMON_NAME_INVALID; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 299 | 332 |
| 300 (new SSLBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_, | 333 (new SSLBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_, |
| 301 options_mask_, base::Time::NowFromSystemTime(), | 334 options_mask_, base::Time::NowFromSystemTime(), |
| 302 ssl_cert_reporter_.Pass(), callback_)) | 335 ssl_cert_reporter_.Pass(), callback_)) |
| 303 ->Show(); | 336 ->Show(); |
| 304 // Once an interstitial is displayed, no need to keep the handler around. | 337 // Once an interstitial is displayed, no need to keep the handler around. |
| 305 // This is the equivalent of "delete this". | 338 // This is the equivalent of "delete this". |
| 306 web_contents_->RemoveUserData(UserDataKey()); | 339 web_contents_->RemoveUserData(UserDataKey()); |
| 307 } | 340 } |
| 308 | 341 |
| 342 void SSLErrorHandler::ShowBadClockInterstitial(const base::Time& now) { | |
| 343 RecordUMA(SHOW_BAD_CLOCK); | |
| 344 (new BadClockBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_, | |
| 345 now, callback_)) | |
| 346 ->Show(); | |
| 347 // Once an interstitial is displayed, no need to keep the handler around. | |
| 348 // This is the equivalent of "delete this". | |
| 349 web_contents_->RemoveUserData(UserDataKey()); | |
| 350 } | |
| 351 | |
| 309 void SSLErrorHandler::CommonNameMismatchHandlerCallback( | 352 void SSLErrorHandler::CommonNameMismatchHandlerCallback( |
| 310 const CommonNameMismatchHandler::SuggestedUrlCheckResult& result, | 353 const CommonNameMismatchHandler::SuggestedUrlCheckResult& result, |
| 311 const GURL& suggested_url) { | 354 const GURL& suggested_url) { |
| 312 timer_.Stop(); | 355 timer_.Stop(); |
| 313 if (result == CommonNameMismatchHandler::SuggestedUrlCheckResult:: | 356 if (result == CommonNameMismatchHandler::SuggestedUrlCheckResult:: |
| 314 SUGGESTED_URL_AVAILABLE) { | 357 SUGGESTED_URL_AVAILABLE) { |
| 315 RecordUMA(WWW_MISMATCH_URL_AVAILABLE); | 358 RecordUMA(WWW_MISMATCH_URL_AVAILABLE); |
| 316 CommonNameMismatchRedirectObserver::AddToConsoleAfterNavigation( | 359 CommonNameMismatchRedirectObserver::AddToConsoleAfterNavigation( |
| 317 web_contents(), request_url_.host(), suggested_url.host()); | 360 web_contents(), request_url_.host(), suggested_url.host()); |
| 318 NavigateToSuggestedURL(suggested_url); | 361 NavigateToSuggestedURL(suggested_url); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 359 if (!callback_.is_null()) { | 402 if (!callback_.is_null()) { |
| 360 base::ResetAndReturn(&callback_).Run(false); | 403 base::ResetAndReturn(&callback_).Run(false); |
| 361 } | 404 } |
| 362 if (common_name_mismatch_handler_) { | 405 if (common_name_mismatch_handler_) { |
| 363 common_name_mismatch_handler_->Cancel(); | 406 common_name_mismatch_handler_->Cancel(); |
| 364 common_name_mismatch_handler_.reset(); | 407 common_name_mismatch_handler_.reset(); |
| 365 } | 408 } |
| 366 // Deletes |this| and also destroys the timer. | 409 // Deletes |this| and also destroys the timer. |
| 367 web_contents_->RemoveUserData(UserDataKey()); | 410 web_contents_->RemoveUserData(UserDataKey()); |
| 368 } | 411 } |
| OLD | NEW |