Upstream version 7.36.149.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/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"
40
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"
44 #endif
45
46 #if defined(OS_WIN)
47 #include "base/win/windows_version.h"
48 #endif
49
50 using base::ASCIIToUTF16;
51 using base::TimeTicks;
52 using content::InterstitialPage;
53 using content::NavigationController;
54 using content::NavigationEntry;
55
56 namespace {
57
58 // These represent the commands sent by ssl_roadblock.html.
59 enum SSLBlockingPageCommands {
60   CMD_DONT_PROCEED,
61   CMD_PROCEED,
62   CMD_MORE,
63   CMD_RELOAD
64 };
65
66 // Events for UMA.
67 enum SSLBlockingPageEvent {
68   SHOW_ALL,
69   SHOW_OVERRIDABLE,
70   PROCEED_OVERRIDABLE,
71   PROCEED_NAME,
72   PROCEED_DATE,
73   PROCEED_AUTHORITY,
74   DONT_PROCEED_OVERRIDABLE,
75   DONT_PROCEED_NAME,
76   DONT_PROCEED_DATE,
77   DONT_PROCEED_AUTHORITY,
78   MORE,
79   SHOW_UNDERSTAND,  // Used by the summer 2013 Finch trial. Deprecated.
80   SHOW_INTERNAL_HOSTNAME,
81   PROCEED_INTERNAL_HOSTNAME,
82   SHOW_NEW_SITE,
83   PROCEED_NEW_SITE,
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,
94 };
95
96 void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event) {
97   UMA_HISTOGRAM_ENUMERATION("interstitial.ssl",
98                             event,
99                             UNUSED_BLOCKING_PAGE_EVENT);
100 }
101
102 void RecordSSLBlockingPageDetailedStats(
103     bool proceed,
104     int cert_error,
105     bool overridable,
106     bool internal,
107     int num_visits,
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(
117         overridable ?
118         CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE :
119         CAPTIVE_PORTAL_DETECTION_ENABLED);
120   if (captive_portal_probe_completed)
121     RecordSSLBlockingPageEventStats(
122         overridable ?
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(
128         overridable ?
129         CAPTIVE_PORTAL_DETECTED_OVERRIDABLE :
130         CAPTIVE_PORTAL_DETECTED);
131   else if (captive_portal_no_response)
132     RecordSSLBlockingPageEventStats(
133         overridable ?
134         CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE :
135         CAPTIVE_PORTAL_NO_RESPONSE);
136 #endif
137   if (!overridable) {
138     if (proceed) {
139       RecordSSLBlockingPageEventStats(PROCEED_MANUAL_NONOVERRIDABLE);
140     }
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.
143     return;
144   }
145   if (num_visits == 0)
146     RecordSSLBlockingPageEventStats(SHOW_NEW_SITE);
147   if (proceed) {
148     RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE);
149     if (internal)
150       RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME);
151     if (num_visits == 0)
152       RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE);
153   } else if (!proceed) {
154     RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE);
155   }
156   SSLErrorInfo::ErrorType type = SSLErrorInfo::NetErrorToErrorType(cert_error);
157   switch (type) {
158     case SSLErrorInfo::CERT_COMMON_NAME_INVALID: {
159       if (proceed)
160         RecordSSLBlockingPageEventStats(PROCEED_NAME);
161       else
162         RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME);
163       break;
164     }
165     case SSLErrorInfo::CERT_DATE_INVALID: {
166       if (proceed)
167         RecordSSLBlockingPageEventStats(PROCEED_DATE);
168       else
169         RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE);
170       break;
171     }
172     case SSLErrorInfo::CERT_AUTHORITY_INVALID: {
173       if (proceed)
174         RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY);
175       else
176         RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY);
177       break;
178     }
179     default: {
180       break;
181     }
182   }
183 }
184
185 }  // namespace
186
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,
191     int cert_error,
192     const net::SSLInfo& ssl_info,
193     const GURL& request_url,
194     bool overridable,
195     bool strict_enforcement,
196     const base::Callback<void(bool)>& callback)
197     : callback_(callback),
198       web_contents_(web_contents),
199       cert_error_(cert_error),
200       ssl_info_(ssl_info),
201       request_url_(request_url),
202       overridable_(overridable),
203       strict_enforcement_(strict_enforcement),
204       internal_(false),
205       num_visits_(-1),
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());
212   // For UMA stats.
213   if (net::IsHostnameNonUnique(request_url_.HostNoBrackets()))
214     internal_ = true;
215   RecordSSLBlockingPageEventStats(SHOW_ALL);
216   if (overridable_ && !strict_enforcement_) {
217     RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE);
218     if (internal_)
219       RecordSSLBlockingPageEventStats(SHOW_INTERNAL_HOSTNAME);
220     HistoryService* history_service = HistoryServiceFactory::GetForProfile(
221         profile, Profile::EXPLICIT_ACCESS);
222     if (history_service) {
223       history_service->GetVisibleVisitCountToHost(
224           request_url_,
225           &request_consumer_,
226           base::Bind(&SSLBlockingPage::OnGotHistoryCount,
227                     base::Unretained(this)));
228     }
229   }
230
231 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
232   CaptivePortalService* captive_portal_service =
233       CaptivePortalServiceFactory::GetForProfile(profile);
234   captive_portal_detection_enabled_ = captive_portal_service ->enabled();
235   captive_portal_service ->DetectCaptivePortal();
236   registrar_.Add(this,
237                  chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
238                  content::Source<Profile>(profile));
239 #endif
240
241   interstitial_page_ = InterstitialPage::Create(
242       web_contents_, true, request_url, this);
243   interstitial_page_->Show();
244 }
245
246 SSLBlockingPage::~SSLBlockingPage() {
247   if (!callback_.is_null()) {
248     RecordSSLBlockingPageDetailedStats(false,
249                                        cert_error_,
250                                        overridable_ && !strict_enforcement_,
251                                        internal_,
252                                        num_visits_,
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
258     // deny.
259     NotifyDenyCertificate();
260   }
261 }
262
263 std::string SSLBlockingPage::GetHTMLContents() {
264   base::DictionaryValue strings;
265   int resource_id;
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(),
272             request_url_);
273
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());
280
281     strings.SetString(
282         "exit", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_EXIT));
283     strings.SetString(
284         "title", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_TITLE));
285     strings.SetString(
286         "proceed", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_PROCEED));
287     strings.SetString(
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");
292   } else {
293     // Let's build the blocking error page.
294     resource_id = IDR_SSL_BLOCKING_HTML;
295
296     // Strings that are not dependent on the URL.
297     strings.SetString(
298         "title", l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE));
299     strings.SetString(
300         "reloadMsg", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_RELOAD));
301     strings.SetString(
302         "more", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_MORE));
303     strings.SetString(
304         "less", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_LESS));
305     strings.SetString(
306         "moreTitle",
307         l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TITLE));
308     strings.SetString(
309         "techTitle",
310         l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TECH_TITLE));
311
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");
316     if (rtl)
317       base::i18n::WrapStringWithLTRFormatting(&url);
318     strings.SetString(
319         "headline", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HEADLINE,
320                                                url.c_str()));
321     strings.SetString(
322         "message", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_BODY_TEXT,
323                                               url.c_str()));
324     strings.SetString(
325         "moreMessage",
326         l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TEXT,
327                                    url.c_str()));
328     strings.SetString("reloadUrl", request_url_.spec());
329
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"));
336       strings.SetString(
337           "failure",
338           l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_REVOKED));
339     } else if (type == SSLErrorInfo::CERT_INVALID) {
340       errorType = base::string16(ASCIIToUTF16("Malformed certificate"));
341       strings.SetString(
342           "failure",
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"));
346       strings.SetString(
347           "failure",
348           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_PINNING,
349                                      url.c_str()));
350     } else if (type == SSLErrorInfo::CERT_WEAK_KEY_DH) {
351       errorType = base::string16(ASCIIToUTF16("Weak DH public key"));
352       strings.SetString(
353           "failure",
354           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_WEAK_DH,
355                                      url.c_str()));
356     } else {
357       // HSTS failure.
358       errorType = base::string16(ASCIIToUTF16("HSTS failure"));
359       strings.SetString(
360           "failure",
361           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HSTS, url.c_str()));
362     }
363     if (rtl)
364       base::i18n::WrapStringWithLTRFormatting(&errorType);
365     strings.SetString(
366         "errorType", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ERROR,
367                                                 errorType.c_str()));
368
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()));
374     std::string hashes;
375     for (std::vector<net::HashValue>::const_iterator it =
376             ssl_info_.public_key_hashes.begin();
377          it != ssl_info_.public_key_hashes.end();
378          ++it) {
379       base::StringAppendF(&hashes, "%s ", it->ToString().c_str());
380     }
381     base::string16 fingerprint(ASCIIToUTF16(hashes));
382     if (rtl) {
383       // These are always going to be LTR.
384       base::i18n::WrapStringWithLTRFormatting(&subject);
385       base::i18n::WrapStringWithLTRFormatting(&issuer);
386       base::i18n::WrapStringWithLTRFormatting(&fingerprint);
387     }
388     strings.SetString(
389         "subject", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_SUBJECT,
390                                               subject.c_str()));
391     strings.SetString(
392         "issuer", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ISSUER,
393                                              issuer.c_str()));
394     strings.SetString(
395         "fingerprint",
396         l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HASHES,
397                                    fingerprint.c_str()));
398   }
399
400   base::StringPiece html(
401       ResourceBundle::GetSharedInstance().GetRawDataResource(
402           resource_id));
403   return webui::GetI18nTemplateHtml(html, &strings);
404 }
405
406 void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
407   int cert_id = content::CertStore::GetInstance()->StoreCert(
408       ssl_info_.cert.get(), web_contents_->GetRenderProcessHost()->GetID());
409   DCHECK(cert_id);
410
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_);
418   if (browser)
419     browser->VisibleSSLStateChanged(web_contents_);
420 #endif  // !defined(OS_ANDROID)
421 }
422
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);
436   }
437 }
438
439 void SSLBlockingPage::OverrideRendererPrefs(
440       content::RendererPreferences* prefs) {
441   Profile* profile = Profile::FromBrowserContext(
442       web_contents_->GetBrowserContext());
443   renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
444 }
445
446 void SSLBlockingPage::OnProceed() {
447   RecordSSLBlockingPageDetailedStats(true,
448                                      cert_error_,
449                                      overridable_ && !strict_enforcement_,
450                                      internal_,
451                                      num_visits_,
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();
458 }
459
460 void SSLBlockingPage::OnDontProceed() {
461   RecordSSLBlockingPageDetailedStats(false,
462                                      cert_error_,
463                                      overridable_ && !strict_enforcement_,
464                                      internal_,
465                                      num_visits_,
466                                      captive_portal_detection_enabled_,
467                                      captive_portal_probe_completed_,
468                                      captive_portal_no_response_,
469                                      captive_portal_detected_);
470   NotifyDenyCertificate();
471 }
472
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())
478     return;
479
480   callback_.Run(false);
481   callback_.Reset();
482 }
483
484 void SSLBlockingPage::NotifyAllowCertificate() {
485   DCHECK(!callback_.is_null());
486
487   callback_.Run(true);
488   callback_.Reset();
489 }
490
491 // static
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"
498   };
499   int i;
500   for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
501     strings->SetString(keys[i], extra_info[i]);
502   }
503   for (; i < 5; i++) {
504     strings->SetString(keys[i], std::string());
505   }
506 }
507
508 void SSLBlockingPage::OnGotHistoryCount(HistoryService::Handle handle,
509                                         bool success,
510                                         int num_visits,
511                                         base::Time first_visit) {
512   num_visits_ = num_visits;
513 }
514
515 void SSLBlockingPage::Observe(
516     int type,
517     const content::NotificationSource& source,
518     const content::NotificationDetails& details) {
519 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
520   // When detection is disabled, captive portal service always sends
521   // RESULT_INTERNET_CONNECTED. Ignore any probe results in that case.
522   if (!captive_portal_detection_enabled_)
523     return;
524   if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) {
525     captive_portal_probe_completed_ = true;
526     CaptivePortalService::Results* results =
527         content::Details<CaptivePortalService::Results>(
528             details).ptr();
529     // If a captive portal was detected at any point when the interstitial was
530     // displayed, assume that the interstitial was caused by a captive portal.
531     // Example scenario:
532     // 1- Interstitial displayed and captive portal detected, setting the flag.
533     // 2- Captive portal detection automatically opens portal login page.
534     // 3- User logs in on the portal login page.
535     // A notification will be received here for RESULT_INTERNET_CONNECTED. Make
536     // sure we don't clear the captive portal flag, since the interstitial was
537     // potentially caused by the captive portal.
538     captive_portal_detected_ = captive_portal_detected_ ||
539         (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
540     // Also keep track of non-HTTP portals and error cases.
541     captive_portal_no_response_ = captive_portal_no_response_ ||
542         (results->result == captive_portal::RESULT_NO_RESPONSE);
543   }
544 #endif
545 }