ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / ssl / ssl_blocking_page.cc
blob2dd3c51a9329e4807d4ce770a425e874c6988726
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/build_time.h"
8 #include "base/command_line.h"
9 #include "base/i18n/rtl.h"
10 #include "base/i18n/time_formatting.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/metrics/histogram.h"
13 #include "base/process/launch.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_piece.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/time/time.h"
20 #include "base/values.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/chrome_notification_types.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/renderer_preferences_util.h"
25 #include "chrome/browser/ssl/ssl_error_classification.h"
26 #include "chrome/browser/ssl/ssl_error_info.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/grit/chromium_strings.h"
29 #include "chrome/grit/generated_resources.h"
30 #include "components/google/core/browser/google_util.h"
31 #include "content/public/browser/cert_store.h"
32 #include "content/public/browser/interstitial_page.h"
33 #include "content/public/browser/navigation_controller.h"
34 #include "content/public/browser/navigation_entry.h"
35 #include "content/public/browser/notification_service.h"
36 #include "content/public/browser/notification_types.h"
37 #include "content/public/browser/render_process_host.h"
38 #include "content/public/browser/render_view_host.h"
39 #include "content/public/browser/web_contents.h"
40 #include "content/public/common/renderer_preferences.h"
41 #include "content/public/common/ssl_status.h"
42 #include "grit/browser_resources.h"
43 #include "net/base/hash_value.h"
44 #include "net/base/net_errors.h"
45 #include "net/base/net_util.h"
46 #include "ui/base/l10n/l10n_util.h"
48 #if defined(OS_WIN)
49 #include "base/base_paths_win.h"
50 #include "base/path_service.h"
51 #include "base/strings/string16.h"
52 #include "base/win/windows_version.h"
53 #endif
55 #if defined(OS_ANDROID)
56 #include "chrome/browser/android/intent_helper.h"
57 #endif
59 #if defined(OS_CHROMEOS)
60 #include "chrome/browser/profiles/profile_manager.h"
61 #include "chrome/browser/ui/chrome_pages.h"
62 #include "chrome/common/url_constants.h"
63 #endif
65 using base::ASCIIToUTF16;
66 using base::TimeTicks;
67 using content::InterstitialPage;
68 using content::NavigationController;
69 using content::NavigationEntry;
71 namespace {
73 // URL for help page.
74 const char kHelpURL[] = "https://support.google.com/chrome/answer/4454607";
76 // Constants for the Experience Sampling instrumentation.
77 const char kEventNameBase[] = "ssl_interstitial_";
78 const char kEventNotOverridable[] = "notoverridable_";
79 const char kEventOverridable[] = "overridable_";
81 // Events for UMA. Do not reorder or change!
82 enum SSLExpirationAndDecision {
83 EXPIRED_AND_PROCEED,
84 EXPIRED_AND_DO_NOT_PROCEED,
85 NOT_EXPIRED_AND_PROCEED,
86 NOT_EXPIRED_AND_DO_NOT_PROCEED,
87 END_OF_SSL_EXPIRATION_AND_DECISION,
90 // Rappor prefix
91 const char kSSLRapporPrefix[] = "ssl";
93 void RecordSSLExpirationPageEventState(bool expired_but_previously_allowed,
94 bool proceed,
95 bool overridable) {
96 SSLExpirationAndDecision event;
97 if (expired_but_previously_allowed && proceed)
98 event = EXPIRED_AND_PROCEED;
99 else if (expired_but_previously_allowed && !proceed)
100 event = EXPIRED_AND_DO_NOT_PROCEED;
101 else if (!expired_but_previously_allowed && proceed)
102 event = NOT_EXPIRED_AND_PROCEED;
103 else
104 event = NOT_EXPIRED_AND_DO_NOT_PROCEED;
106 if (overridable) {
107 UMA_HISTOGRAM_ENUMERATION(
108 "interstitial.ssl.expiration_and_decision.overridable",
109 event,
110 END_OF_SSL_EXPIRATION_AND_DECISION);
111 } else {
112 UMA_HISTOGRAM_ENUMERATION(
113 "interstitial.ssl.expiration_and_decision.nonoverridable",
114 event,
115 END_OF_SSL_EXPIRATION_AND_DECISION);
119 void LaunchDateAndTimeSettings() {
120 // The code for each OS is completely separate, in order to avoid bugs like
121 // https://crbug.com/430877 .
122 #if defined(OS_ANDROID)
123 chrome::android::OpenDateAndTimeSettings();
125 #elif defined(OS_CHROMEOS)
126 std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
127 l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME);
128 chrome::ShowSettingsSubPageForProfile(
129 ProfileManager::GetActiveUserProfile(), sub_page);
131 #elif defined(OS_IOS)
132 // iOS does not have a way to launch the date and time settings.
133 NOTREACHED();
135 #elif defined(OS_LINUX)
136 struct ClockCommand {
137 const char* pathname;
138 const char* argument;
140 static const ClockCommand kClockCommands[] = {
141 // Unity
142 { "/usr/bin/unity-control-center", "datetime" },
143 // GNOME
145 // NOTE: On old Ubuntu, naming control panels doesn't work, so it
146 // opens the overview. This will have to be good enough.
147 { "/usr/bin/gnome-control-center", "datetime" },
148 { "/usr/local/bin/gnome-control-center", "datetime" },
149 { "/opt/bin/gnome-control-center", "datetime" },
150 // KDE
151 { "/usr/bin/kcmshell4", "clock" },
152 { "/usr/local/bin/kcmshell4", "clock" },
153 { "/opt/bin/kcmshell4", "clock" },
156 base::CommandLine command(base::FilePath(""));
157 for (size_t i = 0; i < arraysize(kClockCommands); ++i) {
158 base::FilePath pathname(kClockCommands[i].pathname);
159 if (base::PathExists(pathname)) {
160 command.SetProgram(pathname);
161 command.AppendArg(kClockCommands[i].argument);
162 break;
165 if (command.GetProgram().empty()) {
166 // Alas, there is nothing we can do.
167 return;
170 base::LaunchOptions options;
171 options.wait = false;
172 options.allow_new_privs = true;
173 base::LaunchProcess(command, options);
175 #elif defined(OS_MACOSX)
176 base::CommandLine command(base::FilePath("/usr/bin/open"));
177 command.AppendArg("/System/Library/PreferencePanes/DateAndTime.prefPane");
179 base::LaunchOptions options;
180 options.wait = false;
181 base::LaunchProcess(command, options);
183 #elif defined(OS_WIN)
184 base::FilePath path;
185 PathService::Get(base::DIR_SYSTEM, &path);
186 static const base::char16 kControlPanelExe[] = L"control.exe";
187 path = path.Append(base::string16(kControlPanelExe));
188 base::CommandLine command(path);
189 command.AppendArg(std::string("/name"));
190 command.AppendArg(std::string("Microsoft.DateAndTime"));
192 base::LaunchOptions options;
193 options.wait = false;
194 base::LaunchProcess(command, options);
196 #else
197 NOTREACHED();
199 #endif
200 // Don't add code here! (See the comment at the beginning of the function.)
203 bool IsErrorDueToBadClock(const base::Time& now, int error) {
204 if (SSLErrorInfo::NetErrorToErrorType(error) !=
205 SSLErrorInfo::CERT_DATE_INVALID) {
206 return false;
208 return SSLErrorClassification::IsUserClockInThePast(now) ||
209 SSLErrorClassification::IsUserClockInTheFuture(now);
212 } // namespace
214 // static
215 const void* SSLBlockingPage::kTypeForTesting =
216 &SSLBlockingPage::kTypeForTesting;
218 // Note that we always create a navigation entry with SSL errors.
219 // No error happening loading a sub-resource triggers an interstitial so far.
220 SSLBlockingPage::SSLBlockingPage(content::WebContents* web_contents,
221 int cert_error,
222 const net::SSLInfo& ssl_info,
223 const GURL& request_url,
224 int options_mask,
225 const base::Time& time_triggered,
226 const base::Callback<void(bool)>& callback)
227 : SecurityInterstitialPage(web_contents, request_url),
228 callback_(callback),
229 cert_error_(cert_error),
230 ssl_info_(ssl_info),
231 overridable_(IsOptionsOverridable(options_mask)),
232 danger_overridable_(true),
233 strict_enforcement_((options_mask & STRICT_ENFORCEMENT) != 0),
234 expired_but_previously_allowed_(
235 (options_mask & EXPIRED_BUT_PREVIOUSLY_ALLOWED) != 0),
236 time_triggered_(time_triggered) {
237 interstitial_reason_ =
238 IsErrorDueToBadClock(time_triggered_, cert_error_) ?
239 SSL_REASON_BAD_CLOCK : SSL_REASON_SSL;
241 // We collapse the Rappor metric name to just "ssl" so we don't leak
242 // the "overridable" bit. We skip Rappor altogether for bad clocks.
243 // This must be done after calculating |interstitial_reason_| above.
244 metrics_helper_.reset(new SecurityInterstitialMetricsHelper(
245 web_contents, request_url, GetUmaHistogramPrefix(), kSSLRapporPrefix,
246 (interstitial_reason_ == SSL_REASON_BAD_CLOCK
247 ? SecurityInterstitialMetricsHelper::SKIP_RAPPOR
248 : SecurityInterstitialMetricsHelper::REPORT_RAPPOR),
249 GetSamplingEventName()));
251 metrics_helper_->RecordUserDecision(SecurityInterstitialMetricsHelper::SHOW);
252 metrics_helper_->RecordUserInteraction(
253 SecurityInterstitialMetricsHelper::TOTAL_VISITS);
255 ssl_error_classification_.reset(new SSLErrorClassification(
256 web_contents,
257 time_triggered_,
258 request_url,
259 cert_error_,
260 *ssl_info_.cert.get()));
261 ssl_error_classification_->RecordUMAStatistics(overridable_);
263 // Creating an interstitial without showing (e.g. from chrome://interstitials)
264 // it leaks memory, so don't create it here.
267 bool SSLBlockingPage::ShouldCreateNewNavigation() const {
268 return true;
271 const void* SSLBlockingPage::GetTypeForTesting() const {
272 return SSLBlockingPage::kTypeForTesting;
275 SSLBlockingPage::~SSLBlockingPage() {
276 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
277 // Captive portal detection results can arrive anytime during the interstitial
278 // is being displayed, so record it when the interstitial is going away.
279 ssl_error_classification_->RecordCaptivePortalUMAStatistics(overridable_);
280 #endif
281 if (!callback_.is_null()) {
282 // The page is closed without the user having chosen what to do, default to
283 // deny.
284 metrics_helper_->RecordUserDecision(
285 SecurityInterstitialMetricsHelper::DONT_PROCEED);
286 RecordSSLExpirationPageEventState(
287 expired_but_previously_allowed_, false, overridable_);
288 NotifyDenyCertificate();
292 void SSLBlockingPage::PopulateInterstitialStrings(
293 base::DictionaryValue* load_time_data) {
294 CHECK(load_time_data);
295 base::string16 url(GetFormattedHostName());
296 // Shared values for both the overridable and non-overridable versions.
297 load_time_data->SetString("type", "SSL");
299 // Shared UI configuration for all SSL interstitials.
300 load_time_data->SetString("errorCode", net::ErrorToString(cert_error_));
301 load_time_data->SetString(
302 "openDetails",
303 l10n_util::GetStringUTF16(IDS_SSL_V2_OPEN_DETAILS_BUTTON));
304 load_time_data->SetString(
305 "closeDetails",
306 l10n_util::GetStringUTF16(IDS_SSL_V2_CLOSE_DETAILS_BUTTON));
308 // Conditional UI configuration.
309 if (interstitial_reason_ == SSL_REASON_BAD_CLOCK) {
310 load_time_data->SetBoolean("bad_clock", true);
311 load_time_data->SetBoolean("overridable", false);
313 #if defined(OS_IOS)
314 load_time_data->SetBoolean("hide_primary_button", true);
315 #else
316 load_time_data->SetBoolean("hide_primary_button", false);
317 #endif
319 // We're showing the SSL clock warning to be helpful, but we haven't warned
320 // them about the risks. (And there might still be an SSL error after they
321 // fix their clock.) Thus, we don't allow the "danger" override in this
322 // case.
323 danger_overridable_ = false;
325 int heading_string =
326 SSLErrorClassification::IsUserClockInTheFuture(time_triggered_) ?
327 IDS_SSL_V2_CLOCK_AHEAD_HEADING :
328 IDS_SSL_V2_CLOCK_BEHIND_HEADING;
330 load_time_data->SetString(
331 "tabTitle",
332 l10n_util::GetStringUTF16(IDS_SSL_V2_CLOCK_TITLE));
333 load_time_data->SetString(
334 "heading",
335 l10n_util::GetStringUTF16(heading_string));
336 load_time_data->SetString(
337 "primaryParagraph",
338 l10n_util::GetStringFUTF16(
339 IDS_SSL_V2_CLOCK_PRIMARY_PARAGRAPH,
340 url,
341 base::TimeFormatFriendlyDateAndTime(time_triggered_)));
343 load_time_data->SetString(
344 "primaryButtonText",
345 l10n_util::GetStringUTF16(IDS_SSL_V2_CLOCK_UPDATE_DATE_AND_TIME));
346 load_time_data->SetString(
347 "explanationParagraph",
348 l10n_util::GetStringUTF16(IDS_SSL_V2_CLOCK_EXPLANATION));
350 // The interstitial template expects this string, but we're not using it. So
351 // we send a blank string for now.
352 load_time_data->SetString("finalParagraph", std::string());
353 } else {
354 load_time_data->SetBoolean("bad_clock", false);
356 load_time_data->SetString(
357 "tabTitle", l10n_util::GetStringUTF16(IDS_SSL_V2_TITLE));
358 load_time_data->SetString(
359 "heading", l10n_util::GetStringUTF16(IDS_SSL_V2_HEADING));
360 load_time_data->SetString(
361 "primaryParagraph",
362 l10n_util::GetStringFUTF16(IDS_SSL_V2_PRIMARY_PARAGRAPH, url));
364 if (overridable_) {
365 load_time_data->SetBoolean("overridable", true);
367 SSLErrorInfo error_info =
368 SSLErrorInfo::CreateError(
369 SSLErrorInfo::NetErrorToErrorType(cert_error_),
370 ssl_info_.cert.get(),
371 request_url());
372 load_time_data->SetString("explanationParagraph", error_info.details());
373 load_time_data->SetString(
374 "primaryButtonText",
375 l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_SAFETY_BUTTON));
376 load_time_data->SetString(
377 "finalParagraph",
378 l10n_util::GetStringFUTF16(IDS_SSL_OVERRIDABLE_PROCEED_PARAGRAPH,
379 url));
380 } else {
381 load_time_data->SetBoolean("overridable", false);
383 SSLErrorInfo::ErrorType type =
384 SSLErrorInfo::NetErrorToErrorType(cert_error_);
385 if (type == SSLErrorInfo::CERT_INVALID && SSLErrorClassification::
386 MaybeWindowsLacksSHA256Support()) {
387 load_time_data->SetString(
388 "explanationParagraph",
389 l10n_util::GetStringFUTF16(
390 IDS_SSL_NONOVERRIDABLE_MORE_INVALID_SP3, url));
391 } else {
392 load_time_data->SetString("explanationParagraph",
393 l10n_util::GetStringFUTF16(
394 IDS_SSL_NONOVERRIDABLE_MORE, url));
396 load_time_data->SetString(
397 "primaryButtonText",
398 l10n_util::GetStringUTF16(IDS_SSL_RELOAD));
399 // Customize the help link depending on the specific error type.
400 // Only mark as HSTS if none of the more specific error types apply,
401 // and use INVALID as a fallback if no other string is appropriate.
402 load_time_data->SetInteger("errorType", type);
403 int help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
404 switch (type) {
405 case SSLErrorInfo::CERT_REVOKED:
406 help_string = IDS_SSL_NONOVERRIDABLE_REVOKED;
407 break;
408 case SSLErrorInfo::CERT_PINNED_KEY_MISSING:
409 help_string = IDS_SSL_NONOVERRIDABLE_PINNED;
410 break;
411 case SSLErrorInfo::CERT_INVALID:
412 help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
413 break;
414 default:
415 if (strict_enforcement_)
416 help_string = IDS_SSL_NONOVERRIDABLE_HSTS;
418 load_time_data->SetString(
419 "finalParagraph", l10n_util::GetStringFUTF16(help_string, url));
423 // Set debugging information at the bottom of the warning.
424 load_time_data->SetString(
425 "subject", ssl_info_.cert->subject().GetDisplayName());
426 load_time_data->SetString(
427 "issuer", ssl_info_.cert->issuer().GetDisplayName());
428 load_time_data->SetString(
429 "expirationDate",
430 base::TimeFormatShortDate(ssl_info_.cert->valid_expiry()));
431 load_time_data->SetString(
432 "currentDate", base::TimeFormatShortDate(time_triggered_));
433 std::vector<std::string> encoded_chain;
434 ssl_info_.cert->GetPEMEncodedChain(
435 &encoded_chain);
436 load_time_data->SetString(
437 "pem", JoinString(encoded_chain, std::string()));
440 void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
441 int cert_id = content::CertStore::GetInstance()->StoreCert(
442 ssl_info_.cert.get(), web_contents()->GetRenderProcessHost()->GetID());
443 DCHECK(cert_id);
445 entry->GetSSL().security_style =
446 content::SECURITY_STYLE_AUTHENTICATION_BROKEN;
447 entry->GetSSL().cert_id = cert_id;
448 entry->GetSSL().cert_status = ssl_info_.cert_status;
449 entry->GetSSL().security_bits = ssl_info_.security_bits;
452 // This handles the commands sent from the interstitial JavaScript. They are
453 // defined in chrome/browser/resources/ssl/ssl_errors_common.js.
454 // DO NOT reorder or change this logic without also changing the JavaScript!
455 void SSLBlockingPage::CommandReceived(const std::string& command) {
456 int cmd = 0;
457 bool retval = base::StringToInt(command, &cmd);
458 DCHECK(retval);
459 switch (cmd) {
460 case CMD_DONT_PROCEED: {
461 interstitial_page()->DontProceed();
462 break;
464 case CMD_PROCEED: {
465 if (danger_overridable_) {
466 interstitial_page()->Proceed();
468 break;
470 case CMD_MORE: {
471 metrics_helper_->RecordUserInteraction(
472 SecurityInterstitialMetricsHelper::SHOW_ADVANCED);
473 break;
475 case CMD_RELOAD: {
476 metrics_helper_->RecordUserInteraction(
477 SecurityInterstitialMetricsHelper::RELOAD);
478 // The interstitial can't refresh itself.
479 web_contents()->GetController().Reload(true);
480 break;
482 case CMD_HELP: {
483 metrics_helper_->RecordUserInteraction(
484 SecurityInterstitialMetricsHelper::SHOW_LEARN_MORE);
485 content::NavigationController::LoadURLParams help_page_params(
486 google_util::AppendGoogleLocaleParam(
487 GURL(kHelpURL), g_browser_process->GetApplicationLocale()));
488 web_contents()->GetController().LoadURLWithParams(help_page_params);
489 break;
491 case CMD_CLOCK: {
492 metrics_helper_->RecordUserInteraction(
493 SecurityInterstitialMetricsHelper::OPEN_TIME_SETTINGS);
494 LaunchDateAndTimeSettings();
495 break;
497 default: {
498 NOTREACHED();
503 void SSLBlockingPage::OverrideRendererPrefs(
504 content::RendererPreferences* prefs) {
505 Profile* profile = Profile::FromBrowserContext(
506 web_contents()->GetBrowserContext());
507 renderer_preferences_util::UpdateFromSystemSettings(
508 prefs, profile, web_contents());
511 void SSLBlockingPage::OnProceed() {
512 metrics_helper_->RecordUserDecision(
513 SecurityInterstitialMetricsHelper::PROCEED);
514 RecordSSLExpirationPageEventState(
515 expired_but_previously_allowed_, true, overridable_);
516 // Accepting the certificate resumes the loading of the page.
517 NotifyAllowCertificate();
520 void SSLBlockingPage::OnDontProceed() {
521 metrics_helper_->RecordUserDecision(
522 SecurityInterstitialMetricsHelper::DONT_PROCEED);
523 RecordSSLExpirationPageEventState(
524 expired_but_previously_allowed_, false, overridable_);
525 NotifyDenyCertificate();
528 void SSLBlockingPage::NotifyDenyCertificate() {
529 // It's possible that callback_ may not exist if the user clicks "Proceed"
530 // followed by pressing the back button before the interstitial is hidden.
531 // In that case the certificate will still be treated as allowed.
532 if (callback_.is_null())
533 return;
535 callback_.Run(false);
536 callback_.Reset();
539 void SSLBlockingPage::NotifyAllowCertificate() {
540 DCHECK(!callback_.is_null());
542 callback_.Run(true);
543 callback_.Reset();
546 std::string SSLBlockingPage::GetUmaHistogramPrefix() const {
547 switch (interstitial_reason_) {
548 case SSL_REASON_SSL:
549 if (overridable_)
550 return "ssl_overridable";
551 else
552 return "ssl_nonoverridable";
553 case SSL_REASON_BAD_CLOCK:
554 return "bad_clock";
556 NOTREACHED();
557 return std::string();
560 std::string SSLBlockingPage::GetSamplingEventName() const {
561 std::string event_name(kEventNameBase);
562 if (overridable_)
563 event_name.append(kEventOverridable);
564 else
565 event_name.append(kEventNotOverridable);
566 event_name.append(net::ErrorToString(cert_error_));
567 return event_name;
570 // static
571 bool SSLBlockingPage::IsOptionsOverridable(int options_mask) {
572 return (options_mask & SSLBlockingPage::OVERRIDABLE) &&
573 !(options_mask & SSLBlockingPage::STRICT_ENFORCEMENT);