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/history/history_service_factory.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/renderer_preferences_util.h"
26 #include "chrome/browser/ssl/ssl_error_classification.h"
27 #include "chrome/browser/ssl/ssl_error_info.h"
28 #include "chrome/browser/ui/zoom/zoom_controller.h"
29 #include "chrome/common/chrome_switches.h"
30 #include "chrome/grit/chromium_strings.h"
31 #include "chrome/grit/generated_resources.h"
32 #include "components/google/core/browser/google_util.h"
33 #include "content/public/browser/cert_store.h"
34 #include "content/public/browser/interstitial_page.h"
35 #include "content/public/browser/navigation_controller.h"
36 #include "content/public/browser/navigation_entry.h"
37 #include "content/public/browser/notification_service.h"
38 #include "content/public/browser/notification_types.h"
39 #include "content/public/browser/render_process_host.h"
40 #include "content/public/browser/render_view_host.h"
41 #include "content/public/browser/web_contents.h"
42 #include "content/public/common/renderer_preferences.h"
43 #include "content/public/common/ssl_status.h"
44 #include "grit/browser_resources.h"
45 #include "net/base/hash_value.h"
46 #include "net/base/net_errors.h"
47 #include "net/base/net_util.h"
48 #include "ui/base/l10n/l10n_util.h"
49 #include "ui/base/resource/resource_bundle.h"
50 #include "ui/base/webui/jstemplate_builder.h"
51 #include "ui/base/webui/web_ui_util.h"
53 #if defined(ENABLE_EXTENSIONS)
54 #include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
58 #include "base/base_paths_win.h"
59 #include "base/path_service.h"
60 #include "base/strings/string16.h"
61 #include "base/win/windows_version.h"
64 #if defined(OS_ANDROID)
65 #include "chrome/browser/android/intent_helper.h"
68 #if defined(OS_CHROMEOS)
69 #include "chrome/browser/profiles/profile_manager.h"
70 #include "chrome/browser/ui/chrome_pages.h"
71 #include "chrome/common/url_constants.h"
74 using base::ASCIIToUTF16;
75 using base::TimeTicks;
76 using content::InterstitialPage;
77 using content::NavigationController;
78 using content::NavigationEntry;
80 #if defined(ENABLE_EXTENSIONS)
81 using extensions::ExperienceSamplingEvent;
87 const char kHelpURL[] = "https://support.google.com/chrome/answer/4454607";
89 // Constants for the Experience Sampling instrumentation.
90 #if defined(ENABLE_EXTENSIONS)
91 const char kEventNameBase[] = "ssl_interstitial_";
92 const char kEventNotOverridable[] = "notoverridable_";
93 const char kEventOverridable[] = "overridable_";
96 // Events for UMA. Do not reorder or change!
97 enum SSLBlockingPageEvent {
104 DONT_PROCEED_OVERRIDABLE,
107 DONT_PROCEED_AUTHORITY,
109 SHOW_UNDERSTAND, // Used by the summer 2013 Finch trial. Deprecated.
110 SHOW_INTERNAL_HOSTNAME,
111 PROCEED_INTERNAL_HOSTNAME,
114 PROCEED_MANUAL_NONOVERRIDABLE,
115 // Captive Portal errors moved to ssl_error_classification.
116 DEPRECATED_CAPTIVE_PORTAL_DETECTION_ENABLED,
117 DEPRECATED_CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE,
118 DEPRECATED_CAPTIVE_PORTAL_PROBE_COMPLETED,
119 DEPRECATED_CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE,
120 DEPRECATED_CAPTIVE_PORTAL_NO_RESPONSE,
121 DEPRECATED_CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE,
122 DEPRECATED_CAPTIVE_PORTAL_DETECTED,
123 DEPRECATED_CAPTIVE_PORTAL_DETECTED_OVERRIDABLE,
124 UNUSED_BLOCKING_PAGE_EVENT,
127 // Events for UMA. Do not reorder or change!
128 enum SSLExpirationAndDecision {
130 EXPIRED_AND_DO_NOT_PROCEED,
131 NOT_EXPIRED_AND_PROCEED,
132 NOT_EXPIRED_AND_DO_NOT_PROCEED,
133 END_OF_SSL_EXPIRATION_AND_DECISION,
136 void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event) {
137 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl",
139 UNUSED_BLOCKING_PAGE_EVENT);
142 void RecordSSLExpirationPageEventState(bool expired_but_previously_allowed,
145 SSLExpirationAndDecision event;
146 if (expired_but_previously_allowed && proceed)
147 event = EXPIRED_AND_PROCEED;
148 else if (expired_but_previously_allowed && !proceed)
149 event = EXPIRED_AND_DO_NOT_PROCEED;
150 else if (!expired_but_previously_allowed && proceed)
151 event = NOT_EXPIRED_AND_PROCEED;
153 event = NOT_EXPIRED_AND_DO_NOT_PROCEED;
156 UMA_HISTOGRAM_ENUMERATION(
157 "interstitial.ssl.expiration_and_decision.overridable",
159 END_OF_SSL_EXPIRATION_AND_DECISION);
161 UMA_HISTOGRAM_ENUMERATION(
162 "interstitial.ssl.expiration_and_decision.nonoverridable",
164 END_OF_SSL_EXPIRATION_AND_DECISION);
168 void RecordSSLBlockingPageDetailedStats(bool proceed,
173 bool expired_but_previously_allowed) {
174 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type",
175 SSLErrorInfo::NetErrorToErrorType(cert_error), SSLErrorInfo::END_OF_ENUM);
176 RecordSSLExpirationPageEventState(
177 expired_but_previously_allowed, proceed, overridable);
180 RecordSSLBlockingPageEventStats(PROCEED_MANUAL_NONOVERRIDABLE);
182 // Overridable is false if the user didn't have any option except to turn
183 // back. If that's the case, don't record some of the metrics.
187 RecordSSLBlockingPageEventStats(SHOW_NEW_SITE);
189 RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE);
191 RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME);
193 RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE);
194 } else if (!proceed) {
195 RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE);
197 SSLErrorInfo::ErrorType type = SSLErrorInfo::NetErrorToErrorType(cert_error);
199 case SSLErrorInfo::CERT_COMMON_NAME_INVALID: {
201 RecordSSLBlockingPageEventStats(PROCEED_NAME);
203 RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME);
206 case SSLErrorInfo::CERT_DATE_INVALID: {
208 RecordSSLBlockingPageEventStats(PROCEED_DATE);
210 RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE);
213 case SSLErrorInfo::CERT_AUTHORITY_INVALID: {
215 RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY);
217 RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY);
226 void LaunchDateAndTimeSettings() {
227 #if defined(OS_CHROMEOS)
228 std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
229 l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME);
230 chrome::ShowSettingsSubPageForProfile(
231 ProfileManager::GetActiveUserProfile(), sub_page);
233 #elif defined(OS_ANDROID)
234 chrome::android::OpenDateAndTimeSettings();
236 #elif defined(OS_IOS)
237 // iOS does not have a way to launch the date and time settings.
239 #elif defined(OS_LINUX)
240 struct ClockCommand {
241 const char* pathname;
242 const char* argument;
244 static const ClockCommand kClockCommands[] = {
246 { "/usr/bin/unity-control-center", "datetime" },
249 // NOTE: On old Ubuntu, naming control panels doesn't work, so it
250 // opens the overview. This will have to be good enough.
251 { "/usr/bin/gnome-control-center", "datetime" },
252 { "/usr/local/bin/gnome-control-center", "datetime" },
253 { "/opt/bin/gnome-control-center", "datetime" },
255 { "/usr/bin/kcmshell4", "clock" },
256 { "/usr/local/bin/kcmshell4", "clock" },
257 { "/opt/bin/kcmshell4", "clock" },
260 CommandLine command(base::FilePath(""));
261 for (size_t i = 0; i < arraysize(kClockCommands); ++i) {
262 base::FilePath pathname(kClockCommands[i].pathname);
263 if (base::PathExists(pathname)) {
264 command.SetProgram(pathname);
265 command.AppendArg(kClockCommands[i].argument);
269 if (command.GetProgram().empty()) {
270 // Alas, there is nothing we can do.
273 #elif defined(OS_MACOSX)
274 CommandLine command(base::FilePath("/usr/bin/open"));
275 command.AppendArg("/System/Library/PreferencePanes/DateAndTime.prefPane");
276 #elif defined(OS_WIN)
278 PathService::Get(base::DIR_SYSTEM, &path);
279 static const base::char16 kControlPanelExe[] = L"control.exe";
280 path = path.Append(base::string16(kControlPanelExe));
281 CommandLine command(path);
282 command.AppendArg(std::string("/name"));
283 command.AppendArg(std::string("Microsoft.DateAndTime"));
288 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
289 base::LaunchOptions options;
290 options.wait = false;
291 #if defined(OS_LINUX)
292 options.allow_new_privs = true;
294 base::LaunchProcess(command, options, NULL);
298 bool IsErrorDueToBadClock(const base::Time& now, int error) {
299 if (SSLErrorInfo::NetErrorToErrorType(error) !=
300 SSLErrorInfo::CERT_DATE_INVALID) {
303 return SSLErrorClassification::IsUserClockInThePast(now) ||
304 SSLErrorClassification::IsUserClockInTheFuture(now);
309 // Note that we always create a navigation entry with SSL errors.
310 // No error happening loading a sub-resource triggers an interstitial so far.
311 SSLBlockingPage::SSLBlockingPage(content::WebContents* web_contents,
313 const net::SSLInfo& ssl_info,
314 const GURL& request_url,
316 const base::Callback<void(bool)>& callback)
317 : callback_(callback),
318 web_contents_(web_contents),
319 cert_error_(cert_error),
321 request_url_(request_url),
322 overridable_(options_mask & OVERRIDABLE &&
323 !(options_mask & STRICT_ENFORCEMENT)),
324 danger_overridable_(true),
325 strict_enforcement_((options_mask & STRICT_ENFORCEMENT) != 0),
326 interstitial_page_(NULL),
329 expired_but_previously_allowed_(
330 (options_mask & EXPIRED_BUT_PREVIOUSLY_ALLOWED) != 0) {
331 Profile* profile = Profile::FromBrowserContext(
332 web_contents->GetBrowserContext());
334 if (SSLErrorClassification::IsHostnameNonUniqueOrDotless(
335 request_url_.HostNoBrackets()))
337 RecordSSLBlockingPageEventStats(SHOW_ALL);
339 RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE);
341 RecordSSLBlockingPageEventStats(SHOW_INTERNAL_HOSTNAME);
342 HistoryService* history_service = HistoryServiceFactory::GetForProfile(
343 profile, Profile::EXPLICIT_ACCESS);
344 if (history_service) {
345 history_service->GetVisibleVisitCountToHost(
347 base::Bind(&SSLBlockingPage::OnGotHistoryCount,
348 base::Unretained(this)),
353 ssl_error_classification_.reset(new SSLErrorClassification(
355 base::Time::NowFromSystemTime(),
358 *ssl_info_.cert.get()));
359 ssl_error_classification_->RecordUMAStatistics(overridable_);
361 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
362 ssl_error_classification_->RecordCaptivePortalUMAStatistics(overridable_);
365 #if defined(ENABLE_EXTENSIONS)
366 // ExperienceSampling: Set up new sampling event for this interstitial.
367 std::string event_name(kEventNameBase);
368 if (overridable_ && !strict_enforcement_)
369 event_name.append(kEventOverridable);
371 event_name.append(kEventNotOverridable);
372 event_name.append(net::ErrorToString(cert_error_));
373 sampling_event_.reset(new ExperienceSamplingEvent(
376 web_contents_->GetLastCommittedURL(),
377 web_contents_->GetBrowserContext()));
380 // Creating an interstitial without showing (e.g. from chrome://interstitials)
381 // it leaks memory, so don't create it here.
384 SSLBlockingPage::~SSLBlockingPage() {
385 // InvalidCommonNameSeverityScore() and InvalidDateSeverityScore() are in the
386 // destructor because they depend on knowing whether captive portal detection
387 // happened before the user made a decision.
388 SSLErrorInfo::ErrorType type =
389 SSLErrorInfo::NetErrorToErrorType(cert_error_);
391 case SSLErrorInfo::CERT_DATE_INVALID:
392 ssl_error_classification_->InvalidDateSeverityScore();
394 case SSLErrorInfo::CERT_COMMON_NAME_INVALID:
395 ssl_error_classification_->InvalidCommonNameSeverityScore();
397 case SSLErrorInfo::CERT_AUTHORITY_INVALID:
398 ssl_error_classification_->InvalidAuthoritySeverityScore();
403 if (!callback_.is_null()) {
404 RecordSSLBlockingPageDetailedStats(false,
409 expired_but_previously_allowed_);
410 // The page is closed without the user having chosen what to do, default to
412 NotifyDenyCertificate();
416 void SSLBlockingPage::Show() {
417 DCHECK(!interstitial_page_);
418 interstitial_page_ = InterstitialPage::Create(
419 web_contents_, true, request_url_, this);
420 interstitial_page_->Show();
423 std::string SSLBlockingPage::GetHTMLContents() {
424 base::DictionaryValue load_time_data;
425 base::string16 url(ASCIIToUTF16(request_url_.host()));
426 if (base::i18n::IsRTL())
427 base::i18n::WrapStringWithLTRFormatting(&url);
428 webui::SetFontAndTextDirection(&load_time_data);
430 load_time_data.SetString("type", "SSL");
432 // Shared UI configuration for all SSL interstitials.
433 base::Time now = base::Time::NowFromSystemTime();
434 bool bad_clock = IsErrorDueToBadClock(now, cert_error_);
436 load_time_data.SetString("errorCode", net::ErrorToString(cert_error_));
437 load_time_data.SetString(
439 l10n_util::GetStringUTF16(IDS_SSL_V2_OPEN_DETAILS_BUTTON));
440 load_time_data.SetString(
442 l10n_util::GetStringUTF16(IDS_SSL_V2_CLOSE_DETAILS_BUTTON));
444 // Conditional UI configuration.
446 load_time_data.SetBoolean("bad_clock", true);
447 load_time_data.SetBoolean("overridable", false);
450 load_time_data.SetBoolean("hide_primary_button", true);
452 load_time_data.SetBoolean("hide_primary_button", false);
455 // We're showing the SSL clock warning to be helpful, but we haven't warned
456 // them about the risks. (And there might still be an SSL error after they
457 // fix their clock.) Thus, we don't allow the "danger" override in this
459 danger_overridable_ = false;
461 int heading_string = SSLErrorClassification::IsUserClockInTheFuture(now) ?
462 IDS_SSL_V2_CLOCK_AHEAD_HEADING :
463 IDS_SSL_V2_CLOCK_BEHIND_HEADING;
465 load_time_data.SetString(
467 l10n_util::GetStringUTF16(IDS_SSL_V2_CLOCK_TITLE));
468 load_time_data.SetString(
470 l10n_util::GetStringUTF16(heading_string));
471 load_time_data.SetString("primaryParagraph",
472 l10n_util::GetStringFUTF16(
473 IDS_SSL_V2_CLOCK_PRIMARY_PARAGRAPH ,
475 base::TimeFormatFriendlyDateAndTime(now)));
477 load_time_data.SetString(
479 l10n_util::GetStringUTF16(IDS_SSL_V2_CLOCK_UPDATE_DATE_AND_TIME));
480 load_time_data.SetString(
481 "explanationParagraph",
482 l10n_util::GetStringUTF16(IDS_SSL_V2_CLOCK_EXPLANATION));
484 // The interstitial template expects this string, but we're not using it. So
485 // we send a blank string for now.
486 load_time_data.SetString("finalParagraph", std::string());
488 load_time_data.SetBoolean("bad_clock", false);
490 load_time_data.SetString(
491 "tabTitle", l10n_util::GetStringUTF16(IDS_SSL_V2_TITLE));
492 load_time_data.SetString(
493 "heading", l10n_util::GetStringUTF16(IDS_SSL_V2_HEADING));
494 load_time_data.SetString(
496 l10n_util::GetStringFUTF16(IDS_SSL_V2_PRIMARY_PARAGRAPH, url));
499 load_time_data.SetBoolean("overridable", true);
501 SSLErrorInfo error_info =
502 SSLErrorInfo::CreateError(
503 SSLErrorInfo::NetErrorToErrorType(cert_error_),
504 ssl_info_.cert.get(),
506 load_time_data.SetString("explanationParagraph", error_info.details());
507 load_time_data.SetString(
509 l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_SAFETY_BUTTON));
510 load_time_data.SetString(
512 l10n_util::GetStringFUTF16(IDS_SSL_OVERRIDABLE_PROCEED_PARAGRAPH,
515 load_time_data.SetBoolean("overridable", false);
517 SSLErrorInfo::ErrorType type =
518 SSLErrorInfo::NetErrorToErrorType(cert_error_);
519 if (type == SSLErrorInfo::CERT_INVALID && SSLErrorClassification::
520 MaybeWindowsLacksSHA256Support()) {
521 load_time_data.SetString(
522 "explanationParagraph",
523 l10n_util::GetStringFUTF16(
524 IDS_SSL_NONOVERRIDABLE_MORE_INVALID_SP3, url));
526 load_time_data.SetString("explanationParagraph",
527 l10n_util::GetStringFUTF16(
528 IDS_SSL_NONOVERRIDABLE_MORE, url));
530 load_time_data.SetString(
532 l10n_util::GetStringUTF16(IDS_SSL_RELOAD));
533 // Customize the help link depending on the specific error type.
534 // Only mark as HSTS if none of the more specific error types apply,
535 // and use INVALID as a fallback if no other string is appropriate.
536 load_time_data.SetInteger("errorType", type);
537 int help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
539 case SSLErrorInfo::CERT_REVOKED:
540 help_string = IDS_SSL_NONOVERRIDABLE_REVOKED;
542 case SSLErrorInfo::CERT_PINNED_KEY_MISSING:
543 help_string = IDS_SSL_NONOVERRIDABLE_PINNED;
545 case SSLErrorInfo::CERT_INVALID:
546 help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
549 if (strict_enforcement_)
550 help_string = IDS_SSL_NONOVERRIDABLE_HSTS;
552 load_time_data.SetString(
553 "finalParagraph", l10n_util::GetStringFUTF16(help_string, url));
557 // Set debugging information at the bottom of the warning.
558 load_time_data.SetString(
559 "subject", ssl_info_.cert->subject().GetDisplayName());
560 load_time_data.SetString(
561 "issuer", ssl_info_.cert->issuer().GetDisplayName());
562 load_time_data.SetString(
564 base::TimeFormatShortDate(ssl_info_.cert->valid_expiry()));
565 load_time_data.SetString(
566 "currentDate", base::TimeFormatShortDate(now));
567 std::vector<std::string> encoded_chain;
568 ssl_info_.cert->GetPEMEncodedChain(&encoded_chain);
569 load_time_data.SetString("pem", JoinString(encoded_chain, std::string()));
571 base::StringPiece html(
572 ResourceBundle::GetSharedInstance().GetRawDataResource(
573 IDR_SECURITY_INTERSTITIAL_HTML));
574 return webui::GetI18nTemplateHtml(html, &load_time_data);
577 void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
578 int cert_id = content::CertStore::GetInstance()->StoreCert(
579 ssl_info_.cert.get(), web_contents_->GetRenderProcessHost()->GetID());
582 entry->GetSSL().security_style =
583 content::SECURITY_STYLE_AUTHENTICATION_BROKEN;
584 entry->GetSSL().cert_id = cert_id;
585 entry->GetSSL().cert_status = ssl_info_.cert_status;
586 entry->GetSSL().security_bits = ssl_info_.security_bits;
589 // This handles the commands sent from the interstitial JavaScript. They are
590 // defined in chrome/browser/resources/ssl/ssl_errors_common.js.
591 // DO NOT reorder or change this logic without also changing the JavaScript!
592 void SSLBlockingPage::CommandReceived(const std::string& command) {
594 bool retval = base::StringToInt(command, &cmd);
597 case CMD_DONT_PROCEED: {
598 interstitial_page_->DontProceed();
602 if (danger_overridable_) {
603 interstitial_page_->Proceed();
608 RecordSSLBlockingPageEventStats(MORE);
609 #if defined(ENABLE_EXTENSIONS)
610 if (sampling_event_.get())
611 sampling_event_->set_has_viewed_details(true);
616 // The interstitial can't refresh itself.
617 web_contents_->GetController().Reload(true);
621 content::NavigationController::LoadURLParams help_page_params(
622 google_util::AppendGoogleLocaleParam(
623 GURL(kHelpURL), g_browser_process->GetApplicationLocale()));
624 #if defined(ENABLE_EXTENSIONS)
625 if (sampling_event_.get())
626 sampling_event_->set_has_viewed_learn_more(true);
628 web_contents_->GetController().LoadURLWithParams(help_page_params);
632 LaunchDateAndTimeSettings();
641 void SSLBlockingPage::OverrideRendererPrefs(
642 content::RendererPreferences* prefs) {
643 Profile* profile = Profile::FromBrowserContext(
644 web_contents_->GetBrowserContext());
645 renderer_preferences_util::UpdateFromSystemSettings(
646 prefs, profile, web_contents_);
649 void SSLBlockingPage::OnProceed() {
650 RecordSSLBlockingPageDetailedStats(true,
655 expired_but_previously_allowed_);
656 #if defined(ENABLE_EXTENSIONS)
657 // ExperienceSampling: Notify that user decided to proceed.
658 if (sampling_event_.get())
659 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
662 // Accepting the certificate resumes the loading of the page.
663 NotifyAllowCertificate();
666 void SSLBlockingPage::OnDontProceed() {
667 RecordSSLBlockingPageDetailedStats(false,
672 expired_but_previously_allowed_);
673 #if defined(ENABLE_EXTENSIONS)
674 // ExperienceSampling: Notify that user decided to not proceed.
675 // This also occurs if the user navigates away or closes the tab.
676 if (sampling_event_.get())
677 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
679 NotifyDenyCertificate();
682 void SSLBlockingPage::NotifyDenyCertificate() {
683 // It's possible that callback_ may not exist if the user clicks "Proceed"
684 // followed by pressing the back button before the interstitial is hidden.
685 // In that case the certificate will still be treated as allowed.
686 if (callback_.is_null())
689 callback_.Run(false);
693 void SSLBlockingPage::NotifyAllowCertificate() {
694 DCHECK(!callback_.is_null());
701 void SSLBlockingPage::SetExtraInfo(
702 base::DictionaryValue* strings,
703 const std::vector<base::string16>& extra_info) {
704 DCHECK_LT(extra_info.size(), 5U); // We allow 5 paragraphs max.
705 const char* keys[5] = {
706 "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
709 for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
710 strings->SetString(keys[i], extra_info[i]);
713 strings->SetString(keys[i], std::string());
717 void SSLBlockingPage::OnGotHistoryCount(bool success,
719 base::Time first_visit) {
720 num_visits_ = num_visits;