- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ssl / ssl_blocking_page.cc
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.
4
5 #include "chrome/browser/ssl/ssl_blocking_page.h"
6
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"
39
40 #if defined(OS_WIN)
41 #include "base/win/windows_version.h"
42 #endif
43
44 using base::TimeTicks;
45 using content::InterstitialPage;
46 using content::NavigationController;
47 using content::NavigationEntry;
48
49 namespace {
50
51 // These represent the commands sent by ssl_roadblock.html.
52 enum SSLBlockingPageCommands {
53   CMD_DONT_PROCEED,
54   CMD_PROCEED,
55   CMD_MORE,
56   CMD_RELOAD,
57 };
58
59 // Events for UMA.
60 enum SSLBlockingPageEvent {
61   SHOW_ALL,
62   SHOW_OVERRIDABLE,
63   PROCEED_OVERRIDABLE,
64   PROCEED_NAME,
65   PROCEED_DATE,
66   PROCEED_AUTHORITY,
67   DONT_PROCEED_OVERRIDABLE,
68   DONT_PROCEED_NAME,
69   DONT_PROCEED_DATE,
70   DONT_PROCEED_AUTHORITY,
71   MORE,
72   SHOW_UNDERSTAND,  // Used by the summer 2013 Finch trial. Deprecated.
73   SHOW_INTERNAL_HOSTNAME,
74   PROCEED_INTERNAL_HOSTNAME,
75   SHOW_NEW_SITE,
76   PROCEED_NEW_SITE,
77   UNUSED_BLOCKING_PAGE_EVENT,
78 };
79
80 void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event) {
81   UMA_HISTOGRAM_ENUMERATION("interstitial.ssl",
82                             event,
83                             UNUSED_BLOCKING_PAGE_EVENT);
84 }
85
86 void RecordSSLBlockingPageDetailedStats(
87     bool proceed,
88     int cert_error,
89     bool overridable,
90     bool internal,
91     int num_visits) {
92   UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type",
93      SSLErrorInfo::NetErrorToErrorType(cert_error), SSLErrorInfo::END_OF_ENUM);
94   if (!overridable) {
95     // Overridable is false if the user didn't have any option except to turn
96     // back. If that's the case, don't record some of the metrics.
97     return;
98   }
99   if (num_visits == 0)
100     RecordSSLBlockingPageEventStats(SHOW_NEW_SITE);
101   if (proceed) {
102     RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE);
103     if (internal)
104       RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME);
105     if (num_visits == 0)
106       RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE);
107   } else if (!proceed) {
108     RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE);
109   }
110   SSLErrorInfo::ErrorType type = SSLErrorInfo::NetErrorToErrorType(cert_error);
111   switch (type) {
112     case SSLErrorInfo::CERT_COMMON_NAME_INVALID: {
113       if (proceed)
114         RecordSSLBlockingPageEventStats(PROCEED_NAME);
115       else
116         RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME);
117       break;
118     }
119     case SSLErrorInfo::CERT_DATE_INVALID: {
120       if (proceed)
121         RecordSSLBlockingPageEventStats(PROCEED_DATE);
122       else
123         RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE);
124       break;
125     }
126     case SSLErrorInfo::CERT_AUTHORITY_INVALID: {
127       if (proceed)
128         RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY);
129       else
130         RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY);
131       break;
132     }
133     default: {
134       break;
135     }
136   }
137 }
138
139 }  // namespace
140
141 // Note that we always create a navigation entry with SSL errors.
142 // No error happening loading a sub-resource triggers an interstitial so far.
143 SSLBlockingPage::SSLBlockingPage(
144     content::WebContents* web_contents,
145     int cert_error,
146     const net::SSLInfo& ssl_info,
147     const GURL& request_url,
148     bool overridable,
149     bool strict_enforcement,
150     const base::Callback<void(bool)>& callback)
151     : callback_(callback),
152       web_contents_(web_contents),
153       cert_error_(cert_error),
154       ssl_info_(ssl_info),
155       request_url_(request_url),
156       overridable_(overridable),
157       strict_enforcement_(strict_enforcement),
158       internal_(false),
159       num_visits_(-1) {
160   // For UMA stats.
161   if (net::IsHostnameNonUnique(request_url_.HostNoBrackets()))
162     internal_ = true;
163   RecordSSLBlockingPageEventStats(SHOW_ALL);
164   if (overridable_ && !strict_enforcement_) {
165     RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE);
166     if (internal_)
167       RecordSSLBlockingPageEventStats(SHOW_INTERNAL_HOSTNAME);
168     HistoryService* history_service = HistoryServiceFactory::GetForProfile(
169         Profile::FromBrowserContext(web_contents->GetBrowserContext()),
170         Profile::EXPLICIT_ACCESS);
171     if (history_service) {
172       history_service->GetVisibleVisitCountToHost(
173           request_url_,
174           &request_consumer_,
175           base::Bind(&SSLBlockingPage::OnGotHistoryCount,
176                     base::Unretained(this)));
177     }
178   }
179
180   interstitial_page_ = InterstitialPage::Create(
181       web_contents_, true, request_url, this);
182   interstitial_page_->Show();
183 }
184
185 SSLBlockingPage::~SSLBlockingPage() {
186   if (!callback_.is_null()) {
187     RecordSSLBlockingPageDetailedStats(false,
188                                        cert_error_,
189                                        overridable_ && !strict_enforcement_,
190                                        internal_,
191                                        num_visits_);
192     // The page is closed without the user having chosen what to do, default to
193     // deny.
194     NotifyDenyCertificate();
195   }
196 }
197
198 std::string SSLBlockingPage::GetHTMLContents() {
199   DictionaryValue strings;
200   int resource_id;
201   if (overridable_ && !strict_enforcement_) {
202     // Let's build the overridable error page.
203     SSLErrorInfo error_info =
204         SSLErrorInfo::CreateError(
205             SSLErrorInfo::NetErrorToErrorType(cert_error_),
206             ssl_info_.cert.get(),
207             request_url_);
208
209     resource_id = IDR_SSL_ROAD_BLOCK_HTML;
210     strings.SetString("headLine", error_info.title());
211     strings.SetString("description", error_info.details());
212     strings.SetString("moreInfoTitle",
213         l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE));
214     SetExtraInfo(&strings, error_info.extra_information());
215
216     strings.SetString(
217         "exit", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_EXIT));
218     strings.SetString(
219         "title", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_TITLE));
220     strings.SetString(
221         "proceed", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_PROCEED));
222     strings.SetString(
223         "reasonForNotProceeding", l10n_util::GetStringUTF16(
224             IDS_SSL_OVERRIDABLE_PAGE_SHOULD_NOT_PROCEED));
225     strings.SetString("errorType", "overridable");
226     strings.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
227   } else {
228     // Let's build the blocking error page.
229     resource_id = IDR_SSL_BLOCKING_HTML;
230
231     // Strings that are not dependent on the URL.
232     strings.SetString(
233         "title", l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE));
234     strings.SetString(
235         "reloadMsg", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_RELOAD));
236     strings.SetString(
237         "more", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_MORE));
238     strings.SetString(
239         "less", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_LESS));
240     strings.SetString(
241         "moreTitle",
242         l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TITLE));
243     strings.SetString(
244         "techTitle",
245         l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TECH_TITLE));
246
247     // Strings that are dependent on the URL.
248     string16 url(ASCIIToUTF16(request_url_.host()));
249     bool rtl = base::i18n::IsRTL();
250     strings.SetString("textDirection", rtl ? "rtl" : "ltr");
251     if (rtl)
252       base::i18n::WrapStringWithLTRFormatting(&url);
253     strings.SetString(
254         "headline", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HEADLINE,
255                                                url.c_str()));
256     strings.SetString(
257         "message", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_BODY_TEXT,
258                                               url.c_str()));
259     strings.SetString(
260         "moreMessage",
261         l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TEXT,
262                                    url.c_str()));
263     strings.SetString("reloadUrl", request_url_.spec());
264
265     // Strings that are dependent on the error type.
266     SSLErrorInfo::ErrorType type =
267         SSLErrorInfo::NetErrorToErrorType(cert_error_);
268     string16 errorType;
269     if (type == SSLErrorInfo::CERT_REVOKED) {
270       errorType = string16(ASCIIToUTF16("Key revocation"));
271       strings.SetString(
272           "failure",
273           l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_REVOKED));
274     } else if (type == SSLErrorInfo::CERT_INVALID) {
275       errorType = string16(ASCIIToUTF16("Malformed certificate"));
276       strings.SetString(
277           "failure",
278           l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_FORMATTED));
279     } else if (type == SSLErrorInfo::CERT_PINNED_KEY_MISSING) {
280       errorType = string16(ASCIIToUTF16("Certificate pinning failure"));
281       strings.SetString(
282           "failure",
283           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_PINNING,
284                                      url.c_str()));
285     } else if (type == SSLErrorInfo::CERT_WEAK_KEY_DH) {
286       errorType = string16(ASCIIToUTF16("Weak DH public key"));
287       strings.SetString(
288           "failure",
289           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_WEAK_DH,
290                                      url.c_str()));
291     } else {
292       // HSTS failure.
293       errorType = string16(ASCIIToUTF16("HSTS failure"));
294       strings.SetString(
295           "failure",
296           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HSTS, url.c_str()));
297     }
298     if (rtl)
299       base::i18n::WrapStringWithLTRFormatting(&errorType);
300     strings.SetString(
301         "errorType", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ERROR,
302                                                 errorType.c_str()));
303
304     // Strings that display the invalid cert.
305     string16 subject(ASCIIToUTF16(ssl_info_.cert->subject().GetDisplayName()));
306     string16 issuer(ASCIIToUTF16(ssl_info_.cert->issuer().GetDisplayName()));
307     std::string hashes;
308     for (std::vector<net::HashValue>::iterator it =
309             ssl_info_.public_key_hashes.begin();
310          it != ssl_info_.public_key_hashes.end();
311          ++it) {
312       base::StringAppendF(&hashes, "%s ", it->ToString().c_str());
313     }
314     string16 fingerprint(ASCIIToUTF16(hashes));
315     if (rtl) {
316       // These are always going to be LTR.
317       base::i18n::WrapStringWithLTRFormatting(&subject);
318       base::i18n::WrapStringWithLTRFormatting(&issuer);
319       base::i18n::WrapStringWithLTRFormatting(&fingerprint);
320     }
321     strings.SetString(
322         "subject", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_SUBJECT,
323                                               subject.c_str()));
324     strings.SetString(
325         "issuer", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ISSUER,
326                                              issuer.c_str()));
327     strings.SetString(
328         "fingerprint",
329         l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HASHES,
330                                    fingerprint.c_str()));
331   }
332
333   base::StringPiece html(
334       ResourceBundle::GetSharedInstance().GetRawDataResource(
335           resource_id));
336   return webui::GetI18nTemplateHtml(html, &strings);
337 }
338
339 void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
340   int cert_id = content::CertStore::GetInstance()->StoreCert(
341       ssl_info_.cert.get(), web_contents_->GetRenderProcessHost()->GetID());
342
343   entry->GetSSL().security_style =
344       content::SECURITY_STYLE_AUTHENTICATION_BROKEN;
345   entry->GetSSL().cert_id = cert_id;
346   entry->GetSSL().cert_status = ssl_info_.cert_status;
347   entry->GetSSL().security_bits = ssl_info_.security_bits;
348 #if !defined(OS_ANDROID)
349   Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
350   if (browser)
351     browser->VisibleSSLStateChanged(web_contents_);
352 #endif  // !defined(OS_ANDROID)
353 }
354
355 // Matches events defined in ssl_error.html and ssl_roadblock.html.
356 void SSLBlockingPage::CommandReceived(const std::string& command) {
357   int cmd = atoi(command.c_str());
358   if (cmd == CMD_DONT_PROCEED) {
359     interstitial_page_->DontProceed();
360   } else if (cmd == CMD_PROCEED) {
361     interstitial_page_->Proceed();
362   } else if (cmd == CMD_MORE) {
363     RecordSSLBlockingPageEventStats(MORE);
364   } else if (cmd == CMD_RELOAD) {
365     // The interstitial can't refresh itself.
366     content::NavigationController* controller = &web_contents_->GetController();
367     controller->Reload(true);
368   }
369 }
370
371 void SSLBlockingPage::OverrideRendererPrefs(
372       content::RendererPreferences* prefs) {
373   Profile* profile = Profile::FromBrowserContext(
374       web_contents_->GetBrowserContext());
375   renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
376 }
377
378 void SSLBlockingPage::OnProceed() {
379   RecordSSLBlockingPageDetailedStats(true,
380                                      cert_error_,
381                                      overridable_ && !strict_enforcement_,
382                                      internal_,
383                                      num_visits_);
384   // Accepting the certificate resumes the loading of the page.
385   NotifyAllowCertificate();
386 }
387
388 void SSLBlockingPage::OnDontProceed() {
389   RecordSSLBlockingPageDetailedStats(false,
390                                      cert_error_,
391                                      overridable_ && !strict_enforcement_,
392                                      internal_,
393                                      num_visits_);
394   NotifyDenyCertificate();
395 }
396
397 void SSLBlockingPage::NotifyDenyCertificate() {
398   // It's possible that callback_ may not exist if the user clicks "Proceed"
399   // followed by pressing the back button before the interstitial is hidden.
400   // In that case the certificate will still be treated as allowed.
401   if (callback_.is_null())
402     return;
403
404   callback_.Run(false);
405   callback_.Reset();
406 }
407
408 void SSLBlockingPage::NotifyAllowCertificate() {
409   DCHECK(!callback_.is_null());
410
411   callback_.Run(true);
412   callback_.Reset();
413 }
414
415 // static
416 void SSLBlockingPage::SetExtraInfo(
417     DictionaryValue* strings,
418     const std::vector<string16>& extra_info) {
419   DCHECK_LT(extra_info.size(), 5U);  // We allow 5 paragraphs max.
420   const char* keys[5] = {
421       "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
422   };
423   int i;
424   for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
425     strings->SetString(keys[i], extra_info[i]);
426   }
427   for (; i < 5; i++) {
428     strings->SetString(keys[i], std::string());
429   }
430 }
431
432 void SSLBlockingPage::OnGotHistoryCount(HistoryService::Handle handle,
433                                         bool success,
434                                         int num_visits,
435                                         base::Time first_visit) {
436   num_visits_ = num_visits;
437 }