| 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/time/time.h" | 10 #include "base/time/time.h" |
| 11 #include "chrome/browser/profiles/profile.h" | 11 #include "chrome/browser/profiles/profile.h" |
| 12 #include "chrome/browser/ssl/ssl_blocking_page.h" | 12 #include "chrome/browser/ssl/ssl_blocking_page.h" |
| 13 #include "chrome/browser/ssl/ssl_cert_reporter.h" | 13 #include "chrome/browser/ssl/ssl_cert_reporter.h" |
| 14 #include "chrome/browser/ssl/ssl_error_classification.h" |
| 14 #include "content/public/browser/notification_service.h" | 15 #include "content/public/browser/notification_service.h" |
| 15 #include "content/public/browser/notification_source.h" | 16 #include "content/public/browser/notification_source.h" |
| 16 #include "content/public/browser/web_contents.h" | 17 #include "content/public/browser/web_contents.h" |
| 17 | 18 |
| 18 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | 19 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 19 #include "chrome/browser/captive_portal/captive_portal_service.h" | 20 #include "chrome/browser/captive_portal/captive_portal_service.h" |
| 20 #include "chrome/browser/captive_portal/captive_portal_service_factory.h" | 21 #include "chrome/browser/captive_portal/captive_portal_service_factory.h" |
| 21 #include "chrome/browser/captive_portal/captive_portal_tab_helper.h" | 22 #include "chrome/browser/captive_portal/captive_portal_tab_helper.h" |
| 22 #include "chrome/browser/ssl/captive_portal_blocking_page.h" | 23 #include "chrome/browser/ssl/captive_portal_blocking_page.h" |
| 23 #endif | 24 #endif |
| (...skipping 17 matching lines...) Expand all Loading... |
| 41 SHOW_SSL_INTERSTITIAL_OVERRIDABLE, | 42 SHOW_SSL_INTERSTITIAL_OVERRIDABLE, |
| 42 SSL_ERROR_HANDLER_EVENT_COUNT | 43 SSL_ERROR_HANDLER_EVENT_COUNT |
| 43 }; | 44 }; |
| 44 | 45 |
| 45 void RecordUMA(SSLErrorHandlerEvent event) { | 46 void RecordUMA(SSLErrorHandlerEvent event) { |
| 46 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_handler", | 47 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_handler", |
| 47 event, | 48 event, |
| 48 SSL_ERROR_HANDLER_EVENT_COUNT); | 49 SSL_ERROR_HANDLER_EVENT_COUNT); |
| 49 } | 50 } |
| 50 | 51 |
| 51 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | |
| 52 // The delay before displaying the SSL interstitial for cert errors. | 52 // The delay before displaying the SSL interstitial for cert errors. |
| 53 // - If a "captive portal detected" result arrives in this many seconds, | 53 // - If a "captive portal detected" or "suggested url valid" result |
| 54 // a captive portal interstitial is displayed. | 54 // arrives in this many seconds, then a captive portal interstitial |
| 55 // or a common name mismatch interstitial is displayed. |
| 55 // - Otherwise, an SSL interstitial is displayed. | 56 // - Otherwise, an SSL interstitial is displayed. |
| 56 const int kDefaultInterstitialDisplayDelayInSeconds = 2; | 57 const int kDefaultInterstitialDisplayDelayInSeconds = 2; |
| 57 | 58 |
| 58 base::TimeDelta GetInterstitialDisplayDelay( | 59 base::TimeDelta GetInterstitialDisplayDelay( |
| 59 SSLErrorHandler::InterstitialDelayType delay) { | 60 SSLErrorHandler::InterstitialDelayType delay) { |
| 60 switch (delay) { | 61 switch (delay) { |
| 61 case SSLErrorHandler::LONG: | 62 case SSLErrorHandler::LONG: |
| 62 return base::TimeDelta::FromHours(1); | 63 return base::TimeDelta::FromHours(1); |
| 63 | 64 |
| 64 case SSLErrorHandler::NONE: | 65 case SSLErrorHandler::NONE: |
| 65 return base::TimeDelta(); | 66 return base::TimeDelta(); |
| 66 | 67 |
| 67 case SSLErrorHandler::NORMAL: | 68 case SSLErrorHandler::NORMAL: |
| 68 return base::TimeDelta::FromSeconds( | 69 return base::TimeDelta::FromSeconds( |
| 69 kDefaultInterstitialDisplayDelayInSeconds); | 70 kDefaultInterstitialDisplayDelayInSeconds); |
| 70 | 71 |
| 71 default: | 72 default: |
| 72 NOTREACHED(); | 73 NOTREACHED(); |
| 73 } | 74 } |
| 74 return base::TimeDelta(); | 75 return base::TimeDelta(); |
| 75 } | 76 } |
| 76 | 77 |
| 78 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 77 bool IsCaptivePortalInterstitialEnabled() { | 79 bool IsCaptivePortalInterstitialEnabled() { |
| 78 return base::FieldTrialList::FindFullName("CaptivePortalInterstitial") == | 80 return base::FieldTrialList::FindFullName("CaptivePortalInterstitial") == |
| 79 "Enabled"; | 81 "Enabled"; |
| 80 } | 82 } |
| 81 #endif | 83 #endif |
| 82 | 84 |
| 83 } // namespace | 85 } // namespace |
| 84 | 86 |
| 85 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SSLErrorHandler); | 87 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SSLErrorHandler); |
| 86 | 88 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 content::Source<Profile>(profile)); | 148 content::Source<Profile>(profile)); |
| 147 #endif | 149 #endif |
| 148 } | 150 } |
| 149 | 151 |
| 150 SSLErrorHandler::~SSLErrorHandler() { | 152 SSLErrorHandler::~SSLErrorHandler() { |
| 151 } | 153 } |
| 152 | 154 |
| 153 void SSLErrorHandler::StartHandlingError() { | 155 void SSLErrorHandler::StartHandlingError() { |
| 154 RecordUMA(HANDLE_ALL); | 156 RecordUMA(HANDLE_ALL); |
| 155 | 157 |
| 158 std::vector<std::string> dns_names; |
| 159 ssl_info_.cert->GetDNSNames(&dns_names); |
| 160 DCHECK(!dns_names.empty()); |
| 161 GURL suggested_url; |
| 162 if (GetSuggestedUrl(request_url_, dns_names, &suggested_url)) { |
| 163 CheckSuggestedUrl(suggested_url); |
| 164 timer_.Start(FROM_HERE, |
| 165 GetInterstitialDisplayDelay(g_interstitial_delay_type), this, |
| 166 &SSLErrorHandler::OnTimerExpired); |
| 167 if (g_timer_started_callback) |
| 168 g_timer_started_callback->Run(web_contents_); |
| 169 |
| 170 // Do not check for a captive portal in this case, because a captive |
| 171 // portal most likely cannot serve a valid certificate which passes the |
| 172 // similarity check. |
| 173 return; |
| 174 } |
| 175 |
| 156 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | 176 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 157 if (IsCaptivePortalInterstitialEnabled()) { | 177 if (IsCaptivePortalInterstitialEnabled()) { |
| 158 CheckForCaptivePortal(); | 178 CheckForCaptivePortal(); |
| 159 timer_.Start(FROM_HERE, | 179 timer_.Start(FROM_HERE, |
| 160 GetInterstitialDisplayDelay(g_interstitial_delay_type), | 180 GetInterstitialDisplayDelay(g_interstitial_delay_type), |
| 161 this, &SSLErrorHandler::OnTimerExpired); | 181 this, &SSLErrorHandler::OnTimerExpired); |
| 162 if (g_timer_started_callback) | 182 if (g_timer_started_callback) |
| 163 g_timer_started_callback->Run(web_contents_); | 183 g_timer_started_callback->Run(web_contents_); |
| 164 return; | 184 return; |
| 165 } | 185 } |
| 166 #endif | 186 #endif |
| 167 // Display an SSL interstitial. | 187 // Display an SSL interstitial. |
| 168 ShowSSLInterstitial(); | 188 ShowSSLInterstitial(GURL()); |
| 169 } | 189 } |
| 170 | 190 |
| 171 void SSLErrorHandler::OnTimerExpired() { | 191 void SSLErrorHandler::OnTimerExpired() { |
| 172 ShowSSLInterstitial(); | 192 ShowSSLInterstitial(GURL()); |
| 193 } |
| 194 |
| 195 bool SSLErrorHandler::GetSuggestedUrl(const GURL& request_url, |
| 196 const std::vector<std::string>& dns_names, |
| 197 GURL* suggested_url) { |
| 198 return CommonNameMismatchHandler::GetSuggestedUrl(request_url_, dns_names, |
| 199 suggested_url); |
| 200 } |
| 201 |
| 202 void SSLErrorHandler::CheckSuggestedUrl(const GURL& suggested_url) { |
| 203 Profile* profile = |
| 204 Profile::FromBrowserContext(web_contents_->GetBrowserContext()); |
| 205 scoped_refptr<net::URLRequestContextGetter> request_context( |
| 206 profile->GetRequestContext()); |
| 207 common_name_mismatch_handler_.reset( |
| 208 new CommonNameMismatchHandler(request_url_, request_context)); |
| 209 common_name_mismatch_handler_->CheckSuggestedUrl( |
| 210 suggested_url, |
| 211 base::Bind(&SSLErrorHandler::CommonNameMismatchHandlerCallback, |
| 212 base::Unretained(this))); |
| 173 } | 213 } |
| 174 | 214 |
| 175 void SSLErrorHandler::CheckForCaptivePortal() { | 215 void SSLErrorHandler::CheckForCaptivePortal() { |
| 176 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | 216 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 177 Profile* profile = Profile::FromBrowserContext( | 217 Profile* profile = Profile::FromBrowserContext( |
| 178 web_contents_->GetBrowserContext()); | 218 web_contents_->GetBrowserContext()); |
| 179 CaptivePortalService* captive_portal_service = | 219 CaptivePortalService* captive_portal_service = |
| 180 CaptivePortalServiceFactory::GetForProfile(profile); | 220 CaptivePortalServiceFactory::GetForProfile(profile); |
| 181 captive_portal_service->DetectCaptivePortal(); | 221 captive_portal_service->DetectCaptivePortal(); |
| 182 #else | 222 #else |
| (...skipping 13 matching lines...) Expand all Loading... |
| 196 ssl_cert_reporter_.Pass(), ssl_info_, | 236 ssl_cert_reporter_.Pass(), ssl_info_, |
| 197 callback_))->Show(); | 237 callback_))->Show(); |
| 198 // Once an interstitial is displayed, no need to keep the handler around. | 238 // Once an interstitial is displayed, no need to keep the handler around. |
| 199 // This is the equivalent of "delete this". | 239 // This is the equivalent of "delete this". |
| 200 web_contents_->RemoveUserData(UserDataKey()); | 240 web_contents_->RemoveUserData(UserDataKey()); |
| 201 #else | 241 #else |
| 202 NOTREACHED(); | 242 NOTREACHED(); |
| 203 #endif | 243 #endif |
| 204 } | 244 } |
| 205 | 245 |
| 206 void SSLErrorHandler::ShowSSLInterstitial() { | 246 void SSLErrorHandler::ShowSSLInterstitial(const GURL& suggested_url) { |
| 207 // Show SSL blocking page. The interstitial owns the blocking page. | 247 // Show SSL blocking page. The interstitial owns the blocking page. |
| 208 const Profile* const profile = | 248 const Profile* const profile = |
| 209 Profile::FromBrowserContext(web_contents_->GetBrowserContext()); | 249 Profile::FromBrowserContext(web_contents_->GetBrowserContext()); |
| 210 RecordUMA(SSLBlockingPage::IsOverridable(options_mask_, profile) | 250 RecordUMA(SSLBlockingPage::IsOverridable(options_mask_, profile) |
| 211 ? SHOW_SSL_INTERSTITIAL_OVERRIDABLE | 251 ? SHOW_SSL_INTERSTITIAL_OVERRIDABLE |
| 212 : SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE); | 252 : SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE); |
| 213 (new SSLBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_, | 253 (new SSLBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_, |
| 214 options_mask_, base::Time::NowFromSystemTime(), | 254 options_mask_, base::Time::NowFromSystemTime(), |
| 215 ssl_cert_reporter_.Pass(), callback_))->Show(); | 255 ssl_cert_reporter_.Pass(), callback_, suggested_url)) |
| 256 ->Show(); |
| 216 // Once an interstitial is displayed, no need to keep the handler around. | 257 // Once an interstitial is displayed, no need to keep the handler around. |
| 217 // This is the equivalent of "delete this". | 258 // This is the equivalent of "delete this". |
| 218 web_contents_->RemoveUserData(UserDataKey()); | 259 web_contents_->RemoveUserData(UserDataKey()); |
| 219 } | 260 } |
| 220 | 261 |
| 221 void SSLErrorHandler::Observe( | 262 void SSLErrorHandler::Observe( |
| 222 int type, | 263 int type, |
| 223 const content::NotificationSource& source, | 264 const content::NotificationSource& source, |
| 224 const content::NotificationDetails& details) { | 265 const content::NotificationDetails& details) { |
| 225 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) | 266 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 226 if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) { | 267 if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) { |
| 227 timer_.Stop(); | 268 timer_.Stop(); |
| 228 CaptivePortalService::Results* results = | 269 CaptivePortalService::Results* results = |
| 229 content::Details<CaptivePortalService::Results>(details).ptr(); | 270 content::Details<CaptivePortalService::Results>(details).ptr(); |
| 230 if (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL) | 271 if (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL) |
| 231 ShowCaptivePortalInterstitial(results->landing_url); | 272 ShowCaptivePortalInterstitial(results->landing_url); |
| 232 else | 273 else |
| 233 ShowSSLInterstitial(); | 274 ShowSSLInterstitial(GURL()); |
| 234 } | 275 } |
| 235 #endif | 276 #endif |
| 236 } | 277 } |
| 237 | 278 |
| 238 // Destroy the error handler on all new navigations. This ensures that the | 279 // Destroy the error handler on all new navigations. This ensures that the |
| 239 // handler is properly recreated when a hanging page is navigated to an SSL | 280 // handler is properly recreated when a hanging page is navigated to an SSL |
| 240 // error, even when the tab's WebContents doesn't change. | 281 // error, even when the tab's WebContents doesn't change. |
| 241 void SSLErrorHandler::DidStartNavigationToPendingEntry( | 282 void SSLErrorHandler::DidStartNavigationToPendingEntry( |
| 242 const GURL& url, | 283 const GURL& url, |
| 243 content::NavigationController::ReloadType reload_type) { | 284 content::NavigationController::ReloadType reload_type) { |
| 244 // Need to explicity deny the certificate via the callback, otherwise memory | 285 // Need to explicity deny the certificate via the callback, otherwise memory |
| 245 // is leaked. | 286 // is leaked. |
| 246 if (!callback_.is_null()) { | 287 if (!callback_.is_null()) { |
| 247 base::ResetAndReturn(&callback_).Run(false); | 288 base::ResetAndReturn(&callback_).Run(false); |
| 248 } | 289 } |
| 249 web_contents_->RemoveUserData(UserDataKey()); | 290 web_contents_->RemoveUserData(UserDataKey()); |
| 250 } | 291 } |
| 292 |
| 293 void SSLErrorHandler::CommonNameMismatchHandlerCallback( |
| 294 const CommonNameMismatchHandler::Results& results) { |
| 295 timer_.Stop(); |
| 296 if (results.result == CommonNameMismatchHandler::SuggestedUrlCheckResult:: |
| 297 RESULT_SUGGESTED_URL_VALID) { |
| 298 ShowSSLInterstitial(results.new_url); |
| 299 } else { |
| 300 ShowSSLInterstitial(GURL()); |
| 301 } |
| 302 } |
| OLD | NEW |