Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: chrome/browser/ssl/ssl_error_handler.cc

Issue 1223233002: Common Name Mismatch Handler For WWW Subdomain Mismatch case (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Resolved comments, added UMA Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
24 25
25 namespace { 26 namespace {
26 27
27 // The type of the delay before displaying the SSL interstitial. This can be 28 // The type of the delay before displaying the SSL interstitial. This can be
28 // changed in tests. 29 // changed in tests.
29 SSLErrorHandler::InterstitialDelayType g_interstitial_delay_type = 30 SSLErrorHandler::InterstitialDelayType g_interstitial_delay_type =
30 SSLErrorHandler::NORMAL; 31 SSLErrorHandler::NORMAL;
31 32
32 // Callback to call when the interstitial timer is started. Used for testing. 33 // Callback to call when the interstitial timer is started. Used for testing.
33 SSLErrorHandler::TimerStartedCallback* g_timer_started_callback = nullptr; 34 SSLErrorHandler::TimerStartedCallback* g_timer_started_callback = nullptr;
34 35
35 // Events for UMA. 36 // Events for UMA.
36 enum SSLErrorHandlerEvent { 37 enum SSLErrorHandlerEvent {
37 HANDLE_ALL, 38 HANDLE_ALL,
38 SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE, 39 SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE,
39 SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE, 40 SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE,
40 SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE, 41 SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE,
41 SHOW_SSL_INTERSTITIAL_OVERRIDABLE, 42 SHOW_SSL_INTERSTITIAL_OVERRIDABLE,
43 SHOW_COMMON_NAME_MISMATCH_INTERSTITIAL_NONOVERRIDABLE,
44 SHOW_COMMON_NAME_MISMATCH_INTERSTITIAL_OVERRIDABLE,
42 SSL_ERROR_HANDLER_EVENT_COUNT 45 SSL_ERROR_HANDLER_EVENT_COUNT
43 }; 46 };
44 47
45 void RecordUMA(SSLErrorHandlerEvent event) { 48 void RecordUMA(SSLErrorHandlerEvent event) {
46 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_handler", 49 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_handler",
47 event, 50 event,
48 SSL_ERROR_HANDLER_EVENT_COUNT); 51 SSL_ERROR_HANDLER_EVENT_COUNT);
49 } 52 }
50 53
51 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
52 // The delay before displaying the SSL interstitial for cert errors. 54 // The delay before displaying the SSL interstitial for cert errors.
53 // - If a "captive portal detected" result arrives in this many seconds, 55 // - If a "captive portal detected" or "suggested URL valid" result
54 // a captive portal interstitial is displayed. 56 // arrives in this many seconds, then a captive portal interstitial
57 // or a common name mismatch interstitial is displayed.
55 // - Otherwise, an SSL interstitial is displayed. 58 // - Otherwise, an SSL interstitial is displayed.
56 const int kDefaultInterstitialDisplayDelayInSeconds = 2; 59 const int kDefaultInterstitialDisplayDelayInSeconds = 2;
57 60
58 base::TimeDelta GetInterstitialDisplayDelay( 61 base::TimeDelta GetInterstitialDisplayDelay(
59 SSLErrorHandler::InterstitialDelayType delay) { 62 SSLErrorHandler::InterstitialDelayType delay) {
60 switch (delay) { 63 switch (delay) {
61 case SSLErrorHandler::LONG: 64 case SSLErrorHandler::LONG:
62 return base::TimeDelta::FromHours(1); 65 return base::TimeDelta::FromHours(1);
63 66
64 case SSLErrorHandler::NONE: 67 case SSLErrorHandler::NONE:
65 return base::TimeDelta(); 68 return base::TimeDelta();
66 69
67 case SSLErrorHandler::NORMAL: 70 case SSLErrorHandler::NORMAL:
68 return base::TimeDelta::FromSeconds( 71 return base::TimeDelta::FromSeconds(
69 kDefaultInterstitialDisplayDelayInSeconds); 72 kDefaultInterstitialDisplayDelayInSeconds);
70 73
71 default: 74 default:
72 NOTREACHED(); 75 NOTREACHED();
73 } 76 }
74 return base::TimeDelta(); 77 return base::TimeDelta();
75 } 78 }
76 79
80 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
77 bool IsCaptivePortalInterstitialEnabled() { 81 bool IsCaptivePortalInterstitialEnabled() {
78 return base::FieldTrialList::FindFullName("CaptivePortalInterstitial") == 82 return base::FieldTrialList::FindFullName("CaptivePortalInterstitial") ==
79 "Enabled"; 83 "Enabled";
80 } 84 }
81 #endif 85 #endif
82 86
83 } // namespace 87 } // namespace
84 88
85 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SSLErrorHandler); 89 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SSLErrorHandler);
86 90
87 void SSLErrorHandler::HandleSSLError( 91 void SSLErrorHandler::HandleSSLError(
88 content::WebContents* web_contents, 92 content::WebContents* web_contents,
89 int cert_error, 93 int cert_error,
90 const net::SSLInfo& ssl_info, 94 const net::SSLInfo& ssl_info,
91 const GURL& request_url, 95 const GURL& request_url,
92 int options_mask, 96 int options_mask,
93 scoped_ptr<SSLCertReporter> ssl_cert_reporter, 97 scoped_ptr<SSLCertReporter> ssl_cert_reporter,
94 const base::Callback<void(bool)>& callback) { 98 const base::Callback<void(bool)>& callback) {
95 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
96 CaptivePortalTabHelper* captive_portal_tab_helper =
97 CaptivePortalTabHelper::FromWebContents(web_contents);
98 if (captive_portal_tab_helper) {
99 captive_portal_tab_helper->OnSSLCertError(ssl_info);
100 }
101 #endif
102 DCHECK(!FromWebContents(web_contents)); 99 DCHECK(!FromWebContents(web_contents));
103 web_contents->SetUserData( 100 web_contents->SetUserData(
104 UserDataKey(), 101 UserDataKey(),
105 new SSLErrorHandler(web_contents, cert_error, ssl_info, request_url, 102 new SSLErrorHandler(web_contents, cert_error, ssl_info, request_url,
106 options_mask, ssl_cert_reporter.Pass(), callback)); 103 options_mask, ssl_cert_reporter.Pass(), callback));
107 104
108 SSLErrorHandler* error_handler = 105 SSLErrorHandler* error_handler =
109 SSLErrorHandler::FromWebContents(web_contents); 106 SSLErrorHandler::FromWebContents(web_contents);
110 error_handler->StartHandlingError(); 107 error_handler->StartHandlingError();
111 } 108 }
(...skipping 19 matching lines...) Expand all
131 scoped_ptr<SSLCertReporter> ssl_cert_reporter, 128 scoped_ptr<SSLCertReporter> ssl_cert_reporter,
132 const base::Callback<void(bool)>& callback) 129 const base::Callback<void(bool)>& callback)
133 : content::WebContentsObserver(web_contents), 130 : content::WebContentsObserver(web_contents),
134 web_contents_(web_contents), 131 web_contents_(web_contents),
135 cert_error_(cert_error), 132 cert_error_(cert_error),
136 ssl_info_(ssl_info), 133 ssl_info_(ssl_info),
137 request_url_(request_url), 134 request_url_(request_url),
138 options_mask_(options_mask), 135 options_mask_(options_mask),
139 callback_(callback), 136 callback_(callback),
140 ssl_cert_reporter_(ssl_cert_reporter.Pass()) { 137 ssl_cert_reporter_(ssl_cert_reporter.Pass()) {
141 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) 138 profile_ = Profile::FromBrowserContext(web_contents_->GetBrowserContext());
142 Profile* profile = Profile::FromBrowserContext(
143 web_contents->GetBrowserContext());
144 registrar_.Add(this,
145 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
146 content::Source<Profile>(profile));
147 #endif
148 } 139 }
149 140
150 SSLErrorHandler::~SSLErrorHandler() { 141 SSLErrorHandler::~SSLErrorHandler() {
151 } 142 }
152 143
153 void SSLErrorHandler::StartHandlingError() { 144 void SSLErrorHandler::StartHandlingError() {
154 RecordUMA(HANDLE_ALL); 145 RecordUMA(HANDLE_ALL);
155 146
147 std::vector<std::string> dns_names;
148 ssl_info_.cert->GetDNSNames(&dns_names);
149 DCHECK(!dns_names.empty());
150 GURL suggested_url;
151 if (GetSuggestedUrl(dns_names, &suggested_url)) {
152 net::CertStatus extra_cert_errors =
153 ssl_info_.cert_status ^ net::CERT_STATUS_COMMON_NAME_INVALID;
154
155 // Show the SSL intersitial if |CERT_STATUS_COMMON_NAME_INVALID| is not
156 // the only error. Need not check for captive portal in this case.
157 // (See the comment below).
158 if (extra_cert_errors) {
159 ShowSSLInterstitial(GURL());
160 return;
161 }
162 CheckSuggestedUrl(suggested_url);
163 timer_.Start(FROM_HERE,
164 GetInterstitialDisplayDelay(g_interstitial_delay_type), this,
165 &SSLErrorHandler::OnTimerExpired);
166 if (g_timer_started_callback)
167 g_timer_started_callback->Run(web_contents_);
168
169 // Do not check for a captive portal in this case, because a captive
170 // portal most likely cannot serve a valid certificate which passes the
171 // similarity check.
172 return;
173 }
174
156 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) 175 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
176 CaptivePortalTabHelper* captive_portal_tab_helper =
177 CaptivePortalTabHelper::FromWebContents(web_contents_);
178 if (captive_portal_tab_helper) {
179 captive_portal_tab_helper->OnSSLCertError(ssl_info_);
180 }
181
182 registrar_.Add(this, chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
183 content::Source<Profile>(profile_));
184
157 if (IsCaptivePortalInterstitialEnabled()) { 185 if (IsCaptivePortalInterstitialEnabled()) {
158 CheckForCaptivePortal(); 186 CheckForCaptivePortal();
159 timer_.Start(FROM_HERE, 187 timer_.Start(FROM_HERE,
160 GetInterstitialDisplayDelay(g_interstitial_delay_type), 188 GetInterstitialDisplayDelay(g_interstitial_delay_type),
161 this, &SSLErrorHandler::OnTimerExpired); 189 this, &SSLErrorHandler::OnTimerExpired);
162 if (g_timer_started_callback) 190 if (g_timer_started_callback)
163 g_timer_started_callback->Run(web_contents_); 191 g_timer_started_callback->Run(web_contents_);
164 return; 192 return;
165 } 193 }
166 #endif 194 #endif
167 // Display an SSL interstitial. 195 // Display an SSL interstitial.
168 ShowSSLInterstitial(); 196 ShowSSLInterstitial(GURL());
169 } 197 }
170 198
171 void SSLErrorHandler::OnTimerExpired() { 199 void SSLErrorHandler::OnTimerExpired() {
172 ShowSSLInterstitial(); 200 ShowSSLInterstitial(GURL());
201 }
202
203 bool SSLErrorHandler::GetSuggestedUrl(const std::vector<std::string>& dns_names,
204 GURL* suggested_url) const {
205 return CommonNameMismatchHandler::GetSuggestedUrl(request_url_, dns_names,
206 suggested_url);
207 }
208
209 void SSLErrorHandler::CheckSuggestedUrl(const GURL& suggested_url) {
210 scoped_refptr<net::URLRequestContextGetter> request_context(
211 profile_->GetRequestContext());
212 common_name_mismatch_handler_.reset(
213 new CommonNameMismatchHandler(request_url_, request_context));
214
215 common_name_mismatch_handler_->CheckSuggestedUrl(
216 suggested_url,
217 base::Bind(&SSLErrorHandler::CommonNameMismatchHandlerCallback,
218 base::Unretained(this)));
173 } 219 }
174 220
175 void SSLErrorHandler::CheckForCaptivePortal() { 221 void SSLErrorHandler::CheckForCaptivePortal() {
176 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) 222 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
177 Profile* profile = Profile::FromBrowserContext(
178 web_contents_->GetBrowserContext());
179 CaptivePortalService* captive_portal_service = 223 CaptivePortalService* captive_portal_service =
180 CaptivePortalServiceFactory::GetForProfile(profile); 224 CaptivePortalServiceFactory::GetForProfile(profile_);
181 captive_portal_service->DetectCaptivePortal(); 225 captive_portal_service->DetectCaptivePortal();
182 #else 226 #else
183 NOTREACHED(); 227 NOTREACHED();
184 #endif 228 #endif
185 } 229 }
186 230
187 void SSLErrorHandler::ShowCaptivePortalInterstitial(const GURL& landing_url) { 231 void SSLErrorHandler::ShowCaptivePortalInterstitial(const GURL& landing_url) {
188 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) 232 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
189 // Show captive portal blocking page. The interstitial owns the blocking page. 233 // Show captive portal blocking page. The interstitial owns the blocking page.
190 const Profile* const profile = 234 RecordUMA(SSLBlockingPage::IsOverridable(options_mask_, profile_)
191 Profile::FromBrowserContext(web_contents_->GetBrowserContext());
192 RecordUMA(SSLBlockingPage::IsOverridable(options_mask_, profile)
193 ? SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE 235 ? SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE
194 : SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE); 236 : SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE);
195 (new CaptivePortalBlockingPage(web_contents_, request_url_, landing_url, 237 (new CaptivePortalBlockingPage(web_contents_, request_url_, landing_url,
196 ssl_cert_reporter_.Pass(), ssl_info_, 238 ssl_cert_reporter_.Pass(), ssl_info_,
197 callback_))->Show(); 239 callback_))->Show();
198 // Once an interstitial is displayed, no need to keep the handler around. 240 // Once an interstitial is displayed, no need to keep the handler around.
199 // This is the equivalent of "delete this". 241 // This is the equivalent of "delete this".
200 web_contents_->RemoveUserData(UserDataKey()); 242 web_contents_->RemoveUserData(UserDataKey());
201 #else 243 #else
202 NOTREACHED(); 244 NOTREACHED();
203 #endif 245 #endif
204 } 246 }
205 247
206 void SSLErrorHandler::ShowSSLInterstitial() { 248 void SSLErrorHandler::ShowSSLInterstitial(const GURL& suggested_url) {
207 // Show SSL blocking page. The interstitial owns the blocking page. 249 // Show SSL blocking page. The interstitial owns the blocking page.
208 const Profile* const profile = 250
209 Profile::FromBrowserContext(web_contents_->GetBrowserContext()); 251 if (!suggested_url.is_empty()) {
210 RecordUMA(SSLBlockingPage::IsOverridable(options_mask_, profile) 252 RecordUMA(SSLBlockingPage::IsOverridable(options_mask_, profile_)
211 ? SHOW_SSL_INTERSTITIAL_OVERRIDABLE 253 ? SHOW_COMMON_NAME_MISMATCH_INTERSTITIAL_OVERRIDABLE
212 : SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE); 254 : SHOW_COMMON_NAME_MISMATCH_INTERSTITIAL_NONOVERRIDABLE);
255 } else {
256 RecordUMA(SSLBlockingPage::IsOverridable(options_mask_, profile_)
257 ? SHOW_SSL_INTERSTITIAL_OVERRIDABLE
258 : SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE);
259 }
260
213 (new SSLBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_, 261 (new SSLBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_,
214 options_mask_, base::Time::NowFromSystemTime(), 262 options_mask_, base::Time::NowFromSystemTime(),
215 ssl_cert_reporter_.Pass(), callback_))->Show(); 263 ssl_cert_reporter_.Pass(), callback_, suggested_url))
264 ->Show();
216 // Once an interstitial is displayed, no need to keep the handler around. 265 // Once an interstitial is displayed, no need to keep the handler around.
217 // This is the equivalent of "delete this". 266 // This is the equivalent of "delete this".
218 web_contents_->RemoveUserData(UserDataKey()); 267 web_contents_->RemoveUserData(UserDataKey());
219 } 268 }
220 269
221 void SSLErrorHandler::Observe( 270 void SSLErrorHandler::Observe(
222 int type, 271 int type,
223 const content::NotificationSource& source, 272 const content::NotificationSource& source,
224 const content::NotificationDetails& details) { 273 const content::NotificationDetails& details) {
225 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) 274 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
226 if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) { 275 if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) {
227 timer_.Stop(); 276 timer_.Stop();
228 CaptivePortalService::Results* results = 277 CaptivePortalService::Results* results =
229 content::Details<CaptivePortalService::Results>(details).ptr(); 278 content::Details<CaptivePortalService::Results>(details).ptr();
230 if (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL) 279 if (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL)
231 ShowCaptivePortalInterstitial(results->landing_url); 280 ShowCaptivePortalInterstitial(results->landing_url);
232 else 281 else
233 ShowSSLInterstitial(); 282 ShowSSLInterstitial(GURL());
234 } 283 }
235 #endif 284 #endif
236 } 285 }
237 286
238 // Destroy the error handler on all new navigations. This ensures that the 287 // 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 288 // handler is properly recreated when a hanging page is navigated to an SSL
240 // error, even when the tab's WebContents doesn't change. 289 // error, even when the tab's WebContents doesn't change.
241 void SSLErrorHandler::DidStartNavigationToPendingEntry( 290 void SSLErrorHandler::DidStartNavigationToPendingEntry(
242 const GURL& url, 291 const GURL& url,
243 content::NavigationController::ReloadType reload_type) { 292 content::NavigationController::ReloadType reload_type) {
244 // Need to explicity deny the certificate via the callback, otherwise memory 293 // Need to explicity deny the certificate via the callback, otherwise memory
245 // is leaked. 294 // is leaked.
246 if (!callback_.is_null()) { 295 if (!callback_.is_null()) {
247 base::ResetAndReturn(&callback_).Run(false); 296 base::ResetAndReturn(&callback_).Run(false);
248 } 297 }
249 web_contents_->RemoveUserData(UserDataKey()); 298 web_contents_->RemoveUserData(UserDataKey());
250 } 299 }
300
301 void SSLErrorHandler::CommonNameMismatchHandlerCallback(
302 const CommonNameMismatchHandler::Results& results) {
303 timer_.Stop();
304 if (results.result == CommonNameMismatchHandler::SuggestedUrlCheckResult::
305 SUGGESTED_URL_AVAILABLE) {
306 ShowSSLInterstitial(results.suggested_url);
307 } else {
308 ShowSSLInterstitial(GURL());
309 }
310 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698