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/i18n/rtl.h" 8 #include "base/metrics/histogram.h" 9 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_piece.h" 11 #include "base/strings/stringprintf.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/values.h" 14 #include "chrome/browser/history/history_service_factory.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/renderer_preferences_util.h" 17 #include "chrome/browser/ssl/ssl_error_info.h" 18 #include "chrome/browser/ui/browser.h" 19 #include "chrome/browser/ui/browser_finder.h" 20 #include "content/public/browser/cert_store.h" 21 #include "content/public/browser/interstitial_page.h" 22 #include "content/public/browser/navigation_controller.h" 23 #include "content/public/browser/navigation_entry.h" 24 #include "content/public/browser/notification_service.h" 25 #include "content/public/browser/notification_types.h" 26 #include "content/public/browser/render_process_host.h" 27 #include "content/public/browser/render_view_host.h" 28 #include "content/public/browser/web_contents.h" 29 #include "content/public/common/ssl_status.h" 30 #include "grit/app_locale_settings.h" 31 #include "grit/browser_resources.h" 32 #include "grit/generated_resources.h" 33 #include "net/base/hash_value.h" 34 #include "net/base/net_errors.h" 35 #include "net/base/net_util.h" 36 #include "ui/base/l10n/l10n_util.h" 37 #include "ui/base/resource/resource_bundle.h" 38 #include "ui/base/webui/jstemplate_builder.h" 39 40 #if defined(OS_WIN) 41 #include "base/win/windows_version.h" 42 #endif 43 44 using base::TimeTicks; 45 using content::InterstitialPage; 46 using content::NavigationController; 47 using content::NavigationEntry; 48 49 namespace { 50 51 // These represent the commands sent by ssl_roadblock.html. 52 enum SSLBlockingPageCommands { 53 CMD_DONT_PROCEED, 54 CMD_PROCEED, 55 CMD_MORE, 56 CMD_RELOAD, 57 }; 58 59 // Events for UMA. 60 enum SSLBlockingPageEvent { 61 SHOW_ALL, 62 SHOW_OVERRIDABLE, 63 PROCEED_OVERRIDABLE, 64 PROCEED_NAME, 65 PROCEED_DATE, 66 PROCEED_AUTHORITY, 67 DONT_PROCEED_OVERRIDABLE, 68 DONT_PROCEED_NAME, 69 DONT_PROCEED_DATE, 70 DONT_PROCEED_AUTHORITY, 71 MORE, 72 SHOW_UNDERSTAND, // Used by the summer 2013 Finch trial. Deprecated. 73 SHOW_INTERNAL_HOSTNAME, 74 PROCEED_INTERNAL_HOSTNAME, 75 SHOW_NEW_SITE, 76 PROCEED_NEW_SITE, 77 UNUSED_BLOCKING_PAGE_EVENT, 78 }; 79 80 void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event) { 81 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl", 82 event, 83 UNUSED_BLOCKING_PAGE_EVENT); 84 } 85 86 void RecordSSLBlockingPageDetailedStats( 87 bool proceed, 88 int cert_error, 89 bool overridable, 90 bool internal, 91 int num_visits) { 92 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type", 93 SSLErrorInfo::NetErrorToErrorType(cert_error), SSLErrorInfo::END_OF_ENUM); 94 if (!overridable) { 95 // Overridable is false if the user didn't have any option except to turn 96 // back. If that's the case, don't record some of the metrics. 97 return; 98 } 99 if (num_visits == 0) 100 RecordSSLBlockingPageEventStats(SHOW_NEW_SITE); 101 if (proceed) { 102 RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE); 103 if (internal) 104 RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME); 105 if (num_visits == 0) 106 RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE); 107 } else if (!proceed) { 108 RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE); 109 } 110 SSLErrorInfo::ErrorType type = SSLErrorInfo::NetErrorToErrorType(cert_error); 111 switch (type) { 112 case SSLErrorInfo::CERT_COMMON_NAME_INVALID: { 113 if (proceed) 114 RecordSSLBlockingPageEventStats(PROCEED_NAME); 115 else 116 RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME); 117 break; 118 } 119 case SSLErrorInfo::CERT_DATE_INVALID: { 120 if (proceed) 121 RecordSSLBlockingPageEventStats(PROCEED_DATE); 122 else 123 RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE); 124 break; 125 } 126 case SSLErrorInfo::CERT_AUTHORITY_INVALID: { 127 if (proceed) 128 RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY); 129 else 130 RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY); 131 break; 132 } 133 default: { 134 break; 135 } 136 } 137 } 138 139 } // namespace 140 141 // Note that we always create a navigation entry with SSL errors. 142 // No error happening loading a sub-resource triggers an interstitial so far. 143 SSLBlockingPage::SSLBlockingPage( 144 content::WebContents* web_contents, 145 int cert_error, 146 const net::SSLInfo& ssl_info, 147 const GURL& request_url, 148 bool overridable, 149 bool strict_enforcement, 150 const base::Callback<void(bool)>& callback) 151 : callback_(callback), 152 web_contents_(web_contents), 153 cert_error_(cert_error), 154 ssl_info_(ssl_info), 155 request_url_(request_url), 156 overridable_(overridable), 157 strict_enforcement_(strict_enforcement), 158 internal_(false), 159 num_visits_(-1) { 160 // For UMA stats. 161 if (net::IsHostnameNonUnique(request_url_.HostNoBrackets())) 162 internal_ = true; 163 RecordSSLBlockingPageEventStats(SHOW_ALL); 164 if (overridable_ && !strict_enforcement_) { 165 RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE); 166 if (internal_) 167 RecordSSLBlockingPageEventStats(SHOW_INTERNAL_HOSTNAME); 168 HistoryService* history_service = HistoryServiceFactory::GetForProfile( 169 Profile::FromBrowserContext(web_contents->GetBrowserContext()), 170 Profile::EXPLICIT_ACCESS); 171 if (history_service) { 172 history_service->GetVisibleVisitCountToHost( 173 request_url_, 174 &request_consumer_, 175 base::Bind(&SSLBlockingPage::OnGotHistoryCount, 176 base::Unretained(this))); 177 } 178 } 179 180 interstitial_page_ = InterstitialPage::Create( 181 web_contents_, true, request_url, this); 182 interstitial_page_->Show(); 183 } 184 185 SSLBlockingPage::~SSLBlockingPage() { 186 if (!callback_.is_null()) { 187 RecordSSLBlockingPageDetailedStats(false, 188 cert_error_, 189 overridable_ && !strict_enforcement_, 190 internal_, 191 num_visits_); 192 // The page is closed without the user having chosen what to do, default to 193 // deny. 194 NotifyDenyCertificate(); 195 } 196 } 197 198 std::string SSLBlockingPage::GetHTMLContents() { 199 DictionaryValue strings; 200 int resource_id; 201 if (overridable_ && !strict_enforcement_) { 202 // Let's build the overridable error page. 203 SSLErrorInfo error_info = 204 SSLErrorInfo::CreateError( 205 SSLErrorInfo::NetErrorToErrorType(cert_error_), 206 ssl_info_.cert.get(), 207 request_url_); 208 209 resource_id = IDR_SSL_ROAD_BLOCK_HTML; 210 strings.SetString("headLine", error_info.title()); 211 strings.SetString("description", error_info.details()); 212 strings.SetString("moreInfoTitle", 213 l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE)); 214 SetExtraInfo(&strings, error_info.extra_information()); 215 216 strings.SetString( 217 "exit", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_EXIT)); 218 strings.SetString( 219 "title", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_TITLE)); 220 strings.SetString( 221 "proceed", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_PROCEED)); 222 strings.SetString( 223 "reasonForNotProceeding", l10n_util::GetStringUTF16( 224 IDS_SSL_OVERRIDABLE_PAGE_SHOULD_NOT_PROCEED)); 225 strings.SetString("errorType", "overridable"); 226 strings.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr"); 227 } else { 228 // Let's build the blocking error page. 229 resource_id = IDR_SSL_BLOCKING_HTML; 230 231 // Strings that are not dependent on the URL. 232 strings.SetString( 233 "title", l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE)); 234 strings.SetString( 235 "reloadMsg", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_RELOAD)); 236 strings.SetString( 237 "more", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_MORE)); 238 strings.SetString( 239 "less", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_LESS)); 240 strings.SetString( 241 "moreTitle", 242 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TITLE)); 243 strings.SetString( 244 "techTitle", 245 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TECH_TITLE)); 246 247 // Strings that are dependent on the URL. 248 base::string16 url(ASCIIToUTF16(request_url_.host())); 249 bool rtl = base::i18n::IsRTL(); 250 strings.SetString("textDirection", rtl ? "rtl" : "ltr"); 251 if (rtl) 252 base::i18n::WrapStringWithLTRFormatting(&url); 253 strings.SetString( 254 "headline", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HEADLINE, 255 url.c_str())); 256 strings.SetString( 257 "message", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_BODY_TEXT, 258 url.c_str())); 259 strings.SetString( 260 "moreMessage", 261 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TEXT, 262 url.c_str())); 263 strings.SetString("reloadUrl", request_url_.spec()); 264 265 // Strings that are dependent on the error type. 266 SSLErrorInfo::ErrorType type = 267 SSLErrorInfo::NetErrorToErrorType(cert_error_); 268 base::string16 errorType; 269 if (type == SSLErrorInfo::CERT_REVOKED) { 270 errorType = base::string16(ASCIIToUTF16("Key revocation")); 271 strings.SetString( 272 "failure", 273 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_REVOKED)); 274 } else if (type == SSLErrorInfo::CERT_INVALID) { 275 errorType = base::string16(ASCIIToUTF16("Malformed certificate")); 276 strings.SetString( 277 "failure", 278 l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_FORMATTED)); 279 } else if (type == SSLErrorInfo::CERT_PINNED_KEY_MISSING) { 280 errorType = base::string16(ASCIIToUTF16("Certificate pinning failure")); 281 strings.SetString( 282 "failure", 283 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_PINNING, 284 url.c_str())); 285 } else if (type == SSLErrorInfo::CERT_WEAK_KEY_DH) { 286 errorType = base::string16(ASCIIToUTF16("Weak DH public key")); 287 strings.SetString( 288 "failure", 289 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_WEAK_DH, 290 url.c_str())); 291 } else { 292 // HSTS failure. 293 errorType = base::string16(ASCIIToUTF16("HSTS failure")); 294 strings.SetString( 295 "failure", 296 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HSTS, url.c_str())); 297 } 298 if (rtl) 299 base::i18n::WrapStringWithLTRFormatting(&errorType); 300 strings.SetString( 301 "errorType", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ERROR, 302 errorType.c_str())); 303 304 // Strings that display the invalid cert. 305 base::string16 subject( 306 ASCIIToUTF16(ssl_info_.cert->subject().GetDisplayName())); 307 base::string16 issuer( 308 ASCIIToUTF16(ssl_info_.cert->issuer().GetDisplayName())); 309 std::string hashes; 310 for (std::vector<net::HashValue>::iterator it = 311 ssl_info_.public_key_hashes.begin(); 312 it != ssl_info_.public_key_hashes.end(); 313 ++it) { 314 base::StringAppendF(&hashes, "%s ", it->ToString().c_str()); 315 } 316 base::string16 fingerprint(ASCIIToUTF16(hashes)); 317 if (rtl) { 318 // These are always going to be LTR. 319 base::i18n::WrapStringWithLTRFormatting(&subject); 320 base::i18n::WrapStringWithLTRFormatting(&issuer); 321 base::i18n::WrapStringWithLTRFormatting(&fingerprint); 322 } 323 strings.SetString( 324 "subject", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_SUBJECT, 325 subject.c_str())); 326 strings.SetString( 327 "issuer", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ISSUER, 328 issuer.c_str())); 329 strings.SetString( 330 "fingerprint", 331 l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HASHES, 332 fingerprint.c_str())); 333 } 334 335 base::StringPiece html( 336 ResourceBundle::GetSharedInstance().GetRawDataResource( 337 resource_id)); 338 return webui::GetI18nTemplateHtml(html, &strings); 339 } 340 341 void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) { 342 int cert_id = content::CertStore::GetInstance()->StoreCert( 343 ssl_info_.cert.get(), web_contents_->GetRenderProcessHost()->GetID()); 344 345 entry->GetSSL().security_style = 346 content::SECURITY_STYLE_AUTHENTICATION_BROKEN; 347 entry->GetSSL().cert_id = cert_id; 348 entry->GetSSL().cert_status = ssl_info_.cert_status; 349 entry->GetSSL().security_bits = ssl_info_.security_bits; 350 #if !defined(OS_ANDROID) 351 Browser* browser = chrome::FindBrowserWithWebContents(web_contents_); 352 if (browser) 353 browser->VisibleSSLStateChanged(web_contents_); 354 #endif // !defined(OS_ANDROID) 355 } 356 357 // Matches events defined in ssl_error.html and ssl_roadblock.html. 358 void SSLBlockingPage::CommandReceived(const std::string& command) { 359 int cmd = atoi(command.c_str()); 360 if (cmd == CMD_DONT_PROCEED) { 361 interstitial_page_->DontProceed(); 362 } else if (cmd == CMD_PROCEED) { 363 interstitial_page_->Proceed(); 364 } else if (cmd == CMD_MORE) { 365 RecordSSLBlockingPageEventStats(MORE); 366 } else if (cmd == CMD_RELOAD) { 367 // The interstitial can't refresh itself. 368 content::NavigationController* controller = &web_contents_->GetController(); 369 controller->Reload(true); 370 } 371 } 372 373 void SSLBlockingPage::OverrideRendererPrefs( 374 content::RendererPreferences* prefs) { 375 Profile* profile = Profile::FromBrowserContext( 376 web_contents_->GetBrowserContext()); 377 renderer_preferences_util::UpdateFromSystemSettings(prefs, profile); 378 } 379 380 void SSLBlockingPage::OnProceed() { 381 RecordSSLBlockingPageDetailedStats(true, 382 cert_error_, 383 overridable_ && !strict_enforcement_, 384 internal_, 385 num_visits_); 386 // Accepting the certificate resumes the loading of the page. 387 NotifyAllowCertificate(); 388 } 389 390 void SSLBlockingPage::OnDontProceed() { 391 RecordSSLBlockingPageDetailedStats(false, 392 cert_error_, 393 overridable_ && !strict_enforcement_, 394 internal_, 395 num_visits_); 396 NotifyDenyCertificate(); 397 } 398 399 void SSLBlockingPage::NotifyDenyCertificate() { 400 // It's possible that callback_ may not exist if the user clicks "Proceed" 401 // followed by pressing the back button before the interstitial is hidden. 402 // In that case the certificate will still be treated as allowed. 403 if (callback_.is_null()) 404 return; 405 406 callback_.Run(false); 407 callback_.Reset(); 408 } 409 410 void SSLBlockingPage::NotifyAllowCertificate() { 411 DCHECK(!callback_.is_null()); 412 413 callback_.Run(true); 414 callback_.Reset(); 415 } 416 417 // static 418 void SSLBlockingPage::SetExtraInfo( 419 DictionaryValue* strings, 420 const std::vector<base::string16>& extra_info) { 421 DCHECK_LT(extra_info.size(), 5U); // We allow 5 paragraphs max. 422 const char* keys[5] = { 423 "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5" 424 }; 425 int i; 426 for (i = 0; i < static_cast<int>(extra_info.size()); i++) { 427 strings->SetString(keys[i], extra_info[i]); 428 } 429 for (; i < 5; i++) { 430 strings->SetString(keys[i], std::string()); 431 } 432 } 433 434 void SSLBlockingPage::OnGotHistoryCount(HistoryService::Handle handle, 435 bool success, 436 int num_visits, 437 base::Time first_visit) { 438 num_visits_ = num_visits; 439 } 440