Upstream version 5.34.104.0
[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::ASCIIToUTF16;
45 using base::TimeTicks;
46 using content::InterstitialPage;
47 using content::NavigationController;
48 using content::NavigationEntry;
49
50 namespace {
51
52 // These represent the commands sent by ssl_roadblock.html.
53 enum SSLBlockingPageCommands {
54   CMD_DONT_PROCEED,
55   CMD_PROCEED,
56   CMD_MORE,
57   CMD_RELOAD,
58 };
59
60 // Events for UMA.
61 enum SSLBlockingPageEvent {
62   SHOW_ALL,
63   SHOW_OVERRIDABLE,
64   PROCEED_OVERRIDABLE,
65   PROCEED_NAME,
66   PROCEED_DATE,
67   PROCEED_AUTHORITY,
68   DONT_PROCEED_OVERRIDABLE,
69   DONT_PROCEED_NAME,
70   DONT_PROCEED_DATE,
71   DONT_PROCEED_AUTHORITY,
72   MORE,
73   SHOW_UNDERSTAND,  // Used by the summer 2013 Finch trial. Deprecated.
74   SHOW_INTERNAL_HOSTNAME,
75   PROCEED_INTERNAL_HOSTNAME,
76   SHOW_NEW_SITE,
77   PROCEED_NEW_SITE,
78   PROCEED_MANUAL_NONOVERRIDABLE,
79   UNUSED_BLOCKING_PAGE_EVENT,
80 };
81
82 void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event) {
83   UMA_HISTOGRAM_ENUMERATION("interstitial.ssl",
84                             event,
85                             UNUSED_BLOCKING_PAGE_EVENT);
86 }
87
88 void RecordSSLBlockingPageDetailedStats(
89     bool proceed,
90     int cert_error,
91     bool overridable,
92     bool internal,
93     int num_visits) {
94   UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type",
95      SSLErrorInfo::NetErrorToErrorType(cert_error), SSLErrorInfo::END_OF_ENUM);
96   if (!overridable) {
97     if (proceed) {
98       RecordSSLBlockingPageEventStats(PROCEED_MANUAL_NONOVERRIDABLE);
99     }
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.
102     return;
103   }
104   if (num_visits == 0)
105     RecordSSLBlockingPageEventStats(SHOW_NEW_SITE);
106   if (proceed) {
107     RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE);
108     if (internal)
109       RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME);
110     if (num_visits == 0)
111       RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE);
112   } else if (!proceed) {
113     RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE);
114   }
115   SSLErrorInfo::ErrorType type = SSLErrorInfo::NetErrorToErrorType(cert_error);
116   switch (type) {
117     case SSLErrorInfo::CERT_COMMON_NAME_INVALID: {
118       if (proceed)
119         RecordSSLBlockingPageEventStats(PROCEED_NAME);
120       else
121         RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME);
122       break;
123     }
124     case SSLErrorInfo::CERT_DATE_INVALID: {
125       if (proceed)
126         RecordSSLBlockingPageEventStats(PROCEED_DATE);
127       else
128         RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE);
129       break;
130     }
131     case SSLErrorInfo::CERT_AUTHORITY_INVALID: {
132       if (proceed)
133         RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY);
134       else
135         RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY);
136       break;
137     }
138     default: {
139       break;
140     }
141   }
142 }
143
144 }  // namespace
145
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,
150     int cert_error,
151     const net::SSLInfo& ssl_info,
152     const GURL& request_url,
153     bool overridable,
154     bool strict_enforcement,
155     const base::Callback<void(bool)>& callback)
156     : callback_(callback),
157       web_contents_(web_contents),
158       cert_error_(cert_error),
159       ssl_info_(ssl_info),
160       request_url_(request_url),
161       overridable_(overridable),
162       strict_enforcement_(strict_enforcement),
163       internal_(false),
164       num_visits_(-1) {
165   // For UMA stats.
166   if (net::IsHostnameNonUnique(request_url_.HostNoBrackets()))
167     internal_ = true;
168   RecordSSLBlockingPageEventStats(SHOW_ALL);
169   if (overridable_ && !strict_enforcement_) {
170     RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE);
171     if (internal_)
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(
178           request_url_,
179           &request_consumer_,
180           base::Bind(&SSLBlockingPage::OnGotHistoryCount,
181                     base::Unretained(this)));
182     }
183   }
184
185   interstitial_page_ = InterstitialPage::Create(
186       web_contents_, true, request_url, this);
187   interstitial_page_->Show();
188 }
189
190 SSLBlockingPage::~SSLBlockingPage() {
191   if (!callback_.is_null()) {
192     RecordSSLBlockingPageDetailedStats(false,
193                                        cert_error_,
194                                        overridable_ && !strict_enforcement_,
195                                        internal_,
196                                        num_visits_);
197     // The page is closed without the user having chosen what to do, default to
198     // deny.
199     NotifyDenyCertificate();
200   }
201 }
202
203 std::string SSLBlockingPage::GetHTMLContents() {
204   base::DictionaryValue strings;
205   int resource_id;
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(),
212             request_url_);
213
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());
220
221     strings.SetString(
222         "exit", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_EXIT));
223     strings.SetString(
224         "title", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_TITLE));
225     strings.SetString(
226         "proceed", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_PROCEED));
227     strings.SetString(
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");
232   } else {
233     // Let's build the blocking error page.
234     resource_id = IDR_SSL_BLOCKING_HTML;
235
236     // Strings that are not dependent on the URL.
237     strings.SetString(
238         "title", l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE));
239     strings.SetString(
240         "reloadMsg", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_RELOAD));
241     strings.SetString(
242         "more", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_MORE));
243     strings.SetString(
244         "less", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_LESS));
245     strings.SetString(
246         "moreTitle",
247         l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TITLE));
248     strings.SetString(
249         "techTitle",
250         l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TECH_TITLE));
251
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");
256     if (rtl)
257       base::i18n::WrapStringWithLTRFormatting(&url);
258     strings.SetString(
259         "headline", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HEADLINE,
260                                                url.c_str()));
261     strings.SetString(
262         "message", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_BODY_TEXT,
263                                               url.c_str()));
264     strings.SetString(
265         "moreMessage",
266         l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TEXT,
267                                    url.c_str()));
268     strings.SetString("reloadUrl", request_url_.spec());
269
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"));
276       strings.SetString(
277           "failure",
278           l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_REVOKED));
279     } else if (type == SSLErrorInfo::CERT_INVALID) {
280       errorType = base::string16(ASCIIToUTF16("Malformed certificate"));
281       strings.SetString(
282           "failure",
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"));
286       strings.SetString(
287           "failure",
288           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_PINNING,
289                                      url.c_str()));
290     } else if (type == SSLErrorInfo::CERT_WEAK_KEY_DH) {
291       errorType = base::string16(ASCIIToUTF16("Weak DH public key"));
292       strings.SetString(
293           "failure",
294           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_WEAK_DH,
295                                      url.c_str()));
296     } else {
297       // HSTS failure.
298       errorType = base::string16(ASCIIToUTF16("HSTS failure"));
299       strings.SetString(
300           "failure",
301           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HSTS, url.c_str()));
302     }
303     if (rtl)
304       base::i18n::WrapStringWithLTRFormatting(&errorType);
305     strings.SetString(
306         "errorType", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ERROR,
307                                                 errorType.c_str()));
308
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()));
314     std::string hashes;
315     for (std::vector<net::HashValue>::iterator it =
316             ssl_info_.public_key_hashes.begin();
317          it != ssl_info_.public_key_hashes.end();
318          ++it) {
319       base::StringAppendF(&hashes, "%s ", it->ToString().c_str());
320     }
321     base::string16 fingerprint(ASCIIToUTF16(hashes));
322     if (rtl) {
323       // These are always going to be LTR.
324       base::i18n::WrapStringWithLTRFormatting(&subject);
325       base::i18n::WrapStringWithLTRFormatting(&issuer);
326       base::i18n::WrapStringWithLTRFormatting(&fingerprint);
327     }
328     strings.SetString(
329         "subject", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_SUBJECT,
330                                               subject.c_str()));
331     strings.SetString(
332         "issuer", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ISSUER,
333                                              issuer.c_str()));
334     strings.SetString(
335         "fingerprint",
336         l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HASHES,
337                                    fingerprint.c_str()));
338   }
339
340   base::StringPiece html(
341       ResourceBundle::GetSharedInstance().GetRawDataResource(
342           resource_id));
343   return webui::GetI18nTemplateHtml(html, &strings);
344 }
345
346 void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
347   int cert_id = content::CertStore::GetInstance()->StoreCert(
348       ssl_info_.cert.get(), web_contents_->GetRenderProcessHost()->GetID());
349
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_);
357   if (browser)
358     browser->VisibleSSLStateChanged(web_contents_);
359 #endif  // !defined(OS_ANDROID)
360 }
361
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);
375   }
376 }
377
378 void SSLBlockingPage::OverrideRendererPrefs(
379       content::RendererPreferences* prefs) {
380   Profile* profile = Profile::FromBrowserContext(
381       web_contents_->GetBrowserContext());
382   renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
383 }
384
385 void SSLBlockingPage::OnProceed() {
386   RecordSSLBlockingPageDetailedStats(true,
387                                      cert_error_,
388                                      overridable_ && !strict_enforcement_,
389                                      internal_,
390                                      num_visits_);
391   // Accepting the certificate resumes the loading of the page.
392   NotifyAllowCertificate();
393 }
394
395 void SSLBlockingPage::OnDontProceed() {
396   RecordSSLBlockingPageDetailedStats(false,
397                                      cert_error_,
398                                      overridable_ && !strict_enforcement_,
399                                      internal_,
400                                      num_visits_);
401   NotifyDenyCertificate();
402 }
403
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())
409     return;
410
411   callback_.Run(false);
412   callback_.Reset();
413 }
414
415 void SSLBlockingPage::NotifyAllowCertificate() {
416   DCHECK(!callback_.is_null());
417
418   callback_.Run(true);
419   callback_.Reset();
420 }
421
422 // static
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"
429   };
430   int i;
431   for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
432     strings->SetString(keys[i], extra_info[i]);
433   }
434   for (; i < 5; i++) {
435     strings->SetString(keys[i], std::string());
436   }
437 }
438
439 void SSLBlockingPage::OnGotHistoryCount(HistoryService::Handle handle,
440                                         bool success,
441                                         int num_visits,
442                                         base::Time first_visit) {
443   num_visits_ = num_visits;
444 }