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 PROCEED_MANUAL_NONOVERRIDABLE,
79 UNUSED_BLOCKING_PAGE_EVENT,
82 void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event) {
83 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl",
85 UNUSED_BLOCKING_PAGE_EVENT);
88 void RecordSSLBlockingPageDetailedStats(
94 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type",
95 SSLErrorInfo::NetErrorToErrorType(cert_error), SSLErrorInfo::END_OF_ENUM);
98 RecordSSLBlockingPageEventStats(PROCEED_MANUAL_NONOVERRIDABLE);
100 // Overridable is false if the user didn't have any option except to turn
101 // back. If that's the case, don't record some of the metrics.
105 RecordSSLBlockingPageEventStats(SHOW_NEW_SITE);
107 RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE);
109 RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME);
111 RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE);
112 } else if (!proceed) {
113 RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE);
115 SSLErrorInfo::ErrorType type = SSLErrorInfo::NetErrorToErrorType(cert_error);
117 case SSLErrorInfo::CERT_COMMON_NAME_INVALID: {
119 RecordSSLBlockingPageEventStats(PROCEED_NAME);
121 RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME);
124 case SSLErrorInfo::CERT_DATE_INVALID: {
126 RecordSSLBlockingPageEventStats(PROCEED_DATE);
128 RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE);
131 case SSLErrorInfo::CERT_AUTHORITY_INVALID: {
133 RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY);
135 RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY);
146 // Note that we always create a navigation entry with SSL errors.
147 // No error happening loading a sub-resource triggers an interstitial so far.
148 SSLBlockingPage::SSLBlockingPage(
149 content::WebContents* web_contents,
151 const net::SSLInfo& ssl_info,
152 const GURL& request_url,
154 bool strict_enforcement,
155 const base::Callback<void(bool)>& callback)
156 : callback_(callback),
157 web_contents_(web_contents),
158 cert_error_(cert_error),
160 request_url_(request_url),
161 overridable_(overridable),
162 strict_enforcement_(strict_enforcement),
166 if (net::IsHostnameNonUnique(request_url_.HostNoBrackets()))
168 RecordSSLBlockingPageEventStats(SHOW_ALL);
169 if (overridable_ && !strict_enforcement_) {
170 RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE);
172 RecordSSLBlockingPageEventStats(SHOW_INTERNAL_HOSTNAME);
173 HistoryService* history_service = HistoryServiceFactory::GetForProfile(
174 Profile::FromBrowserContext(web_contents->GetBrowserContext()),
175 Profile::EXPLICIT_ACCESS);
176 if (history_service) {
177 history_service->GetVisibleVisitCountToHost(
180 base::Bind(&SSLBlockingPage::OnGotHistoryCount,
181 base::Unretained(this)));
185 interstitial_page_ = InterstitialPage::Create(
186 web_contents_, true, request_url, this);
187 interstitial_page_->Show();
190 SSLBlockingPage::~SSLBlockingPage() {
191 if (!callback_.is_null()) {
192 RecordSSLBlockingPageDetailedStats(false,
194 overridable_ && !strict_enforcement_,
197 // The page is closed without the user having chosen what to do, default to
199 NotifyDenyCertificate();
203 std::string SSLBlockingPage::GetHTMLContents() {
204 base::DictionaryValue strings;
206 if (overridable_ && !strict_enforcement_) {
207 // Let's build the overridable error page.
208 SSLErrorInfo error_info =
209 SSLErrorInfo::CreateError(
210 SSLErrorInfo::NetErrorToErrorType(cert_error_),
211 ssl_info_.cert.get(),
214 resource_id = IDR_SSL_ROAD_BLOCK_HTML;
215 strings.SetString("headLine", error_info.title());
216 strings.SetString("description", error_info.details());
217 strings.SetString("moreInfoTitle",
218 l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE));
219 SetExtraInfo(&strings, error_info.extra_information());
222 "exit", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_EXIT));
224 "title", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_TITLE));
226 "proceed", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_PROCEED));
228 "reasonForNotProceeding", l10n_util::GetStringUTF16(
229 IDS_SSL_OVERRIDABLE_PAGE_SHOULD_NOT_PROCEED));
230 strings.SetString("errorType", "overridable");
231 strings.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
233 // Let's build the blocking error page.
234 resource_id = IDR_SSL_BLOCKING_HTML;
236 // Strings that are not dependent on the URL.
238 "title", l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE));
240 "reloadMsg", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_RELOAD));
242 "more", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_MORE));
244 "less", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_LESS));
247 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TITLE));
250 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TECH_TITLE));
252 // Strings that are dependent on the URL.
253 base::string16 url(ASCIIToUTF16(request_url_.host()));
254 bool rtl = base::i18n::IsRTL();
255 strings.SetString("textDirection", rtl ? "rtl" : "ltr");
257 base::i18n::WrapStringWithLTRFormatting(&url);
259 "headline", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HEADLINE,
262 "message", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_BODY_TEXT,
266 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TEXT,
268 strings.SetString("reloadUrl", request_url_.spec());
270 // Strings that are dependent on the error type.
271 SSLErrorInfo::ErrorType type =
272 SSLErrorInfo::NetErrorToErrorType(cert_error_);
273 base::string16 errorType;
274 if (type == SSLErrorInfo::CERT_REVOKED) {
275 errorType = base::string16(ASCIIToUTF16("Key revocation"));
278 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_REVOKED));
279 } else if (type == SSLErrorInfo::CERT_INVALID) {
280 errorType = base::string16(ASCIIToUTF16("Malformed certificate"));
283 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_FORMATTED));
284 } else if (type == SSLErrorInfo::CERT_PINNED_KEY_MISSING) {
285 errorType = base::string16(ASCIIToUTF16("Certificate pinning failure"));
288 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_PINNING,
290 } else if (type == SSLErrorInfo::CERT_WEAK_KEY_DH) {
291 errorType = base::string16(ASCIIToUTF16("Weak DH public key"));
294 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_WEAK_DH,
298 errorType = base::string16(ASCIIToUTF16("HSTS failure"));
301 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HSTS, url.c_str()));
304 base::i18n::WrapStringWithLTRFormatting(&errorType);
306 "errorType", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ERROR,
309 // Strings that display the invalid cert.
310 base::string16 subject(
311 ASCIIToUTF16(ssl_info_.cert->subject().GetDisplayName()));
312 base::string16 issuer(
313 ASCIIToUTF16(ssl_info_.cert->issuer().GetDisplayName()));
315 for (std::vector<net::HashValue>::iterator it =
316 ssl_info_.public_key_hashes.begin();
317 it != ssl_info_.public_key_hashes.end();
319 base::StringAppendF(&hashes, "%s ", it->ToString().c_str());
321 base::string16 fingerprint(ASCIIToUTF16(hashes));
323 // These are always going to be LTR.
324 base::i18n::WrapStringWithLTRFormatting(&subject);
325 base::i18n::WrapStringWithLTRFormatting(&issuer);
326 base::i18n::WrapStringWithLTRFormatting(&fingerprint);
329 "subject", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_SUBJECT,
332 "issuer", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ISSUER,
336 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HASHES,
337 fingerprint.c_str()));
340 base::StringPiece html(
341 ResourceBundle::GetSharedInstance().GetRawDataResource(
343 return webui::GetI18nTemplateHtml(html, &strings);
346 void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
347 int cert_id = content::CertStore::GetInstance()->StoreCert(
348 ssl_info_.cert.get(), web_contents_->GetRenderProcessHost()->GetID());
350 entry->GetSSL().security_style =
351 content::SECURITY_STYLE_AUTHENTICATION_BROKEN;
352 entry->GetSSL().cert_id = cert_id;
353 entry->GetSSL().cert_status = ssl_info_.cert_status;
354 entry->GetSSL().security_bits = ssl_info_.security_bits;
355 #if !defined(OS_ANDROID)
356 Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
358 browser->VisibleSSLStateChanged(web_contents_);
359 #endif // !defined(OS_ANDROID)
362 // Matches events defined in ssl_error.html and ssl_roadblock.html.
363 void SSLBlockingPage::CommandReceived(const std::string& command) {
364 int cmd = atoi(command.c_str());
365 if (cmd == CMD_DONT_PROCEED) {
366 interstitial_page_->DontProceed();
367 } else if (cmd == CMD_PROCEED) {
368 interstitial_page_->Proceed();
369 } else if (cmd == CMD_MORE) {
370 RecordSSLBlockingPageEventStats(MORE);
371 } else if (cmd == CMD_RELOAD) {
372 // The interstitial can't refresh itself.
373 content::NavigationController* controller = &web_contents_->GetController();
374 controller->Reload(true);
378 void SSLBlockingPage::OverrideRendererPrefs(
379 content::RendererPreferences* prefs) {
380 Profile* profile = Profile::FromBrowserContext(
381 web_contents_->GetBrowserContext());
382 renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
385 void SSLBlockingPage::OnProceed() {
386 RecordSSLBlockingPageDetailedStats(true,
388 overridable_ && !strict_enforcement_,
391 // Accepting the certificate resumes the loading of the page.
392 NotifyAllowCertificate();
395 void SSLBlockingPage::OnDontProceed() {
396 RecordSSLBlockingPageDetailedStats(false,
398 overridable_ && !strict_enforcement_,
401 NotifyDenyCertificate();
404 void SSLBlockingPage::NotifyDenyCertificate() {
405 // It's possible that callback_ may not exist if the user clicks "Proceed"
406 // followed by pressing the back button before the interstitial is hidden.
407 // In that case the certificate will still be treated as allowed.
408 if (callback_.is_null())
411 callback_.Run(false);
415 void SSLBlockingPage::NotifyAllowCertificate() {
416 DCHECK(!callback_.is_null());
423 void SSLBlockingPage::SetExtraInfo(
424 base::DictionaryValue* strings,
425 const std::vector<base::string16>& extra_info) {
426 DCHECK_LT(extra_info.size(), 5U); // We allow 5 paragraphs max.
427 const char* keys[5] = {
428 "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
431 for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
432 strings->SetString(keys[i], extra_info[i]);
435 strings->SetString(keys[i], std::string());
439 void SSLBlockingPage::OnGotHistoryCount(HistoryService::Handle handle,
442 base::Time first_visit) {
443 num_visits_ = num_visits;