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/browser/ssl/ssl_error_info.h"
31 #include "chrome/common/chrome_switches.h"
32 #include "chrome/common/pref_names.h"
33 #include "chrome/grit/chromium_strings.h"
34 #include "chrome/grit/generated_resources.h"
35 #include "components/google/core/browser/google_util.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/web_contents.h"
47 #include "content/public/common/renderer_preferences.h"
48 #include "content/public/common/ssl_status.h"
49 #include "grit/browser_resources.h"
50 #include "grit/components_strings.h"
51 #include "net/base/hash_value.h"
52 #include "net/base/net_errors.h"
53 #include "net/base/net_util.h"
54 #include "ui/base/l10n/l10n_util.h"
56 using base::ASCIIToUTF16
;
57 using base::TimeTicks
;
58 using content::InterstitialPage
;
59 using content::InterstitialPageDelegate
;
60 using content::NavigationController
;
61 using content::NavigationEntry
;
66 const char kHelpURL
[] = "https://support.google.com/chrome/answer/4454607";
68 // Constants for the Experience Sampling instrumentation.
69 const char kEventNameBase
[] = "ssl_interstitial_";
70 const char kEventNotOverridable
[] = "notoverridable_";
71 const char kEventOverridable
[] = "overridable_";
73 // Events for UMA. Do not reorder or change!
74 enum SSLExpirationAndDecision
{
76 EXPIRED_AND_DO_NOT_PROCEED
,
77 NOT_EXPIRED_AND_PROCEED
,
78 NOT_EXPIRED_AND_DO_NOT_PROCEED
,
79 END_OF_SSL_EXPIRATION_AND_DECISION
,
82 // Rappor prefix, which is used for both overridable and non-overridable
83 // interstitials so we don't leak the "overridable" bit.
84 const char kSSLRapporPrefix
[] = "ssl2";
86 void RecordSSLExpirationPageEventState(bool expired_but_previously_allowed
,
89 SSLExpirationAndDecision event
;
90 if (expired_but_previously_allowed
&& proceed
)
91 event
= EXPIRED_AND_PROCEED
;
92 else if (expired_but_previously_allowed
&& !proceed
)
93 event
= EXPIRED_AND_DO_NOT_PROCEED
;
94 else if (!expired_but_previously_allowed
&& proceed
)
95 event
= NOT_EXPIRED_AND_PROCEED
;
97 event
= NOT_EXPIRED_AND_DO_NOT_PROCEED
;
100 UMA_HISTOGRAM_ENUMERATION(
101 "interstitial.ssl.expiration_and_decision.overridable",
103 END_OF_SSL_EXPIRATION_AND_DECISION
);
105 UMA_HISTOGRAM_ENUMERATION(
106 "interstitial.ssl.expiration_and_decision.nonoverridable",
108 END_OF_SSL_EXPIRATION_AND_DECISION
);
115 InterstitialPageDelegate::TypeID
SSLBlockingPage::kTypeForTesting
=
116 &SSLBlockingPage::kTypeForTesting
;
118 // Note that we always create a navigation entry with SSL errors.
119 // No error happening loading a sub-resource triggers an interstitial so far.
120 SSLBlockingPage::SSLBlockingPage(content::WebContents
* web_contents
,
122 const net::SSLInfo
& ssl_info
,
123 const GURL
& request_url
,
125 const base::Time
& time_triggered
,
126 scoped_ptr
<SSLCertReporter
> ssl_cert_reporter
,
127 const base::Callback
<void(bool)>& callback
)
128 : SecurityInterstitialPage(web_contents
, request_url
),
130 cert_error_(cert_error
),
132 overridable_(IsOverridable(
134 Profile::FromBrowserContext(web_contents
->GetBrowserContext()))),
135 danger_overridable_(DoesPolicyAllowDangerOverride(
136 Profile::FromBrowserContext(web_contents
->GetBrowserContext()))),
137 strict_enforcement_((options_mask
& STRICT_ENFORCEMENT
) != 0),
138 expired_but_previously_allowed_(
139 (options_mask
& EXPIRED_BUT_PREVIOUSLY_ALLOWED
) != 0),
140 time_triggered_(time_triggered
) {
141 security_interstitials::MetricsHelper::ReportDetails reporting_info
;
142 reporting_info
.metric_prefix
= GetUmaHistogramPrefix();
143 reporting_info
.rappor_prefix
= kSSLRapporPrefix
;
144 reporting_info
.rappor_report_type
= rappor::UMA_RAPPOR_TYPE
;
145 set_metrics_helper(new ChromeMetricsHelper(
146 web_contents
, request_url
, reporting_info
, GetSamplingEventName()));
147 metrics_helper()->RecordUserDecision(
148 security_interstitials::MetricsHelper::SHOW
);
149 metrics_helper()->RecordUserInteraction(
150 security_interstitials::MetricsHelper::TOTAL_VISITS
);
152 cert_report_helper_
.reset(new CertReportHelper(
153 ssl_cert_reporter
.Pass(), web_contents
, request_url
, ssl_info
,
154 certificate_reporting::ErrorReport::INTERSTITIAL_SSL
, overridable_
,
157 ssl_error_classification_
.reset(new SSLErrorClassification(
162 *ssl_info_
.cert
.get()));
163 ssl_error_classification_
->RecordUMAStatistics(overridable_
);
165 // Creating an interstitial without showing (e.g. from chrome://interstitials)
166 // it leaks memory, so don't create it here.
169 bool SSLBlockingPage::ShouldCreateNewNavigation() const {
173 InterstitialPageDelegate::TypeID
SSLBlockingPage::GetTypeForTesting() const {
174 return SSLBlockingPage::kTypeForTesting
;
177 SSLBlockingPage::~SSLBlockingPage() {
178 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
179 // Captive portal detection results can arrive anytime during the interstitial
180 // is being displayed, so record it when the interstitial is going away.
181 ssl_error_classification_
->RecordCaptivePortalUMAStatistics(overridable_
);
183 if (!callback_
.is_null()) {
184 // The page is closed without the user having chosen what to do, default to
186 metrics_helper()->RecordUserDecision(
187 security_interstitials::MetricsHelper::DONT_PROCEED
);
188 RecordSSLExpirationPageEventState(
189 expired_but_previously_allowed_
, false, overridable_
);
190 NotifyDenyCertificate();
194 void SSLBlockingPage::PopulateInterstitialStrings(
195 base::DictionaryValue
* load_time_data
) {
196 CHECK(load_time_data
);
197 base::string16
url(GetFormattedHostName());
198 // Shared values for both the overridable and non-overridable versions.
199 load_time_data
->SetString("type", "SSL");
200 load_time_data
->SetBoolean("bad_clock", false);
202 // Shared UI configuration for all SSL interstitials.
203 load_time_data
->SetString("errorCode", net::ErrorToString(cert_error_
));
204 load_time_data
->SetString(
206 l10n_util::GetStringUTF16(IDS_SSL_OPEN_DETAILS_BUTTON
));
207 load_time_data
->SetString(
209 l10n_util::GetStringUTF16(IDS_SSL_CLOSE_DETAILS_BUTTON
));
211 load_time_data
->SetString("tabTitle",
212 l10n_util::GetStringUTF16(IDS_SSL_V2_TITLE
));
213 load_time_data
->SetString("heading",
214 l10n_util::GetStringUTF16(IDS_SSL_V2_HEADING
));
215 load_time_data
->SetString(
217 l10n_util::GetStringFUTF16(IDS_SSL_V2_PRIMARY_PARAGRAPH
, url
));
220 load_time_data
->SetBoolean("overridable", true);
222 SSLErrorInfo error_info
= SSLErrorInfo::CreateError(
223 SSLErrorInfo::NetErrorToErrorType(cert_error_
), ssl_info_
.cert
.get(),
225 load_time_data
->SetString("explanationParagraph", error_info
.details());
226 load_time_data
->SetString(
228 l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_SAFETY_BUTTON
));
229 load_time_data
->SetString(
231 l10n_util::GetStringFUTF16(IDS_SSL_OVERRIDABLE_PROCEED_PARAGRAPH
, url
));
233 load_time_data
->SetBoolean("overridable", false);
235 SSLErrorInfo::ErrorType type
=
236 SSLErrorInfo::NetErrorToErrorType(cert_error_
);
237 if (type
== SSLErrorInfo::CERT_INVALID
&&
238 SSLErrorClassification::MaybeWindowsLacksSHA256Support()) {
239 load_time_data
->SetString(
240 "explanationParagraph",
241 l10n_util::GetStringFUTF16(IDS_SSL_NONOVERRIDABLE_MORE_INVALID_SP3
,
244 load_time_data
->SetString(
245 "explanationParagraph",
246 l10n_util::GetStringFUTF16(IDS_SSL_NONOVERRIDABLE_MORE
, url
));
248 load_time_data
->SetString("primaryButtonText",
249 l10n_util::GetStringUTF16(IDS_SSL_RELOAD
));
250 // Customize the help link depending on the specific error type.
251 // Only mark as HSTS if none of the more specific error types apply,
252 // and use INVALID as a fallback if no other string is appropriate.
253 load_time_data
->SetInteger("errorType", type
);
254 int help_string
= IDS_SSL_NONOVERRIDABLE_INVALID
;
256 case SSLErrorInfo::CERT_REVOKED
:
257 help_string
= IDS_SSL_NONOVERRIDABLE_REVOKED
;
259 case SSLErrorInfo::CERT_PINNED_KEY_MISSING
:
260 help_string
= IDS_SSL_NONOVERRIDABLE_PINNED
;
262 case SSLErrorInfo::CERT_INVALID
:
263 help_string
= IDS_SSL_NONOVERRIDABLE_INVALID
;
266 if (strict_enforcement_
)
267 help_string
= IDS_SSL_NONOVERRIDABLE_HSTS
;
269 load_time_data
->SetString("finalParagraph",
270 l10n_util::GetStringFUTF16(help_string
, url
));
273 // Set debugging information at the bottom of the warning.
274 load_time_data
->SetString(
275 "subject", ssl_info_
.cert
->subject().GetDisplayName());
276 load_time_data
->SetString(
277 "issuer", ssl_info_
.cert
->issuer().GetDisplayName());
278 load_time_data
->SetString(
280 base::TimeFormatShortDate(ssl_info_
.cert
->valid_expiry()));
281 load_time_data
->SetString(
282 "currentDate", base::TimeFormatShortDate(time_triggered_
));
283 std::vector
<std::string
> encoded_chain
;
284 ssl_info_
.cert
->GetPEMEncodedChain(
286 load_time_data
->SetString(
287 "pem", base::JoinString(encoded_chain
, base::StringPiece()));
289 cert_report_helper_
->PopulateExtendedReportingOption(load_time_data
);
292 void SSLBlockingPage::OverrideEntry(NavigationEntry
* entry
) {
293 int cert_id
= content::CertStore::GetInstance()->StoreCert(
294 ssl_info_
.cert
.get(), web_contents()->GetRenderProcessHost()->GetID());
297 entry
->GetSSL().security_style
=
298 content::SECURITY_STYLE_AUTHENTICATION_BROKEN
;
299 entry
->GetSSL().cert_id
= cert_id
;
300 entry
->GetSSL().cert_status
= ssl_info_
.cert_status
;
301 entry
->GetSSL().security_bits
= ssl_info_
.security_bits
;
304 void SSLBlockingPage::SetSSLCertReporterForTesting(
305 scoped_ptr
<SSLCertReporter
> ssl_cert_reporter
) {
306 cert_report_helper_
->SetSSLCertReporterForTesting(ssl_cert_reporter
.Pass());
309 // This handles the commands sent from the interstitial JavaScript.
310 // DO NOT reorder or change this logic without also changing the JavaScript!
311 void SSLBlockingPage::CommandReceived(const std::string
& command
) {
312 if (command
== "\"pageLoadComplete\"") {
313 // content::WaitForRenderFrameReady sends this message when the page
314 // load completes. Ignore it.
319 bool retval
= base::StringToInt(command
, &cmd
);
322 case CMD_DONT_PROCEED
: {
323 interstitial_page()->DontProceed();
327 if (danger_overridable_
) {
328 interstitial_page()->Proceed();
332 case CMD_DO_REPORT
: {
333 SetReportingPreference(true);
336 case CMD_DONT_REPORT
: {
337 SetReportingPreference(false);
340 case CMD_SHOW_MORE_SECTION
: {
341 metrics_helper()->RecordUserInteraction(
342 security_interstitials::MetricsHelper::SHOW_ADVANCED
);
345 case CMD_OPEN_HELP_CENTER
: {
346 metrics_helper()->RecordUserInteraction(
347 security_interstitials::MetricsHelper::SHOW_LEARN_MORE
);
348 content::NavigationController::LoadURLParams
help_page_params(
349 google_util::AppendGoogleLocaleParam(
350 GURL(kHelpURL
), g_browser_process
->GetApplicationLocale()));
351 web_contents()->GetController().LoadURLWithParams(help_page_params
);
355 metrics_helper()->RecordUserInteraction(
356 security_interstitials::MetricsHelper::RELOAD
);
357 // The interstitial can't refresh itself.
358 web_contents()->GetController().Reload(true);
361 case CMD_OPEN_REPORTING_PRIVACY
:
362 OpenExtendedReportingPrivacyPolicy();
364 case CMD_OPEN_DATE_SETTINGS
:
365 case CMD_OPEN_DIAGNOSTIC
:
366 // Commands not supported by the SSL interstitial.
367 NOTREACHED() << "Unexpected command: " << command
;
371 void SSLBlockingPage::OverrideRendererPrefs(
372 content::RendererPreferences
* prefs
) {
373 Profile
* profile
= Profile::FromBrowserContext(
374 web_contents()->GetBrowserContext());
375 renderer_preferences_util::UpdateFromSystemSettings(
376 prefs
, profile
, web_contents());
379 void SSLBlockingPage::OnProceed() {
380 metrics_helper()->RecordUserDecision(
381 security_interstitials::MetricsHelper::PROCEED
);
383 // Finish collecting information about invalid certificates, if the
385 cert_report_helper_
->FinishCertCollection(
386 certificate_reporting::ErrorReport::USER_PROCEEDED
);
388 RecordSSLExpirationPageEventState(
389 expired_but_previously_allowed_
, true, overridable_
);
390 // Accepting the certificate resumes the loading of the page.
391 NotifyAllowCertificate();
394 void SSLBlockingPage::OnDontProceed() {
395 metrics_helper()->RecordUserDecision(
396 security_interstitials::MetricsHelper::DONT_PROCEED
);
398 // Finish collecting information about invalid certificates, if the
400 cert_report_helper_
->FinishCertCollection(
401 certificate_reporting::ErrorReport::USER_DID_NOT_PROCEED
);
403 RecordSSLExpirationPageEventState(
404 expired_but_previously_allowed_
, false, overridable_
);
405 NotifyDenyCertificate();
408 void SSLBlockingPage::NotifyDenyCertificate() {
409 // It's possible that callback_ may not exist if the user clicks "Proceed"
410 // followed by pressing the back button before the interstitial is hidden.
411 // In that case the certificate will still be treated as allowed.
412 if (callback_
.is_null())
415 callback_
.Run(false);
419 void SSLBlockingPage::NotifyAllowCertificate() {
420 DCHECK(!callback_
.is_null());
426 std::string
SSLBlockingPage::GetUmaHistogramPrefix() const {
427 return overridable_
? "ssl_overridable" : "ssl_nonoverridable";
430 std::string
SSLBlockingPage::GetSamplingEventName() const {
431 std::string
event_name(kEventNameBase
);
433 event_name
.append(kEventOverridable
);
435 event_name
.append(kEventNotOverridable
);
436 event_name
.append(net::ErrorToString(cert_error_
));
441 bool SSLBlockingPage::IsOverridable(int options_mask
,
442 const Profile
* const profile
) {
443 const bool is_overridable
=
444 (options_mask
& SSLBlockingPage::OVERRIDABLE
) &&
445 !(options_mask
& SSLBlockingPage::STRICT_ENFORCEMENT
) &&
446 profile
->GetPrefs()->GetBoolean(prefs::kSSLErrorOverrideAllowed
);
447 return is_overridable
;
451 bool SSLBlockingPage::DoesPolicyAllowDangerOverride(
452 const Profile
* const profile
) {
453 return profile
->GetPrefs()->GetBoolean(prefs::kSSLErrorOverrideAllowed
);