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
3 // found in the LICENSE file.
5 #include "chrome/browser/ssl/ssl_blocking_page.h"
7 #include "base/i18n/rtl.h"
8 #include "base/metrics/histogram.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_piece.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/history/history_service_factory.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/renderer_preferences_util.h"
18 #include "chrome/browser/ssl/ssl_error_info.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_finder.h"
21 #include "content/public/browser/cert_store.h"
22 #include "content/public/browser/interstitial_page.h"
23 #include "content/public/browser/navigation_controller.h"
24 #include "content/public/browser/navigation_entry.h"
25 #include "content/public/browser/notification_service.h"
26 #include "content/public/browser/notification_types.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/render_view_host.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/common/ssl_status.h"
31 #include "grit/app_locale_settings.h"
32 #include "grit/browser_resources.h"
33 #include "grit/generated_resources.h"
34 #include "net/base/hash_value.h"
35 #include "net/base/net_errors.h"
36 #include "net/base/net_util.h"
37 #include "ui/base/l10n/l10n_util.h"
38 #include "ui/base/resource/resource_bundle.h"
39 #include "ui/base/webui/jstemplate_builder.h"
41 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
42 #include "chrome/browser/captive_portal/captive_portal_service.h"
43 #include "chrome/browser/captive_portal/captive_portal_service_factory.h"
47 #include "base/win/windows_version.h"
50 using base::ASCIIToUTF16
;
51 using base::TimeTicks
;
52 using content::InterstitialPage
;
53 using content::NavigationController
;
54 using content::NavigationEntry
;
58 // These represent the commands sent by ssl_roadblock.html.
59 enum SSLBlockingPageCommands
{
67 enum SSLBlockingPageEvent
{
74 DONT_PROCEED_OVERRIDABLE
,
77 DONT_PROCEED_AUTHORITY
,
79 SHOW_UNDERSTAND
, // Used by the summer 2013 Finch trial. Deprecated.
80 SHOW_INTERNAL_HOSTNAME
,
81 PROCEED_INTERNAL_HOSTNAME
,
84 PROCEED_MANUAL_NONOVERRIDABLE
,
85 CAPTIVE_PORTAL_DETECTION_ENABLED
,
86 CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE
,
87 CAPTIVE_PORTAL_PROBE_COMPLETED
,
88 CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE
,
89 CAPTIVE_PORTAL_NO_RESPONSE
,
90 CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE
,
91 CAPTIVE_PORTAL_DETECTED
,
92 CAPTIVE_PORTAL_DETECTED_OVERRIDABLE
,
93 UNUSED_BLOCKING_PAGE_EVENT
,
96 void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event
) {
97 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl",
99 UNUSED_BLOCKING_PAGE_EVENT
);
102 void RecordSSLBlockingPageDetailedStats(
108 bool captive_portal_detection_enabled
,
109 bool captive_portal_probe_completed
,
110 bool captive_portal_no_response
,
111 bool captive_portal_detected
) {
112 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type",
113 SSLErrorInfo::NetErrorToErrorType(cert_error
), SSLErrorInfo::END_OF_ENUM
);
114 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
115 if (captive_portal_detection_enabled
)
116 RecordSSLBlockingPageEventStats(
118 CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE
:
119 CAPTIVE_PORTAL_DETECTION_ENABLED
);
120 if (captive_portal_probe_completed
)
121 RecordSSLBlockingPageEventStats(
123 CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE
:
124 CAPTIVE_PORTAL_PROBE_COMPLETED
);
125 // Log only one of portal detected and no response results.
126 if (captive_portal_detected
)
127 RecordSSLBlockingPageEventStats(
129 CAPTIVE_PORTAL_DETECTED_OVERRIDABLE
:
130 CAPTIVE_PORTAL_DETECTED
);
131 else if (captive_portal_no_response
)
132 RecordSSLBlockingPageEventStats(
134 CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE
:
135 CAPTIVE_PORTAL_NO_RESPONSE
);
139 RecordSSLBlockingPageEventStats(PROCEED_MANUAL_NONOVERRIDABLE
);
141 // Overridable is false if the user didn't have any option except to turn
142 // back. If that's the case, don't record some of the metrics.
146 RecordSSLBlockingPageEventStats(SHOW_NEW_SITE
);
148 RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE
);
150 RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME
);
152 RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE
);
153 } else if (!proceed
) {
154 RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE
);
156 SSLErrorInfo::ErrorType type
= SSLErrorInfo::NetErrorToErrorType(cert_error
);
158 case SSLErrorInfo::CERT_COMMON_NAME_INVALID
: {
160 RecordSSLBlockingPageEventStats(PROCEED_NAME
);
162 RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME
);
165 case SSLErrorInfo::CERT_DATE_INVALID
: {
167 RecordSSLBlockingPageEventStats(PROCEED_DATE
);
169 RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE
);
172 case SSLErrorInfo::CERT_AUTHORITY_INVALID
: {
174 RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY
);
176 RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY
);
187 // Note that we always create a navigation entry with SSL errors.
188 // No error happening loading a sub-resource triggers an interstitial so far.
189 SSLBlockingPage::SSLBlockingPage(
190 content::WebContents
* web_contents
,
192 const net::SSLInfo
& ssl_info
,
193 const GURL
& request_url
,
195 bool strict_enforcement
,
196 const base::Callback
<void(bool)>& callback
)
197 : callback_(callback
),
198 web_contents_(web_contents
),
199 cert_error_(cert_error
),
201 request_url_(request_url
),
202 overridable_(overridable
),
203 strict_enforcement_(strict_enforcement
),
206 captive_portal_detection_enabled_(false),
207 captive_portal_probe_completed_(false),
208 captive_portal_no_response_(false),
209 captive_portal_detected_(false) {
210 Profile
* profile
= Profile::FromBrowserContext(
211 web_contents
->GetBrowserContext());
213 if (net::IsHostnameNonUnique(request_url_
.HostNoBrackets()))
215 RecordSSLBlockingPageEventStats(SHOW_ALL
);
216 if (overridable_
&& !strict_enforcement_
) {
217 RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE
);
219 RecordSSLBlockingPageEventStats(SHOW_INTERNAL_HOSTNAME
);
220 HistoryService
* history_service
= HistoryServiceFactory::GetForProfile(
221 profile
, Profile::EXPLICIT_ACCESS
);
222 if (history_service
) {
223 history_service
->GetVisibleVisitCountToHost(
226 base::Bind(&SSLBlockingPage::OnGotHistoryCount
,
227 base::Unretained(this)));
231 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
232 captive_portal::CaptivePortalService
* captive_portal_service
=
233 captive_portal::CaptivePortalServiceFactory::GetForProfile(profile
);
234 captive_portal_detection_enabled_
= captive_portal_service
->enabled();
235 captive_portal_service
->DetectCaptivePortal();
237 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT
,
238 content::Source
<Profile
>(profile
));
241 interstitial_page_
= InterstitialPage::Create(
242 web_contents_
, true, request_url
, this);
243 interstitial_page_
->Show();
246 SSLBlockingPage::~SSLBlockingPage() {
247 if (!callback_
.is_null()) {
248 RecordSSLBlockingPageDetailedStats(false,
250 overridable_
&& !strict_enforcement_
,
253 captive_portal_detection_enabled_
,
254 captive_portal_probe_completed_
,
255 captive_portal_no_response_
,
256 captive_portal_detected_
);
257 // The page is closed without the user having chosen what to do, default to
259 NotifyDenyCertificate();
263 std::string
SSLBlockingPage::GetHTMLContents() {
264 base::DictionaryValue strings
;
266 if (overridable_
&& !strict_enforcement_
) {
267 // Let's build the overridable error page.
268 SSLErrorInfo error_info
=
269 SSLErrorInfo::CreateError(
270 SSLErrorInfo::NetErrorToErrorType(cert_error_
),
271 ssl_info_
.cert
.get(),
274 resource_id
= IDR_SSL_ROAD_BLOCK_HTML
;
275 strings
.SetString("headLine", error_info
.title());
276 strings
.SetString("description", error_info
.details());
277 strings
.SetString("moreInfoTitle",
278 l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE
));
279 SetExtraInfo(&strings
, error_info
.extra_information());
282 "exit", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_EXIT
));
284 "title", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_TITLE
));
286 "proceed", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_PROCEED
));
288 "reasonForNotProceeding", l10n_util::GetStringUTF16(
289 IDS_SSL_OVERRIDABLE_PAGE_SHOULD_NOT_PROCEED
));
290 strings
.SetString("errorType", "overridable");
291 strings
.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
293 // Let's build the blocking error page.
294 resource_id
= IDR_SSL_BLOCKING_HTML
;
296 // Strings that are not dependent on the URL.
298 "title", l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE
));
300 "reloadMsg", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_RELOAD
));
302 "more", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_MORE
));
304 "less", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_LESS
));
307 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TITLE
));
310 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TECH_TITLE
));
312 // Strings that are dependent on the URL.
313 base::string16
url(ASCIIToUTF16(request_url_
.host()));
314 bool rtl
= base::i18n::IsRTL();
315 strings
.SetString("textDirection", rtl
? "rtl" : "ltr");
317 base::i18n::WrapStringWithLTRFormatting(&url
);
319 "headline", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HEADLINE
,
322 "message", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_BODY_TEXT
,
326 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TEXT
,
328 strings
.SetString("reloadUrl", request_url_
.spec());
330 // Strings that are dependent on the error type.
331 SSLErrorInfo::ErrorType type
=
332 SSLErrorInfo::NetErrorToErrorType(cert_error_
);
333 base::string16 errorType
;
334 if (type
== SSLErrorInfo::CERT_REVOKED
) {
335 errorType
= base::string16(ASCIIToUTF16("Key revocation"));
338 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_REVOKED
));
339 } else if (type
== SSLErrorInfo::CERT_INVALID
) {
340 errorType
= base::string16(ASCIIToUTF16("Malformed certificate"));
343 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_FORMATTED
));
344 } else if (type
== SSLErrorInfo::CERT_PINNED_KEY_MISSING
) {
345 errorType
= base::string16(ASCIIToUTF16("Certificate pinning failure"));
348 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_PINNING
,
350 } else if (type
== SSLErrorInfo::CERT_WEAK_KEY_DH
) {
351 errorType
= base::string16(ASCIIToUTF16("Weak DH public key"));
354 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_WEAK_DH
,
358 errorType
= base::string16(ASCIIToUTF16("HSTS failure"));
361 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HSTS
, url
.c_str()));
364 base::i18n::WrapStringWithLTRFormatting(&errorType
);
366 "errorType", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ERROR
,
369 // Strings that display the invalid cert.
370 base::string16
subject(
371 ASCIIToUTF16(ssl_info_
.cert
->subject().GetDisplayName()));
372 base::string16
issuer(
373 ASCIIToUTF16(ssl_info_
.cert
->issuer().GetDisplayName()));
375 for (std::vector
<net::HashValue
>::const_iterator it
=
376 ssl_info_
.public_key_hashes
.begin();
377 it
!= ssl_info_
.public_key_hashes
.end();
379 base::StringAppendF(&hashes
, "%s ", it
->ToString().c_str());
381 base::string16
fingerprint(ASCIIToUTF16(hashes
));
383 // These are always going to be LTR.
384 base::i18n::WrapStringWithLTRFormatting(&subject
);
385 base::i18n::WrapStringWithLTRFormatting(&issuer
);
386 base::i18n::WrapStringWithLTRFormatting(&fingerprint
);
389 "subject", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_SUBJECT
,
392 "issuer", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ISSUER
,
396 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HASHES
,
397 fingerprint
.c_str()));
400 base::StringPiece
html(
401 ResourceBundle::GetSharedInstance().GetRawDataResource(
403 return webui::GetI18nTemplateHtml(html
, &strings
);
406 void SSLBlockingPage::OverrideEntry(NavigationEntry
* entry
) {
407 int cert_id
= content::CertStore::GetInstance()->StoreCert(
408 ssl_info_
.cert
.get(), web_contents_
->GetRenderProcessHost()->GetID());
411 entry
->GetSSL().security_style
=
412 content::SECURITY_STYLE_AUTHENTICATION_BROKEN
;
413 entry
->GetSSL().cert_id
= cert_id
;
414 entry
->GetSSL().cert_status
= ssl_info_
.cert_status
;
415 entry
->GetSSL().security_bits
= ssl_info_
.security_bits
;
416 #if !defined(OS_ANDROID)
417 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents_
);
419 browser
->VisibleSSLStateChanged(web_contents_
);
420 #endif // !defined(OS_ANDROID)
423 // Matches events defined in ssl_error.html and ssl_roadblock.html.
424 void SSLBlockingPage::CommandReceived(const std::string
& command
) {
425 int cmd
= atoi(command
.c_str());
426 if (cmd
== CMD_DONT_PROCEED
) {
427 interstitial_page_
->DontProceed();
428 } else if (cmd
== CMD_PROCEED
) {
429 interstitial_page_
->Proceed();
430 } else if (cmd
== CMD_MORE
) {
431 RecordSSLBlockingPageEventStats(MORE
);
432 } else if (cmd
== CMD_RELOAD
) {
433 // The interstitial can't refresh itself.
434 content::NavigationController
* controller
= &web_contents_
->GetController();
435 controller
->Reload(true);
439 void SSLBlockingPage::OverrideRendererPrefs(
440 content::RendererPreferences
* prefs
) {
441 Profile
* profile
= Profile::FromBrowserContext(
442 web_contents_
->GetBrowserContext());
443 renderer_preferences_util::UpdateFromSystemSettings(prefs
, profile
);
446 void SSLBlockingPage::OnProceed() {
447 RecordSSLBlockingPageDetailedStats(true,
449 overridable_
&& !strict_enforcement_
,
452 captive_portal_detection_enabled_
,
453 captive_portal_probe_completed_
,
454 captive_portal_no_response_
,
455 captive_portal_detected_
);
456 // Accepting the certificate resumes the loading of the page.
457 NotifyAllowCertificate();
460 void SSLBlockingPage::OnDontProceed() {
461 RecordSSLBlockingPageDetailedStats(false,
463 overridable_
&& !strict_enforcement_
,
466 captive_portal_detection_enabled_
,
467 captive_portal_probe_completed_
,
468 captive_portal_no_response_
,
469 captive_portal_detected_
);
470 NotifyDenyCertificate();
473 void SSLBlockingPage::NotifyDenyCertificate() {
474 // It's possible that callback_ may not exist if the user clicks "Proceed"
475 // followed by pressing the back button before the interstitial is hidden.
476 // In that case the certificate will still be treated as allowed.
477 if (callback_
.is_null())
480 callback_
.Run(false);
484 void SSLBlockingPage::NotifyAllowCertificate() {
485 DCHECK(!callback_
.is_null());
492 void SSLBlockingPage::SetExtraInfo(
493 base::DictionaryValue
* strings
,
494 const std::vector
<base::string16
>& extra_info
) {
495 DCHECK_LT(extra_info
.size(), 5U); // We allow 5 paragraphs max.
496 const char* keys
[5] = {
497 "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
500 for (i
= 0; i
< static_cast<int>(extra_info
.size()); i
++) {
501 strings
->SetString(keys
[i
], extra_info
[i
]);
504 strings
->SetString(keys
[i
], std::string());
508 void SSLBlockingPage::OnGotHistoryCount(HistoryService::Handle handle
,
511 base::Time first_visit
) {
512 num_visits_
= num_visits
;
515 void SSLBlockingPage::Observe(
517 const content::NotificationSource
& source
,
518 const content::NotificationDetails
& details
) {
519 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
520 if (type
== chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT
) {
521 captive_portal_probe_completed_
= true;
522 captive_portal::CaptivePortalService::Results
* results
=
523 content::Details
<captive_portal::CaptivePortalService::Results
>(
525 // If a captive portal was detected at any point when the interstitial was
526 // displayed, assume that the interstitial was caused by a captive portal.
528 // 1- Interstitial displayed and captive portal detected, setting the flag.
529 // 2- Captive portal detection automatically opens portal login page.
530 // 3- User logs in on the portal login page.
531 // A notification will be received here for RESULT_INTERNET_CONNECTED. Make
532 // sure we don't clear the captive portal flag, since the interstitial was
533 // potentially caused by the captive portal.
534 captive_portal_detected_
= captive_portal_detected_
||
535 (results
->result
== captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL
);
536 // Also keep track of non-HTTP portals and error cases.
537 captive_portal_no_response_
= captive_portal_no_response_
||
538 (results
->result
== captive_portal::RESULT_NO_RESPONSE
);