| 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 return SSLErrorClassification::IsUserClockInThePast(now) || |
| 141 SSLErrorClassification::IsUserClockInTheFuture(now); |
| 142 } |
| 143 |
| 128 } // namespace | 144 } // namespace |
| 129 | 145 |
| 130 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SSLErrorHandler); | 146 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SSLErrorHandler); |
| 131 DEFINE_WEB_CONTENTS_USER_DATA_KEY(CommonNameMismatchRedirectObserver); | 147 DEFINE_WEB_CONTENTS_USER_DATA_KEY(CommonNameMismatchRedirectObserver); |
| 132 | 148 |
| 133 void SSLErrorHandler::HandleSSLError( | 149 void SSLErrorHandler::HandleSSLError( |
| 134 content::WebContents* web_contents, | 150 content::WebContents* web_contents, |
| 135 int cert_error, | 151 int cert_error, |
| 136 const net::SSLInfo& ssl_info, | 152 const net::SSLInfo& ssl_info, |
| 137 const GURL& request_url, | 153 const GURL& request_url, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 151 g_interstitial_delay_in_milliseconds = delay.InMilliseconds(); | 167 g_interstitial_delay_in_milliseconds = delay.InMilliseconds(); |
| 152 } | 168 } |
| 153 | 169 |
| 154 // static | 170 // static |
| 155 void SSLErrorHandler::SetInterstitialTimerStartedCallbackForTest( | 171 void SSLErrorHandler::SetInterstitialTimerStartedCallbackForTest( |
| 156 TimerStartedCallback* callback) { | 172 TimerStartedCallback* callback) { |
| 157 DCHECK(!callback || !callback->is_null()); | 173 DCHECK(!callback || !callback->is_null()); |
| 158 g_timer_started_callback = callback; | 174 g_timer_started_callback = callback; |
| 159 } | 175 } |
| 160 | 176 |
| 177 // static |
| 178 void SSLErrorHandler::SetClockForTest(base::Clock* testing_clock) { |
| 179 g_testing_clock = testing_clock; |
| 180 } |
| 181 |
| 161 SSLErrorHandler::SSLErrorHandler(content::WebContents* web_contents, | 182 SSLErrorHandler::SSLErrorHandler(content::WebContents* web_contents, |
| 162 int cert_error, | 183 int cert_error, |
| 163 const net::SSLInfo& ssl_info, | 184 const net::SSLInfo& ssl_info, |
| 164 const GURL& request_url, | 185 const GURL& request_url, |
| 165 int options_mask, | 186 int options_mask, |
| 166 scoped_ptr<SSLCertReporter> ssl_cert_reporter, | 187 scoped_ptr<SSLCertReporter> ssl_cert_reporter, |
| 167 const base::Callback<void(bool)>& callback) | 188 const base::Callback<void(bool)>& callback) |
| 168 : content::WebContentsObserver(web_contents), | 189 : content::WebContentsObserver(web_contents), |
| 169 web_contents_(web_contents), | 190 web_contents_(web_contents), |
| 170 cert_error_(cert_error), | 191 cert_error_(cert_error), |
| 171 ssl_info_(ssl_info), | 192 ssl_info_(ssl_info), |
| 172 request_url_(request_url), | 193 request_url_(request_url), |
| 173 options_mask_(options_mask), | 194 options_mask_(options_mask), |
| 174 callback_(callback), | 195 callback_(callback), |
| 175 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), | 196 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), |
| 176 ssl_cert_reporter_(ssl_cert_reporter.Pass()) {} | 197 ssl_cert_reporter_(ssl_cert_reporter.Pass()) {} |
| 177 | 198 |
| 178 SSLErrorHandler::~SSLErrorHandler() { | 199 SSLErrorHandler::~SSLErrorHandler() { |
| 179 } | 200 } |
| 180 | 201 |
| 181 void SSLErrorHandler::StartHandlingError() { | 202 void SSLErrorHandler::StartHandlingError() { |
| 182 RecordUMA(HANDLE_ALL); | 203 RecordUMA(HANDLE_ALL); |
| 183 | 204 |
| 205 const base::Time now = g_testing_clock == nullptr |
| 206 ? base::Time::NowFromSystemTime() |
| 207 : g_testing_clock->Now(); |
| 208 if (IsErrorDueToBadClock(now, cert_error_)) { |
| 209 ShowBadClockInterstitial(now); |
| 210 return; // |this| is deleted after showing the interstitial. |
| 211 } |
| 212 |
| 184 std::vector<std::string> dns_names; | 213 std::vector<std::string> dns_names; |
| 185 ssl_info_.cert->GetDNSNames(&dns_names); | 214 ssl_info_.cert->GetDNSNames(&dns_names); |
| 186 DCHECK(!dns_names.empty()); | 215 DCHECK(!dns_names.empty()); |
| 187 GURL suggested_url; | 216 GURL suggested_url; |
| 188 if (IsSSLCommonNameMismatchHandlingEnabled() && | 217 if (IsSSLCommonNameMismatchHandlingEnabled() && |
| 189 cert_error_ == net::ERR_CERT_COMMON_NAME_INVALID && | 218 cert_error_ == net::ERR_CERT_COMMON_NAME_INVALID && |
| 190 IsErrorOverridable() && GetSuggestedUrl(dns_names, &suggested_url)) { | 219 IsErrorOverridable() && GetSuggestedUrl(dns_names, &suggested_url)) { |
| 191 RecordUMA(WWW_MISMATCH_FOUND); | 220 RecordUMA(WWW_MISMATCH_FOUND); |
| 192 net::CertStatus extra_cert_errors = | 221 net::CertStatus extra_cert_errors = |
| 193 ssl_info_.cert_status ^ net::CERT_STATUS_COMMON_NAME_INVALID; | 222 ssl_info_.cert_status ^ net::CERT_STATUS_COMMON_NAME_INVALID; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 | 328 |
| 300 (new SSLBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_, | 329 (new SSLBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_, |
| 301 options_mask_, base::Time::NowFromSystemTime(), | 330 options_mask_, base::Time::NowFromSystemTime(), |
| 302 ssl_cert_reporter_.Pass(), callback_)) | 331 ssl_cert_reporter_.Pass(), callback_)) |
| 303 ->Show(); | 332 ->Show(); |
| 304 // Once an interstitial is displayed, no need to keep the handler around. | 333 // Once an interstitial is displayed, no need to keep the handler around. |
| 305 // This is the equivalent of "delete this". | 334 // This is the equivalent of "delete this". |
| 306 web_contents_->RemoveUserData(UserDataKey()); | 335 web_contents_->RemoveUserData(UserDataKey()); |
| 307 } | 336 } |
| 308 | 337 |
| 338 void SSLErrorHandler::ShowBadClockInterstitial(const base::Time& now) { |
| 339 RecordUMA(SHOW_BAD_CLOCK); |
| 340 (new BadClockBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_, |
| 341 now, callback_)) |
| 342 ->Show(); |
| 343 // Once an interstitial is displayed, no need to keep the handler around. |
| 344 // This is the equivalent of "delete this". |
| 345 web_contents_->RemoveUserData(UserDataKey()); |
| 346 } |
| 347 |
| 309 void SSLErrorHandler::CommonNameMismatchHandlerCallback( | 348 void SSLErrorHandler::CommonNameMismatchHandlerCallback( |
| 310 const CommonNameMismatchHandler::SuggestedUrlCheckResult& result, | 349 const CommonNameMismatchHandler::SuggestedUrlCheckResult& result, |
| 311 const GURL& suggested_url) { | 350 const GURL& suggested_url) { |
| 312 timer_.Stop(); | 351 timer_.Stop(); |
| 313 if (result == CommonNameMismatchHandler::SuggestedUrlCheckResult:: | 352 if (result == CommonNameMismatchHandler::SuggestedUrlCheckResult:: |
| 314 SUGGESTED_URL_AVAILABLE) { | 353 SUGGESTED_URL_AVAILABLE) { |
| 315 RecordUMA(WWW_MISMATCH_URL_AVAILABLE); | 354 RecordUMA(WWW_MISMATCH_URL_AVAILABLE); |
| 316 CommonNameMismatchRedirectObserver::AddToConsoleAfterNavigation( | 355 CommonNameMismatchRedirectObserver::AddToConsoleAfterNavigation( |
| 317 web_contents(), request_url_.host(), suggested_url.host()); | 356 web_contents(), request_url_.host(), suggested_url.host()); |
| 318 NavigateToSuggestedURL(suggested_url); | 357 NavigateToSuggestedURL(suggested_url); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 359 if (!callback_.is_null()) { | 398 if (!callback_.is_null()) { |
| 360 base::ResetAndReturn(&callback_).Run(false); | 399 base::ResetAndReturn(&callback_).Run(false); |
| 361 } | 400 } |
| 362 if (common_name_mismatch_handler_) { | 401 if (common_name_mismatch_handler_) { |
| 363 common_name_mismatch_handler_->Cancel(); | 402 common_name_mismatch_handler_->Cancel(); |
| 364 common_name_mismatch_handler_.reset(); | 403 common_name_mismatch_handler_.reset(); |
| 365 } | 404 } |
| 366 // Deletes |this| and also destroys the timer. | 405 // Deletes |this| and also destroys the timer. |
| 367 web_contents_->RemoveUserData(UserDataKey()); | 406 web_contents_->RemoveUserData(UserDataKey()); |
| 368 } | 407 } |
| OLD | NEW |