BookmarkManager: Fix 'new folder text field size changes on clicking it' issue.
[chromium-blink-merge.git] / chrome / browser / ssl / ssl_blocking_page.cc
blob21477857108b489e078f7c743730b123a42e246f
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/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback_helpers.h"
10 #include "base/i18n/rtl.h"
11 #include "base/i18n/time_formatting.h"
12 #include "base/metrics/histogram.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/rand_util.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_piece.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/time/time.h"
21 #include "base/values.h"
22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/chrome_notification_types.h"
24 #include "chrome/browser/interstitials/chrome_metrics_helper.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/browser/renderer_preferences_util.h"
27 #include "chrome/browser/ssl/cert_report_helper.h"
28 #include "chrome/browser/ssl/ssl_cert_reporter.h"
29 #include "chrome/browser/ssl/ssl_error_classification.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/pref_names.h"
32 #include "chrome/grit/chromium_strings.h"
33 #include "chrome/grit/generated_resources.h"
34 #include "components/google/core/browser/google_util.h"
35 #include "components/ssl_errors/error_info.h"
36 #include "content/public/browser/browser_thread.h"
37 #include "content/public/browser/cert_store.h"
38 #include "content/public/browser/interstitial_page.h"
39 #include "content/public/browser/interstitial_page_delegate.h"
40 #include "content/public/browser/navigation_controller.h"
41 #include "content/public/browser/navigation_entry.h"
42 #include "content/public/browser/notification_service.h"
43 #include "content/public/browser/notification_types.h"
44 #include "content/public/browser/render_process_host.h"
45 #include "content/public/browser/render_view_host.h"
46 #include "content/public/browser/signed_certificate_timestamp_store.h"
47 #include "content/public/browser/web_contents.h"
48 #include "content/public/common/renderer_preferences.h"
49 #include "content/public/common/ssl_status.h"
50 #include "grit/browser_resources.h"
51 #include "grit/components_strings.h"
52 #include "net/base/hash_value.h"
53 #include "net/base/net_errors.h"
54 #include "net/base/net_util.h"
55 #include "ui/base/l10n/l10n_util.h"
57 using base::ASCIIToUTF16;
58 using base::TimeTicks;
59 using content::InterstitialPage;
60 using content::InterstitialPageDelegate;
61 using content::NavigationController;
62 using content::NavigationEntry;
64 namespace {
66 // URL for help page.
67 const char kHelpURL[] = "https://support.google.com/chrome/answer/4454607";
69 // Constants for the Experience Sampling instrumentation.
70 const char kEventNameBase[] = "ssl_interstitial_";
71 const char kEventNotOverridable[] = "notoverridable_";
72 const char kEventOverridable[] = "overridable_";
74 // Events for UMA. Do not reorder or change!
75 enum SSLExpirationAndDecision {
76 EXPIRED_AND_PROCEED,
77 EXPIRED_AND_DO_NOT_PROCEED,
78 NOT_EXPIRED_AND_PROCEED,
79 NOT_EXPIRED_AND_DO_NOT_PROCEED,
80 END_OF_SSL_EXPIRATION_AND_DECISION,
83 // Rappor prefix, which is used for both overridable and non-overridable
84 // interstitials so we don't leak the "overridable" bit.
85 const char kSSLRapporPrefix[] = "ssl2";
87 void RecordSSLExpirationPageEventState(bool expired_but_previously_allowed,
88 bool proceed,
89 bool overridable) {
90 SSLExpirationAndDecision event;
91 if (expired_but_previously_allowed && proceed)
92 event = EXPIRED_AND_PROCEED;
93 else if (expired_but_previously_allowed && !proceed)
94 event = EXPIRED_AND_DO_NOT_PROCEED;
95 else if (!expired_but_previously_allowed && proceed)
96 event = NOT_EXPIRED_AND_PROCEED;
97 else
98 event = NOT_EXPIRED_AND_DO_NOT_PROCEED;
100 if (overridable) {
101 UMA_HISTOGRAM_ENUMERATION(
102 "interstitial.ssl.expiration_and_decision.overridable",
103 event,
104 END_OF_SSL_EXPIRATION_AND_DECISION);
105 } else {
106 UMA_HISTOGRAM_ENUMERATION(
107 "interstitial.ssl.expiration_and_decision.nonoverridable",
108 event,
109 END_OF_SSL_EXPIRATION_AND_DECISION);
113 } // namespace
115 // static
116 InterstitialPageDelegate::TypeID SSLBlockingPage::kTypeForTesting =
117 &SSLBlockingPage::kTypeForTesting;
119 // Note that we always create a navigation entry with SSL errors.
120 // No error happening loading a sub-resource triggers an interstitial so far.
121 SSLBlockingPage::SSLBlockingPage(content::WebContents* web_contents,
122 int cert_error,
123 const net::SSLInfo& ssl_info,
124 const GURL& request_url,
125 int options_mask,
126 const base::Time& time_triggered,
127 scoped_ptr<SSLCertReporter> ssl_cert_reporter,
128 const base::Callback<void(bool)>& callback)
129 : SecurityInterstitialPage(web_contents, request_url),
130 callback_(callback),
131 cert_error_(cert_error),
132 ssl_info_(ssl_info),
133 overridable_(IsOverridable(
134 options_mask,
135 Profile::FromBrowserContext(web_contents->GetBrowserContext()))),
136 danger_overridable_(DoesPolicyAllowDangerOverride(
137 Profile::FromBrowserContext(web_contents->GetBrowserContext()))),
138 strict_enforcement_((options_mask & STRICT_ENFORCEMENT) != 0),
139 expired_but_previously_allowed_(
140 (options_mask & EXPIRED_BUT_PREVIOUSLY_ALLOWED) != 0),
141 time_triggered_(time_triggered) {
142 security_interstitials::MetricsHelper::ReportDetails reporting_info;
143 reporting_info.metric_prefix = GetUmaHistogramPrefix();
144 reporting_info.rappor_prefix = kSSLRapporPrefix;
145 reporting_info.rappor_report_type = rappor::UMA_RAPPOR_TYPE;
146 set_metrics_helper(new ChromeMetricsHelper(
147 web_contents, request_url, reporting_info, GetSamplingEventName()));
148 metrics_helper()->RecordUserDecision(
149 security_interstitials::MetricsHelper::SHOW);
150 metrics_helper()->RecordUserInteraction(
151 security_interstitials::MetricsHelper::TOTAL_VISITS);
153 cert_report_helper_.reset(new CertReportHelper(
154 ssl_cert_reporter.Pass(), web_contents, request_url, ssl_info,
155 certificate_reporting::ErrorReport::INTERSTITIAL_SSL, overridable_,
156 metrics_helper()));
158 ssl_error_classification_.reset(new SSLErrorClassification(
159 web_contents,
160 time_triggered_,
161 request_url,
162 cert_error_,
163 *ssl_info_.cert.get()));
164 ssl_error_classification_->RecordUMAStatistics(overridable_);
166 // Creating an interstitial without showing (e.g. from chrome://interstitials)
167 // it leaks memory, so don't create it here.
170 bool SSLBlockingPage::ShouldCreateNewNavigation() const {
171 return true;
174 InterstitialPageDelegate::TypeID SSLBlockingPage::GetTypeForTesting() const {
175 return SSLBlockingPage::kTypeForTesting;
178 SSLBlockingPage::~SSLBlockingPage() {
179 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
180 // Captive portal detection results can arrive anytime during the interstitial
181 // is being displayed, so record it when the interstitial is going away.
182 ssl_error_classification_->RecordCaptivePortalUMAStatistics(overridable_);
183 #endif
184 if (!callback_.is_null()) {
185 // The page is closed without the user having chosen what to do, default to
186 // deny.
187 metrics_helper()->RecordUserDecision(
188 security_interstitials::MetricsHelper::DONT_PROCEED);
189 RecordSSLExpirationPageEventState(
190 expired_but_previously_allowed_, false, overridable_);
191 NotifyDenyCertificate();
195 void SSLBlockingPage::PopulateInterstitialStrings(
196 base::DictionaryValue* load_time_data) {
197 CHECK(load_time_data);
198 base::string16 url(GetFormattedHostName());
199 // Shared values for both the overridable and non-overridable versions.
200 load_time_data->SetString("type", "SSL");
201 load_time_data->SetBoolean("bad_clock", false);
203 // Shared UI configuration for all SSL interstitials.
204 load_time_data->SetString("errorCode", net::ErrorToString(cert_error_));
205 load_time_data->SetString(
206 "openDetails",
207 l10n_util::GetStringUTF16(IDS_SSL_OPEN_DETAILS_BUTTON));
208 load_time_data->SetString(
209 "closeDetails",
210 l10n_util::GetStringUTF16(IDS_SSL_CLOSE_DETAILS_BUTTON));
212 load_time_data->SetString("tabTitle",
213 l10n_util::GetStringUTF16(IDS_SSL_V2_TITLE));
214 load_time_data->SetString("heading",
215 l10n_util::GetStringUTF16(IDS_SSL_V2_HEADING));
216 load_time_data->SetString(
217 "primaryParagraph",
218 l10n_util::GetStringFUTF16(IDS_SSL_V2_PRIMARY_PARAGRAPH, url));
220 if (overridable_) {
221 load_time_data->SetBoolean("overridable", true);
223 ssl_errors::ErrorInfo error_info = ssl_errors::ErrorInfo::CreateError(
224 ssl_errors::ErrorInfo::NetErrorToErrorType(cert_error_),
225 ssl_info_.cert.get(), request_url());
226 load_time_data->SetString("explanationParagraph", error_info.details());
227 load_time_data->SetString(
228 "primaryButtonText",
229 l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_SAFETY_BUTTON));
230 load_time_data->SetString(
231 "finalParagraph",
232 l10n_util::GetStringFUTF16(IDS_SSL_OVERRIDABLE_PROCEED_PARAGRAPH, url));
233 } else {
234 load_time_data->SetBoolean("overridable", false);
236 ssl_errors::ErrorInfo::ErrorType type =
237 ssl_errors::ErrorInfo::NetErrorToErrorType(cert_error_);
238 if (type == ssl_errors::ErrorInfo::CERT_INVALID &&
239 SSLErrorClassification::MaybeWindowsLacksSHA256Support()) {
240 load_time_data->SetString(
241 "explanationParagraph",
242 l10n_util::GetStringFUTF16(IDS_SSL_NONOVERRIDABLE_MORE_INVALID_SP3,
243 url));
244 } else {
245 load_time_data->SetString(
246 "explanationParagraph",
247 l10n_util::GetStringFUTF16(IDS_SSL_NONOVERRIDABLE_MORE, url));
249 load_time_data->SetString("primaryButtonText",
250 l10n_util::GetStringUTF16(IDS_SSL_RELOAD));
251 // Customize the help link depending on the specific error type.
252 // Only mark as HSTS if none of the more specific error types apply,
253 // and use INVALID as a fallback if no other string is appropriate.
254 load_time_data->SetInteger("errorType", type);
255 int help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
256 switch (type) {
257 case ssl_errors::ErrorInfo::CERT_REVOKED:
258 help_string = IDS_SSL_NONOVERRIDABLE_REVOKED;
259 break;
260 case ssl_errors::ErrorInfo::CERT_PINNED_KEY_MISSING:
261 help_string = IDS_SSL_NONOVERRIDABLE_PINNED;
262 break;
263 case ssl_errors::ErrorInfo::CERT_INVALID:
264 help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
265 break;
266 default:
267 if (strict_enforcement_)
268 help_string = IDS_SSL_NONOVERRIDABLE_HSTS;
270 load_time_data->SetString("finalParagraph",
271 l10n_util::GetStringFUTF16(help_string, url));
274 // Set debugging information at the bottom of the warning.
275 load_time_data->SetString(
276 "subject", ssl_info_.cert->subject().GetDisplayName());
277 load_time_data->SetString(
278 "issuer", ssl_info_.cert->issuer().GetDisplayName());
279 load_time_data->SetString(
280 "expirationDate",
281 base::TimeFormatShortDate(ssl_info_.cert->valid_expiry()));
282 load_time_data->SetString(
283 "currentDate", base::TimeFormatShortDate(time_triggered_));
284 std::vector<std::string> encoded_chain;
285 ssl_info_.cert->GetPEMEncodedChain(
286 &encoded_chain);
287 load_time_data->SetString(
288 "pem", base::JoinString(encoded_chain, base::StringPiece()));
290 cert_report_helper_->PopulateExtendedReportingOption(load_time_data);
293 void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
294 const int process_id = web_contents()->GetRenderProcessHost()->GetID();
295 const int cert_id = content::CertStore::GetInstance()->StoreCert(
296 ssl_info_.cert.get(), process_id);
297 DCHECK(cert_id);
299 content::SignedCertificateTimestampStore* sct_store(
300 content::SignedCertificateTimestampStore::GetInstance());
301 content::SignedCertificateTimestampIDStatusList sct_ids;
302 for (const auto& sct_and_status : ssl_info_.signed_certificate_timestamps) {
303 const int sct_id(sct_store->Store(sct_and_status.sct.get(), process_id));
304 DCHECK(sct_id);
305 sct_ids.push_back(content::SignedCertificateTimestampIDAndStatus(
306 sct_id, sct_and_status.status));
309 entry->GetSSL() =
310 content::SSLStatus(content::SECURITY_STYLE_AUTHENTICATION_BROKEN, cert_id,
311 sct_ids, ssl_info_);
314 void SSLBlockingPage::SetSSLCertReporterForTesting(
315 scoped_ptr<SSLCertReporter> ssl_cert_reporter) {
316 cert_report_helper_->SetSSLCertReporterForTesting(ssl_cert_reporter.Pass());
319 // This handles the commands sent from the interstitial JavaScript.
320 // DO NOT reorder or change this logic without also changing the JavaScript!
321 void SSLBlockingPage::CommandReceived(const std::string& command) {
322 if (command == "\"pageLoadComplete\"") {
323 // content::WaitForRenderFrameReady sends this message when the page
324 // load completes. Ignore it.
325 return;
328 int cmd = 0;
329 bool retval = base::StringToInt(command, &cmd);
330 DCHECK(retval);
331 switch (cmd) {
332 case CMD_DONT_PROCEED: {
333 interstitial_page()->DontProceed();
334 break;
336 case CMD_PROCEED: {
337 if (danger_overridable_) {
338 interstitial_page()->Proceed();
340 break;
342 case CMD_DO_REPORT: {
343 SetReportingPreference(true);
344 break;
346 case CMD_DONT_REPORT: {
347 SetReportingPreference(false);
348 break;
350 case CMD_SHOW_MORE_SECTION: {
351 metrics_helper()->RecordUserInteraction(
352 security_interstitials::MetricsHelper::SHOW_ADVANCED);
353 break;
355 case CMD_OPEN_HELP_CENTER: {
356 metrics_helper()->RecordUserInteraction(
357 security_interstitials::MetricsHelper::SHOW_LEARN_MORE);
358 content::NavigationController::LoadURLParams help_page_params(
359 google_util::AppendGoogleLocaleParam(
360 GURL(kHelpURL), g_browser_process->GetApplicationLocale()));
361 web_contents()->GetController().LoadURLWithParams(help_page_params);
362 break;
364 case CMD_RELOAD: {
365 metrics_helper()->RecordUserInteraction(
366 security_interstitials::MetricsHelper::RELOAD);
367 // The interstitial can't refresh itself.
368 web_contents()->GetController().Reload(true);
369 break;
371 case CMD_OPEN_REPORTING_PRIVACY:
372 OpenExtendedReportingPrivacyPolicy();
373 break;
374 case CMD_OPEN_DATE_SETTINGS:
375 case CMD_OPEN_DIAGNOSTIC:
376 // Commands not supported by the SSL interstitial.
377 NOTREACHED() << "Unexpected command: " << command;
381 void SSLBlockingPage::OverrideRendererPrefs(
382 content::RendererPreferences* prefs) {
383 Profile* profile = Profile::FromBrowserContext(
384 web_contents()->GetBrowserContext());
385 renderer_preferences_util::UpdateFromSystemSettings(
386 prefs, profile, web_contents());
389 void SSLBlockingPage::OnProceed() {
390 metrics_helper()->RecordUserDecision(
391 security_interstitials::MetricsHelper::PROCEED);
393 // Finish collecting information about invalid certificates, if the
394 // user opted in to.
395 cert_report_helper_->FinishCertCollection(
396 certificate_reporting::ErrorReport::USER_PROCEEDED);
398 RecordSSLExpirationPageEventState(
399 expired_but_previously_allowed_, true, overridable_);
400 // Accepting the certificate resumes the loading of the page.
401 NotifyAllowCertificate();
404 void SSLBlockingPage::OnDontProceed() {
405 metrics_helper()->RecordUserDecision(
406 security_interstitials::MetricsHelper::DONT_PROCEED);
408 // Finish collecting information about invalid certificates, if the
409 // user opted in to.
410 cert_report_helper_->FinishCertCollection(
411 certificate_reporting::ErrorReport::USER_DID_NOT_PROCEED);
413 RecordSSLExpirationPageEventState(
414 expired_but_previously_allowed_, false, overridable_);
415 NotifyDenyCertificate();
418 void SSLBlockingPage::NotifyDenyCertificate() {
419 // It's possible that callback_ may not exist if the user clicks "Proceed"
420 // followed by pressing the back button before the interstitial is hidden.
421 // In that case the certificate will still be treated as allowed.
422 if (callback_.is_null())
423 return;
425 callback_.Run(false);
426 callback_.Reset();
429 void SSLBlockingPage::NotifyAllowCertificate() {
430 DCHECK(!callback_.is_null());
432 callback_.Run(true);
433 callback_.Reset();
436 std::string SSLBlockingPage::GetUmaHistogramPrefix() const {
437 return overridable_ ? "ssl_overridable" : "ssl_nonoverridable";
440 std::string SSLBlockingPage::GetSamplingEventName() const {
441 std::string event_name(kEventNameBase);
442 if (overridable_)
443 event_name.append(kEventOverridable);
444 else
445 event_name.append(kEventNotOverridable);
446 event_name.append(net::ErrorToString(cert_error_));
447 return event_name;
450 // static
451 bool SSLBlockingPage::IsOverridable(int options_mask,
452 const Profile* const profile) {
453 const bool is_overridable =
454 (options_mask & SSLBlockingPage::OVERRIDABLE) &&
455 !(options_mask & SSLBlockingPage::STRICT_ENFORCEMENT) &&
456 profile->GetPrefs()->GetBoolean(prefs::kSSLErrorOverrideAllowed);
457 return is_overridable;
460 // static
461 bool SSLBlockingPage::DoesPolicyAllowDangerOverride(
462 const Profile* const profile) {
463 return profile->GetPrefs()->GetBoolean(prefs::kSSLErrorOverrideAllowed);