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/history/history_service_factory.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/renderer_preferences_util.h"
17 #include "chrome/browser/ssl/ssl_error_info.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_finder.h"
20 #include "content/public/browser/cert_store.h"
21 #include "content/public/browser/interstitial_page.h"
22 #include "content/public/browser/navigation_controller.h"
23 #include "content/public/browser/navigation_entry.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/browser/render_process_host.h"
27 #include "content/public/browser/render_view_host.h"
28 #include "content/public/browser/web_contents.h"
29 #include "content/public/common/ssl_status.h"
30 #include "grit/app_locale_settings.h"
31 #include "grit/browser_resources.h"
32 #include "grit/generated_resources.h"
33 #include "net/base/hash_value.h"
34 #include "net/base/net_errors.h"
35 #include "net/base/net_util.h"
36 #include "ui/base/l10n/l10n_util.h"
37 #include "ui/base/resource/resource_bundle.h"
38 #include "ui/base/webui/jstemplate_builder.h"
41 #include "base/win/windows_version.h"
44 using base::ASCIIToUTF16
;
45 using base::TimeTicks
;
46 using content::InterstitialPage
;
47 using content::NavigationController
;
48 using content::NavigationEntry
;
52 // These represent the commands sent by ssl_roadblock.html.
53 enum SSLBlockingPageCommands
{
61 enum SSLBlockingPageEvent
{
68 DONT_PROCEED_OVERRIDABLE
,
71 DONT_PROCEED_AUTHORITY
,
73 SHOW_UNDERSTAND
, // Used by the summer 2013 Finch trial. Deprecated.
74 SHOW_INTERNAL_HOSTNAME
,
75 PROCEED_INTERNAL_HOSTNAME
,
78 UNUSED_BLOCKING_PAGE_EVENT
,
81 void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event
) {
82 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl",
84 UNUSED_BLOCKING_PAGE_EVENT
);
87 void RecordSSLBlockingPageDetailedStats(
93 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type",
94 SSLErrorInfo::NetErrorToErrorType(cert_error
), SSLErrorInfo::END_OF_ENUM
);
96 // Overridable is false if the user didn't have any option except to turn
97 // back. If that's the case, don't record some of the metrics.
101 RecordSSLBlockingPageEventStats(SHOW_NEW_SITE
);
103 RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE
);
105 RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME
);
107 RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE
);
108 } else if (!proceed
) {
109 RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE
);
111 SSLErrorInfo::ErrorType type
= SSLErrorInfo::NetErrorToErrorType(cert_error
);
113 case SSLErrorInfo::CERT_COMMON_NAME_INVALID
: {
115 RecordSSLBlockingPageEventStats(PROCEED_NAME
);
117 RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME
);
120 case SSLErrorInfo::CERT_DATE_INVALID
: {
122 RecordSSLBlockingPageEventStats(PROCEED_DATE
);
124 RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE
);
127 case SSLErrorInfo::CERT_AUTHORITY_INVALID
: {
129 RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY
);
131 RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY
);
142 // Note that we always create a navigation entry with SSL errors.
143 // No error happening loading a sub-resource triggers an interstitial so far.
144 SSLBlockingPage::SSLBlockingPage(
145 content::WebContents
* web_contents
,
147 const net::SSLInfo
& ssl_info
,
148 const GURL
& request_url
,
150 bool strict_enforcement
,
151 const base::Callback
<void(bool)>& callback
)
152 : callback_(callback
),
153 web_contents_(web_contents
),
154 cert_error_(cert_error
),
156 request_url_(request_url
),
157 overridable_(overridable
),
158 strict_enforcement_(strict_enforcement
),
162 if (net::IsHostnameNonUnique(request_url_
.HostNoBrackets()))
164 RecordSSLBlockingPageEventStats(SHOW_ALL
);
165 if (overridable_
&& !strict_enforcement_
) {
166 RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE
);
168 RecordSSLBlockingPageEventStats(SHOW_INTERNAL_HOSTNAME
);
169 HistoryService
* history_service
= HistoryServiceFactory::GetForProfile(
170 Profile::FromBrowserContext(web_contents
->GetBrowserContext()),
171 Profile::EXPLICIT_ACCESS
);
172 if (history_service
) {
173 history_service
->GetVisibleVisitCountToHost(
176 base::Bind(&SSLBlockingPage::OnGotHistoryCount
,
177 base::Unretained(this)));
181 interstitial_page_
= InterstitialPage::Create(
182 web_contents_
, true, request_url
, this);
183 interstitial_page_
->Show();
186 SSLBlockingPage::~SSLBlockingPage() {
187 if (!callback_
.is_null()) {
188 RecordSSLBlockingPageDetailedStats(false,
190 overridable_
&& !strict_enforcement_
,
193 // The page is closed without the user having chosen what to do, default to
195 NotifyDenyCertificate();
199 std::string
SSLBlockingPage::GetHTMLContents() {
200 base::DictionaryValue strings
;
202 if (overridable_
&& !strict_enforcement_
) {
203 // Let's build the overridable error page.
204 SSLErrorInfo error_info
=
205 SSLErrorInfo::CreateError(
206 SSLErrorInfo::NetErrorToErrorType(cert_error_
),
207 ssl_info_
.cert
.get(),
210 resource_id
= IDR_SSL_ROAD_BLOCK_HTML
;
211 strings
.SetString("headLine", error_info
.title());
212 strings
.SetString("description", error_info
.details());
213 strings
.SetString("moreInfoTitle",
214 l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE
));
215 SetExtraInfo(&strings
, error_info
.extra_information());
218 "exit", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_EXIT
));
220 "title", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_TITLE
));
222 "proceed", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_PROCEED
));
224 "reasonForNotProceeding", l10n_util::GetStringUTF16(
225 IDS_SSL_OVERRIDABLE_PAGE_SHOULD_NOT_PROCEED
));
226 strings
.SetString("errorType", "overridable");
227 strings
.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
229 // Let's build the blocking error page.
230 resource_id
= IDR_SSL_BLOCKING_HTML
;
232 // Strings that are not dependent on the URL.
234 "title", l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE
));
236 "reloadMsg", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_RELOAD
));
238 "more", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_MORE
));
240 "less", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_LESS
));
243 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TITLE
));
246 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TECH_TITLE
));
248 // Strings that are dependent on the URL.
249 base::string16
url(ASCIIToUTF16(request_url_
.host()));
250 bool rtl
= base::i18n::IsRTL();
251 strings
.SetString("textDirection", rtl
? "rtl" : "ltr");
253 base::i18n::WrapStringWithLTRFormatting(&url
);
255 "headline", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HEADLINE
,
258 "message", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_BODY_TEXT
,
262 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TEXT
,
264 strings
.SetString("reloadUrl", request_url_
.spec());
266 // Strings that are dependent on the error type.
267 SSLErrorInfo::ErrorType type
=
268 SSLErrorInfo::NetErrorToErrorType(cert_error_
);
269 base::string16 errorType
;
270 if (type
== SSLErrorInfo::CERT_REVOKED
) {
271 errorType
= base::string16(ASCIIToUTF16("Key revocation"));
274 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_REVOKED
));
275 } else if (type
== SSLErrorInfo::CERT_INVALID
) {
276 errorType
= base::string16(ASCIIToUTF16("Malformed certificate"));
279 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_FORMATTED
));
280 } else if (type
== SSLErrorInfo::CERT_PINNED_KEY_MISSING
) {
281 errorType
= base::string16(ASCIIToUTF16("Certificate pinning failure"));
284 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_PINNING
,
286 } else if (type
== SSLErrorInfo::CERT_WEAK_KEY_DH
) {
287 errorType
= base::string16(ASCIIToUTF16("Weak DH public key"));
290 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_WEAK_DH
,
294 errorType
= base::string16(ASCIIToUTF16("HSTS failure"));
297 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HSTS
, url
.c_str()));
300 base::i18n::WrapStringWithLTRFormatting(&errorType
);
302 "errorType", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ERROR
,
305 // Strings that display the invalid cert.
306 base::string16
subject(
307 ASCIIToUTF16(ssl_info_
.cert
->subject().GetDisplayName()));
308 base::string16
issuer(
309 ASCIIToUTF16(ssl_info_
.cert
->issuer().GetDisplayName()));
311 for (std::vector
<net::HashValue
>::iterator it
=
312 ssl_info_
.public_key_hashes
.begin();
313 it
!= ssl_info_
.public_key_hashes
.end();
315 base::StringAppendF(&hashes
, "%s ", it
->ToString().c_str());
317 base::string16
fingerprint(ASCIIToUTF16(hashes
));
319 // These are always going to be LTR.
320 base::i18n::WrapStringWithLTRFormatting(&subject
);
321 base::i18n::WrapStringWithLTRFormatting(&issuer
);
322 base::i18n::WrapStringWithLTRFormatting(&fingerprint
);
325 "subject", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_SUBJECT
,
328 "issuer", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ISSUER
,
332 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HASHES
,
333 fingerprint
.c_str()));
336 base::StringPiece
html(
337 ResourceBundle::GetSharedInstance().GetRawDataResource(
339 return webui::GetI18nTemplateHtml(html
, &strings
);
342 void SSLBlockingPage::OverrideEntry(NavigationEntry
* entry
) {
343 int cert_id
= content::CertStore::GetInstance()->StoreCert(
344 ssl_info_
.cert
.get(), web_contents_
->GetRenderProcessHost()->GetID());
346 entry
->GetSSL().security_style
=
347 content::SECURITY_STYLE_AUTHENTICATION_BROKEN
;
348 entry
->GetSSL().cert_id
= cert_id
;
349 entry
->GetSSL().cert_status
= ssl_info_
.cert_status
;
350 entry
->GetSSL().security_bits
= ssl_info_
.security_bits
;
351 #if !defined(OS_ANDROID)
352 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents_
);
354 browser
->VisibleSSLStateChanged(web_contents_
);
355 #endif // !defined(OS_ANDROID)
358 // Matches events defined in ssl_error.html and ssl_roadblock.html.
359 void SSLBlockingPage::CommandReceived(const std::string
& command
) {
360 int cmd
= atoi(command
.c_str());
361 if (cmd
== CMD_DONT_PROCEED
) {
362 interstitial_page_
->DontProceed();
363 } else if (cmd
== CMD_PROCEED
) {
364 interstitial_page_
->Proceed();
365 } else if (cmd
== CMD_MORE
) {
366 RecordSSLBlockingPageEventStats(MORE
);
367 } else if (cmd
== CMD_RELOAD
) {
368 // The interstitial can't refresh itself.
369 content::NavigationController
* controller
= &web_contents_
->GetController();
370 controller
->Reload(true);
374 void SSLBlockingPage::OverrideRendererPrefs(
375 content::RendererPreferences
* prefs
) {
376 Profile
* profile
= Profile::FromBrowserContext(
377 web_contents_
->GetBrowserContext());
378 renderer_preferences_util::UpdateFromSystemSettings(prefs
, profile
);
381 void SSLBlockingPage::OnProceed() {
382 RecordSSLBlockingPageDetailedStats(true,
384 overridable_
&& !strict_enforcement_
,
387 // Accepting the certificate resumes the loading of the page.
388 NotifyAllowCertificate();
391 void SSLBlockingPage::OnDontProceed() {
392 RecordSSLBlockingPageDetailedStats(false,
394 overridable_
&& !strict_enforcement_
,
397 NotifyDenyCertificate();
400 void SSLBlockingPage::NotifyDenyCertificate() {
401 // It's possible that callback_ may not exist if the user clicks "Proceed"
402 // followed by pressing the back button before the interstitial is hidden.
403 // In that case the certificate will still be treated as allowed.
404 if (callback_
.is_null())
407 callback_
.Run(false);
411 void SSLBlockingPage::NotifyAllowCertificate() {
412 DCHECK(!callback_
.is_null());
419 void SSLBlockingPage::SetExtraInfo(
420 base::DictionaryValue
* strings
,
421 const std::vector
<base::string16
>& extra_info
) {
422 DCHECK_LT(extra_info
.size(), 5U); // We allow 5 paragraphs max.
423 const char* keys
[5] = {
424 "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
427 for (i
= 0; i
< static_cast<int>(extra_info
.size()); i
++) {
428 strings
->SetString(keys
[i
], extra_info
[i
]);
431 strings
->SetString(keys
[i
], std::string());
435 void SSLBlockingPage::OnGotHistoryCount(HistoryService::Handle handle
,
438 base::Time first_visit
) {
439 num_visits_
= num_visits
;