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"
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
;
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
{
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
,
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
;
98 event
= NOT_EXPIRED_AND_DO_NOT_PROCEED
;
101 UMA_HISTOGRAM_ENUMERATION(
102 "interstitial.ssl.expiration_and_decision.overridable",
104 END_OF_SSL_EXPIRATION_AND_DECISION
);
106 UMA_HISTOGRAM_ENUMERATION(
107 "interstitial.ssl.expiration_and_decision.nonoverridable",
109 END_OF_SSL_EXPIRATION_AND_DECISION
);
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
,
123 const net::SSLInfo
& ssl_info
,
124 const GURL
& request_url
,
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
),
131 cert_error_(cert_error
),
133 overridable_(IsOverridable(
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_
,
158 ssl_error_classification_
.reset(new SSLErrorClassification(
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 {
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_
);
184 if (!callback_
.is_null()) {
185 // The page is closed without the user having chosen what to do, default to
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(
207 l10n_util::GetStringUTF16(IDS_SSL_OPEN_DETAILS_BUTTON
));
208 load_time_data
->SetString(
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(
218 l10n_util::GetStringFUTF16(IDS_SSL_V2_PRIMARY_PARAGRAPH
, url
));
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(
229 l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_SAFETY_BUTTON
));
230 load_time_data
->SetString(
232 l10n_util::GetStringFUTF16(IDS_SSL_OVERRIDABLE_PROCEED_PARAGRAPH
, url
));
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
,
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
;
257 case ssl_errors::ErrorInfo::CERT_REVOKED
:
258 help_string
= IDS_SSL_NONOVERRIDABLE_REVOKED
;
260 case ssl_errors::ErrorInfo::CERT_PINNED_KEY_MISSING
:
261 help_string
= IDS_SSL_NONOVERRIDABLE_PINNED
;
263 case ssl_errors::ErrorInfo::CERT_INVALID
:
264 help_string
= IDS_SSL_NONOVERRIDABLE_INVALID
;
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(
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(
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
);
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
));
305 sct_ids
.push_back(content::SignedCertificateTimestampIDAndStatus(
306 sct_id
, sct_and_status
.status
));
310 content::SSLStatus(content::SECURITY_STYLE_AUTHENTICATION_BROKEN
, cert_id
,
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.
329 bool retval
= base::StringToInt(command
, &cmd
);
332 case CMD_DONT_PROCEED
: {
333 interstitial_page()->DontProceed();
337 if (danger_overridable_
) {
338 interstitial_page()->Proceed();
342 case CMD_DO_REPORT
: {
343 SetReportingPreference(true);
346 case CMD_DONT_REPORT
: {
347 SetReportingPreference(false);
350 case CMD_SHOW_MORE_SECTION
: {
351 metrics_helper()->RecordUserInteraction(
352 security_interstitials::MetricsHelper::SHOW_ADVANCED
);
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
);
365 metrics_helper()->RecordUserInteraction(
366 security_interstitials::MetricsHelper::RELOAD
);
367 // The interstitial can't refresh itself.
368 web_contents()->GetController().Reload(true);
371 case CMD_OPEN_REPORTING_PRIVACY
:
372 OpenExtendedReportingPrivacyPolicy();
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
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
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())
425 callback_
.Run(false);
429 void SSLBlockingPage::NotifyAllowCertificate() {
430 DCHECK(!callback_
.is_null());
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
);
443 event_name
.append(kEventOverridable
);
445 event_name
.append(kEventNotOverridable
);
446 event_name
.append(net::ErrorToString(cert_error_
));
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
;
461 bool SSLBlockingPage::DoesPolicyAllowDangerOverride(
462 const Profile
* const profile
) {
463 return profile
->GetPrefs()->GetBoolean(prefs::kSSLErrorOverrideAllowed
);