Home | History | Annotate | Download | only in ssl
      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.
      4 
      5 #include "chrome/browser/ssl/ssl_blocking_page.h"
      6 
      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/common/chrome_switches.h"
     29 #include "chrome/grit/chromium_strings.h"
     30 #include "chrome/grit/generated_resources.h"
     31 #include "components/google/core/browser/google_util.h"
     32 #include "content/public/browser/cert_store.h"
     33 #include "content/public/browser/interstitial_page.h"
     34 #include "content/public/browser/navigation_controller.h"
     35 #include "content/public/browser/navigation_entry.h"
     36 #include "content/public/browser/notification_service.h"
     37 #include "content/public/browser/notification_types.h"
     38 #include "content/public/browser/render_process_host.h"
     39 #include "content/public/browser/render_view_host.h"
     40 #include "content/public/browser/web_contents.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"
     47 #include "ui/base/resource/resource_bundle.h"
     48 #include "ui/base/webui/jstemplate_builder.h"
     49 #include "ui/base/webui/web_ui_util.h"
     50 
     51 #if defined(ENABLE_EXTENSIONS)
     52 #include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
     53 #endif
     54 
     55 #if defined(OS_WIN)
     56 #include "base/base_paths_win.h"
     57 #include "base/path_service.h"
     58 #include "base/strings/string16.h"
     59 #include "base/win/windows_version.h"
     60 #endif
     61 
     62 #if defined(OS_CHROMEOS)
     63 #include "chrome/browser/profiles/profile_manager.h"
     64 #include "chrome/browser/ui/chrome_pages.h"
     65 #include "chrome/common/url_constants.h"
     66 #endif
     67 
     68 using base::ASCIIToUTF16;
     69 using base::TimeTicks;
     70 using content::InterstitialPage;
     71 using content::NavigationController;
     72 using content::NavigationEntry;
     73 
     74 #if defined(ENABLE_EXTENSIONS)
     75 using extensions::ExperienceSamplingEvent;
     76 #endif
     77 
     78 namespace {
     79 
     80 // URL for help page.
     81 const char kHelpURL[] = "https://support.google.com/chrome/answer/4454607";
     82 
     83 // Constants for the Experience Sampling instrumentation.
     84 #if defined(ENABLE_EXTENSIONS)
     85 const char kEventNameBase[] = "ssl_interstitial_";
     86 const char kEventNotOverridable[] = "notoverridable_";
     87 const char kEventOverridable[] = "overridable_";
     88 #endif
     89 
     90 // Events for UMA. Do not reorder or change!
     91 enum SSLBlockingPageEvent {
     92   SHOW_ALL,
     93   SHOW_OVERRIDABLE,
     94   PROCEED_OVERRIDABLE,
     95   PROCEED_NAME,
     96   PROCEED_DATE,
     97   PROCEED_AUTHORITY,
     98   DONT_PROCEED_OVERRIDABLE,
     99   DONT_PROCEED_NAME,
    100   DONT_PROCEED_DATE,
    101   DONT_PROCEED_AUTHORITY,
    102   MORE,
    103   SHOW_UNDERSTAND,  // Used by the summer 2013 Finch trial. Deprecated.
    104   SHOW_INTERNAL_HOSTNAME,
    105   PROCEED_INTERNAL_HOSTNAME,
    106   SHOW_NEW_SITE,
    107   PROCEED_NEW_SITE,
    108   PROCEED_MANUAL_NONOVERRIDABLE,
    109   // Captive Portal errors moved to ssl_error_classification.
    110   DEPRECATED_CAPTIVE_PORTAL_DETECTION_ENABLED,
    111   DEPRECATED_CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE,
    112   DEPRECATED_CAPTIVE_PORTAL_PROBE_COMPLETED,
    113   DEPRECATED_CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE,
    114   DEPRECATED_CAPTIVE_PORTAL_NO_RESPONSE,
    115   DEPRECATED_CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE,
    116   DEPRECATED_CAPTIVE_PORTAL_DETECTED,
    117   DEPRECATED_CAPTIVE_PORTAL_DETECTED_OVERRIDABLE,
    118   UNUSED_BLOCKING_PAGE_EVENT,
    119 };
    120 
    121 // Events for UMA. Do not reorder or change!
    122 enum SSLExpirationAndDecision {
    123   EXPIRED_AND_PROCEED,
    124   EXPIRED_AND_DO_NOT_PROCEED,
    125   NOT_EXPIRED_AND_PROCEED,
    126   NOT_EXPIRED_AND_DO_NOT_PROCEED,
    127   END_OF_SSL_EXPIRATION_AND_DECISION,
    128 };
    129 
    130 void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event) {
    131   UMA_HISTOGRAM_ENUMERATION("interstitial.ssl",
    132                             event,
    133                             UNUSED_BLOCKING_PAGE_EVENT);
    134 }
    135 
    136 void RecordSSLExpirationPageEventState(bool expired_but_previously_allowed,
    137                                        bool proceed,
    138                                        bool overridable) {
    139   SSLExpirationAndDecision event;
    140   if (expired_but_previously_allowed && proceed)
    141     event = EXPIRED_AND_PROCEED;
    142   else if (expired_but_previously_allowed && !proceed)
    143     event = EXPIRED_AND_DO_NOT_PROCEED;
    144   else if (!expired_but_previously_allowed && proceed)
    145     event = NOT_EXPIRED_AND_PROCEED;
    146   else
    147     event = NOT_EXPIRED_AND_DO_NOT_PROCEED;
    148 
    149   if (overridable) {
    150     UMA_HISTOGRAM_ENUMERATION(
    151         "interstitial.ssl.expiration_and_decision.overridable",
    152         event,
    153         END_OF_SSL_EXPIRATION_AND_DECISION);
    154   } else {
    155     UMA_HISTOGRAM_ENUMERATION(
    156         "interstitial.ssl.expiration_and_decision.nonoverridable",
    157         event,
    158         END_OF_SSL_EXPIRATION_AND_DECISION);
    159   }
    160 }
    161 
    162 void RecordSSLBlockingPageDetailedStats(bool proceed,
    163                                         int cert_error,
    164                                         bool overridable,
    165                                         bool internal,
    166                                         int num_visits,
    167                                         bool expired_but_previously_allowed) {
    168   UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type",
    169       SSLErrorInfo::NetErrorToErrorType(cert_error), SSLErrorInfo::END_OF_ENUM);
    170   RecordSSLExpirationPageEventState(
    171       expired_but_previously_allowed, proceed, overridable);
    172   if (!overridable) {
    173     if (proceed) {
    174       RecordSSLBlockingPageEventStats(PROCEED_MANUAL_NONOVERRIDABLE);
    175     }
    176     // Overridable is false if the user didn't have any option except to turn
    177     // back. If that's the case, don't record some of the metrics.
    178     return;
    179   }
    180   if (num_visits == 0)
    181     RecordSSLBlockingPageEventStats(SHOW_NEW_SITE);
    182   if (proceed) {
    183     RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE);
    184     if (internal)
    185       RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME);
    186     if (num_visits == 0)
    187       RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE);
    188   } else if (!proceed) {
    189     RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE);
    190   }
    191   SSLErrorInfo::ErrorType type = SSLErrorInfo::NetErrorToErrorType(cert_error);
    192   switch (type) {
    193     case SSLErrorInfo::CERT_COMMON_NAME_INVALID: {
    194       if (proceed)
    195         RecordSSLBlockingPageEventStats(PROCEED_NAME);
    196       else
    197         RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME);
    198       break;
    199     }
    200     case SSLErrorInfo::CERT_DATE_INVALID: {
    201       if (proceed)
    202         RecordSSLBlockingPageEventStats(PROCEED_DATE);
    203       else
    204         RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE);
    205       break;
    206     }
    207     case SSLErrorInfo::CERT_AUTHORITY_INVALID: {
    208       if (proceed)
    209         RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY);
    210       else
    211         RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY);
    212       break;
    213     }
    214     default: {
    215       break;
    216     }
    217   }
    218 }
    219 
    220 void LaunchDateAndTimeSettings() {
    221 #if defined(OS_CHROMEOS)
    222   std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
    223       l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME);
    224   chrome::ShowSettingsSubPageForProfile(
    225       ProfileManager::GetActiveUserProfile(), sub_page);
    226   return;
    227 #elif defined(OS_ANDROID)
    228   CommandLine command(base::FilePath("/system/bin/am"));
    229   command.AppendArg("start");
    230   command.AppendArg(
    231       "'com.android.settings/.Settings$DateTimeSettingsActivity'");
    232 #elif defined(OS_IOS)
    233   // Apparently, iOS really does not have a way to launch the date and time
    234   // settings. Weird. TODO(palmer): Do something more graceful than ignoring
    235   // the user's click! crbug.com/394993
    236   return;
    237 #elif defined(OS_LINUX)
    238   struct ClockCommand {
    239     const char* pathname;
    240     const char* argument;
    241   };
    242   static const ClockCommand kClockCommands[] = {
    243     // GNOME
    244     //
    245     // NOTE: On old Ubuntu, naming control panels doesn't work, so it
    246     // opens the overview. This will have to be good enough.
    247     { "/usr/bin/gnome-control-center", "datetime" },
    248     { "/usr/local/bin/gnome-control-center", "datetime" },
    249     { "/opt/bin/gnome-control-center", "datetime" },
    250     // KDE
    251     { "/usr/bin/kcmshell4", "clock" },
    252     { "/usr/local/bin/kcmshell4", "clock" },
    253     { "/opt/bin/kcmshell4", "clock" },
    254   };
    255 
    256   CommandLine command(base::FilePath(""));
    257   for (size_t i = 0; i < arraysize(kClockCommands); ++i) {
    258     base::FilePath pathname(kClockCommands[i].pathname);
    259     if (base::PathExists(pathname)) {
    260       command.SetProgram(pathname);
    261       command.AppendArg(kClockCommands[i].argument);
    262       break;
    263     }
    264   }
    265   if (command.GetProgram().empty()) {
    266     // Alas, there is nothing we can do.
    267     return;
    268   }
    269 #elif defined(OS_MACOSX)
    270   CommandLine command(base::FilePath("/usr/bin/open"));
    271   command.AppendArg("/System/Library/PreferencePanes/DateAndTime.prefPane");
    272 #elif defined(OS_WIN)
    273   base::FilePath path;
    274   PathService::Get(base::DIR_SYSTEM, &path);
    275   static const base::char16 kControlPanelExe[] = L"control.exe";
    276   path = path.Append(base::string16(kControlPanelExe));
    277   CommandLine command(path);
    278   command.AppendArg(std::string("/name"));
    279   command.AppendArg(std::string("Microsoft.DateAndTime"));
    280 #else
    281   return;
    282 #endif
    283 
    284 #if !defined(OS_CHROMEOS)
    285   base::LaunchOptions options;
    286   options.wait = false;
    287 #if defined(OS_LINUX)
    288   options.allow_new_privs = true;
    289 #endif
    290   base::LaunchProcess(command, options, NULL);
    291 #endif
    292 }
    293 
    294 bool IsErrorDueToBadClock(const base::Time& now, int error) {
    295   if (SSLErrorInfo::NetErrorToErrorType(error) !=
    296           SSLErrorInfo::CERT_DATE_INVALID) {
    297     return false;
    298   }
    299   return SSLErrorClassification::IsUserClockInThePast(now) ||
    300       SSLErrorClassification::IsUserClockInTheFuture(now);
    301 }
    302 
    303 }  // namespace
    304 
    305 // Note that we always create a navigation entry with SSL errors.
    306 // No error happening loading a sub-resource triggers an interstitial so far.
    307 SSLBlockingPage::SSLBlockingPage(content::WebContents* web_contents,
    308                                  int cert_error,
    309                                  const net::SSLInfo& ssl_info,
    310                                  const GURL& request_url,
    311                                  int options_mask,
    312                                  const base::Callback<void(bool)>& callback)
    313     : callback_(callback),
    314       web_contents_(web_contents),
    315       cert_error_(cert_error),
    316       ssl_info_(ssl_info),
    317       request_url_(request_url),
    318       overridable_(options_mask & OVERRIDABLE &&
    319                    !(options_mask & STRICT_ENFORCEMENT)),
    320       strict_enforcement_((options_mask & STRICT_ENFORCEMENT) != 0),
    321       interstitial_page_(NULL),
    322       internal_(false),
    323       num_visits_(-1),
    324       expired_but_previously_allowed_(
    325           (options_mask & EXPIRED_BUT_PREVIOUSLY_ALLOWED) != 0) {
    326   Profile* profile = Profile::FromBrowserContext(
    327       web_contents->GetBrowserContext());
    328   // For UMA stats.
    329   if (net::IsHostnameNonUnique(request_url_.HostNoBrackets()))
    330     internal_ = true;
    331   RecordSSLBlockingPageEventStats(SHOW_ALL);
    332   if (overridable_) {
    333     RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE);
    334     if (internal_)
    335       RecordSSLBlockingPageEventStats(SHOW_INTERNAL_HOSTNAME);
    336     HistoryService* history_service = HistoryServiceFactory::GetForProfile(
    337         profile, Profile::EXPLICIT_ACCESS);
    338     if (history_service) {
    339       history_service->GetVisibleVisitCountToHost(
    340           request_url_,
    341           base::Bind(&SSLBlockingPage::OnGotHistoryCount,
    342                      base::Unretained(this)),
    343           &request_tracker_);
    344     }
    345   }
    346 
    347   ssl_error_classification_.reset(new SSLErrorClassification(
    348       web_contents_,
    349       base::Time::NowFromSystemTime(),
    350       request_url_,
    351       cert_error_,
    352       *ssl_info_.cert.get()));
    353   ssl_error_classification_->RecordUMAStatistics(overridable_);
    354 
    355 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
    356   ssl_error_classification_->RecordCaptivePortalUMAStatistics(overridable_);
    357 #endif
    358 
    359 #if defined(ENABLE_EXTENSIONS)
    360   // ExperienceSampling: Set up new sampling event for this interstitial.
    361   std::string event_name(kEventNameBase);
    362   if (overridable_ && !strict_enforcement_)
    363     event_name.append(kEventOverridable);
    364   else
    365     event_name.append(kEventNotOverridable);
    366   event_name.append(net::ErrorToString(cert_error_));
    367   sampling_event_.reset(new ExperienceSamplingEvent(
    368       event_name,
    369       request_url_,
    370       web_contents_->GetLastCommittedURL(),
    371       web_contents_->GetBrowserContext()));
    372 #endif
    373 
    374   // Creating an interstitial without showing (e.g. from chrome://interstitials)
    375   // it leaks memory, so don't create it here.
    376 }
    377 
    378 SSLBlockingPage::~SSLBlockingPage() {
    379   // InvalidCommonNameSeverityScore() and InvalidDateSeverityScore() are in the
    380   // destructor because they depend on knowing whether captive portal detection
    381   // happened before the user made a decision.
    382   SSLErrorInfo::ErrorType type =
    383       SSLErrorInfo::NetErrorToErrorType(cert_error_);
    384   switch (type) {
    385     case SSLErrorInfo::CERT_DATE_INVALID:
    386       ssl_error_classification_->InvalidDateSeverityScore();
    387       break;
    388     case SSLErrorInfo::CERT_COMMON_NAME_INVALID:
    389       ssl_error_classification_->InvalidCommonNameSeverityScore();
    390       break;
    391     default:
    392       break;
    393   }
    394   if (!callback_.is_null()) {
    395     RecordSSLBlockingPageDetailedStats(false,
    396                                        cert_error_,
    397                                        overridable_,
    398                                        internal_,
    399                                        num_visits_,
    400                                        expired_but_previously_allowed_);
    401     // The page is closed without the user having chosen what to do, default to
    402     // deny.
    403     NotifyDenyCertificate();
    404   }
    405 }
    406 
    407 void SSLBlockingPage::Show() {
    408   DCHECK(!interstitial_page_);
    409   interstitial_page_ = InterstitialPage::Create(
    410       web_contents_, true, request_url_, this);
    411   interstitial_page_->Show();
    412 }
    413 
    414 std::string SSLBlockingPage::GetHTMLContents() {
    415   base::DictionaryValue load_time_data;
    416   base::string16 url(ASCIIToUTF16(request_url_.host()));
    417   if (base::i18n::IsRTL())
    418     base::i18n::WrapStringWithLTRFormatting(&url);
    419   webui::SetFontAndTextDirection(&load_time_data);
    420 
    421   // Shared values for both the overridable and non-overridable versions.
    422   load_time_data.SetBoolean("ssl", true);
    423   load_time_data.SetBoolean("overridable", overridable_);
    424   load_time_data.SetString(
    425       "tabTitle", l10n_util::GetStringUTF16(IDS_SSL_V2_TITLE));
    426   load_time_data.SetString(
    427       "heading", l10n_util::GetStringUTF16(IDS_SSL_V2_HEADING));
    428 
    429   base::Time now = base::Time::NowFromSystemTime();
    430   bool bad_clock = IsErrorDueToBadClock(now, cert_error_);
    431   if (bad_clock) {
    432     load_time_data.SetString("primaryParagraph",
    433                              l10n_util::GetStringFUTF16(
    434                                  IDS_SSL_CLOCK_ERROR,
    435                                  url,
    436                                  base::TimeFormatShortDate(now)));
    437   } else {
    438     load_time_data.SetString(
    439         "primaryParagraph",
    440         l10n_util::GetStringFUTF16(IDS_SSL_V2_PRIMARY_PARAGRAPH, url));
    441   }
    442 
    443   load_time_data.SetString(
    444      "openDetails",
    445      l10n_util::GetStringUTF16(IDS_SSL_V2_OPEN_DETAILS_BUTTON));
    446   load_time_data.SetString(
    447      "closeDetails",
    448      l10n_util::GetStringUTF16(IDS_SSL_V2_CLOSE_DETAILS_BUTTON));
    449   load_time_data.SetString("errorCode", net::ErrorToString(cert_error_));
    450 
    451   if (overridable_) {
    452     SSLErrorInfo error_info =
    453         SSLErrorInfo::CreateError(
    454             SSLErrorInfo::NetErrorToErrorType(cert_error_),
    455             ssl_info_.cert.get(),
    456             request_url_);
    457     if (bad_clock) {
    458       load_time_data.SetString("explanationParagraph",
    459                                l10n_util::GetStringFUTF16(
    460                                    IDS_SSL_CLOCK_ERROR_EXPLANATION, url));
    461     } else {
    462       load_time_data.SetString("explanationParagraph", error_info.details());
    463     }
    464     load_time_data.SetString(
    465         "primaryButtonText",
    466         l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_SAFETY_BUTTON));
    467     load_time_data.SetString(
    468         "finalParagraph",
    469         l10n_util::GetStringFUTF16(IDS_SSL_OVERRIDABLE_PROCEED_PARAGRAPH,
    470                                    url));
    471   } else {
    472     SSLErrorInfo::ErrorType type =
    473         SSLErrorInfo::NetErrorToErrorType(cert_error_);
    474     if (type == SSLErrorInfo::CERT_INVALID && SSLErrorClassification::
    475         MaybeWindowsLacksSHA256Support()) {
    476       load_time_data.SetString(
    477           "explanationParagraph",
    478           l10n_util::GetStringFUTF16(
    479               IDS_SSL_NONOVERRIDABLE_MORE_INVALID_SP3, url));
    480     } else if (bad_clock) {
    481       load_time_data.SetString("explanationParagraph",
    482                                l10n_util::GetStringFUTF16(
    483                                    IDS_SSL_CLOCK_ERROR_EXPLANATION, url));
    484     } else {
    485       load_time_data.SetString("explanationParagraph",
    486                                l10n_util::GetStringFUTF16(
    487                                    IDS_SSL_NONOVERRIDABLE_MORE, url));
    488     }
    489     load_time_data.SetString(
    490         "primaryButtonText",
    491         l10n_util::GetStringUTF16(IDS_SSL_NONOVERRIDABLE_RELOAD_BUTTON));
    492     // Customize the help link depending on the specific error type.
    493     // Only mark as HSTS if none of the more specific error types apply, and use
    494     // INVALID as a fallback if no other string is appropriate.
    495     load_time_data.SetInteger("errorType", type);
    496     int help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
    497     switch (type) {
    498       case SSLErrorInfo::CERT_REVOKED:
    499         help_string = IDS_SSL_NONOVERRIDABLE_REVOKED;
    500         break;
    501       case SSLErrorInfo::CERT_PINNED_KEY_MISSING:
    502         help_string = IDS_SSL_NONOVERRIDABLE_PINNED;
    503         break;
    504       case SSLErrorInfo::CERT_INVALID:
    505         help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
    506         break;
    507       default:
    508         if (strict_enforcement_)
    509           help_string = IDS_SSL_NONOVERRIDABLE_HSTS;
    510     }
    511     load_time_data.SetString(
    512         "finalParagraph", l10n_util::GetStringFUTF16(help_string, url));
    513   }
    514 
    515   // Set debugging information at the bottom of the warning.
    516   load_time_data.SetString(
    517       "subject", ssl_info_.cert->subject().GetDisplayName());
    518   load_time_data.SetString(
    519       "issuer", ssl_info_.cert->issuer().GetDisplayName());
    520   load_time_data.SetString(
    521       "expirationDate",
    522       base::TimeFormatShortDate(ssl_info_.cert->valid_expiry()));
    523   load_time_data.SetString(
    524       "currentDate", base::TimeFormatShortDate(now));
    525   std::vector<std::string> encoded_chain;
    526   ssl_info_.cert->GetPEMEncodedChain(&encoded_chain);
    527   load_time_data.SetString("pem", JoinString(encoded_chain, std::string()));
    528 
    529   base::StringPiece html(
    530      ResourceBundle::GetSharedInstance().GetRawDataResource(
    531          IRD_SECURITY_INTERSTITIAL_HTML));
    532   webui::UseVersion2 version;
    533   return webui::GetI18nTemplateHtml(html, &load_time_data);
    534 }
    535 
    536 void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
    537   int cert_id = content::CertStore::GetInstance()->StoreCert(
    538       ssl_info_.cert.get(), web_contents_->GetRenderProcessHost()->GetID());
    539   DCHECK(cert_id);
    540 
    541   entry->GetSSL().security_style =
    542       content::SECURITY_STYLE_AUTHENTICATION_BROKEN;
    543   entry->GetSSL().cert_id = cert_id;
    544   entry->GetSSL().cert_status = ssl_info_.cert_status;
    545   entry->GetSSL().security_bits = ssl_info_.security_bits;
    546 }
    547 
    548 // This handles the commands sent from the interstitial JavaScript. They are
    549 // defined in chrome/browser/resources/ssl/ssl_errors_common.js.
    550 // DO NOT reorder or change this logic without also changing the JavaScript!
    551 void SSLBlockingPage::CommandReceived(const std::string& command) {
    552   int cmd = 0;
    553   bool retval = base::StringToInt(command, &cmd);
    554   DCHECK(retval);
    555   switch (cmd) {
    556     case CMD_DONT_PROCEED: {
    557       interstitial_page_->DontProceed();
    558       break;
    559     }
    560     case CMD_PROCEED: {
    561       interstitial_page_->Proceed();
    562       break;
    563     }
    564     case CMD_MORE: {
    565       RecordSSLBlockingPageEventStats(MORE);
    566 #if defined(ENABLE_EXTENSIONS)
    567       if (sampling_event_.get())
    568         sampling_event_->set_has_viewed_details(true);
    569 #endif
    570       break;
    571     }
    572     case CMD_RELOAD: {
    573       // The interstitial can't refresh itself.
    574       web_contents_->GetController().Reload(true);
    575       break;
    576     }
    577     case CMD_HELP: {
    578       content::NavigationController::LoadURLParams help_page_params(
    579           google_util::AppendGoogleLocaleParam(
    580               GURL(kHelpURL), g_browser_process->GetApplicationLocale()));
    581 #if defined(ENABLE_EXTENSIONS)
    582       if (sampling_event_.get())
    583         sampling_event_->set_has_viewed_learn_more(true);
    584 #endif
    585       web_contents_->GetController().LoadURLWithParams(help_page_params);
    586       break;
    587     }
    588     case CMD_CLOCK: {
    589       LaunchDateAndTimeSettings();
    590       break;
    591     }
    592     default: {
    593       NOTREACHED();
    594     }
    595   }
    596 }
    597 
    598 void SSLBlockingPage::OverrideRendererPrefs(
    599       content::RendererPreferences* prefs) {
    600   Profile* profile = Profile::FromBrowserContext(
    601       web_contents_->GetBrowserContext());
    602   renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
    603 }
    604 
    605 void SSLBlockingPage::OnProceed() {
    606   RecordSSLBlockingPageDetailedStats(true,
    607                                      cert_error_,
    608                                      overridable_,
    609                                      internal_,
    610                                      num_visits_,
    611                                      expired_but_previously_allowed_);
    612 #if defined(ENABLE_EXTENSIONS)
    613   // ExperienceSampling: Notify that user decided to proceed.
    614   if (sampling_event_.get())
    615     sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
    616 #endif
    617 
    618   // Accepting the certificate resumes the loading of the page.
    619   NotifyAllowCertificate();
    620 }
    621 
    622 void SSLBlockingPage::OnDontProceed() {
    623   RecordSSLBlockingPageDetailedStats(false,
    624                                      cert_error_,
    625                                      overridable_,
    626                                      internal_,
    627                                      num_visits_,
    628                                      expired_but_previously_allowed_);
    629 #if defined(ENABLE_EXTENSIONS)
    630   // ExperienceSampling: Notify that user decided to not proceed.
    631   // This also occurs if the user navigates away or closes the tab.
    632   if (sampling_event_.get())
    633     sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
    634 #endif
    635   NotifyDenyCertificate();
    636 }
    637 
    638 void SSLBlockingPage::NotifyDenyCertificate() {
    639   // It's possible that callback_ may not exist if the user clicks "Proceed"
    640   // followed by pressing the back button before the interstitial is hidden.
    641   // In that case the certificate will still be treated as allowed.
    642   if (callback_.is_null())
    643     return;
    644 
    645   callback_.Run(false);
    646   callback_.Reset();
    647 }
    648 
    649 void SSLBlockingPage::NotifyAllowCertificate() {
    650   DCHECK(!callback_.is_null());
    651 
    652   callback_.Run(true);
    653   callback_.Reset();
    654 }
    655 
    656 // static
    657 void SSLBlockingPage::SetExtraInfo(
    658     base::DictionaryValue* strings,
    659     const std::vector<base::string16>& extra_info) {
    660   DCHECK_LT(extra_info.size(), 5U);  // We allow 5 paragraphs max.
    661   const char* keys[5] = {
    662       "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
    663   };
    664   int i;
    665   for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
    666     strings->SetString(keys[i], extra_info[i]);
    667   }
    668   for (; i < 5; i++) {
    669     strings->SetString(keys[i], std::string());
    670   }
    671 }
    672 
    673 void SSLBlockingPage::OnGotHistoryCount(bool success,
    674                                         int num_visits,
    675                                         base::Time first_visit) {
    676   num_visits_ = num_visits;
    677 }
    678