OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ssl/ssl_error_handler.h" | 5 #include "chrome/browser/ssl/ssl_error_handler.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 #include <unordered_set> | 8 #include <unordered_set> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
12 #include "base/feature_list.h" | 12 #include "base/feature_list.h" |
13 #include "base/files/file_util.h" | 13 #include "base/files/file_util.h" |
14 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" |
15 #include "base/macros.h" | 15 #include "base/macros.h" |
16 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
17 #include "base/metrics/histogram_macros.h" | 17 #include "base/metrics/histogram_macros.h" |
18 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
19 #include "base/time/clock.h" | 19 #include "base/time/clock.h" |
20 #include "base/time/time.h" | 20 #include "base/time/time.h" |
21 #include "chrome/browser/browser_process.h" | 21 #include "chrome/browser/browser_process.h" |
22 #include "chrome/browser/profiles/profile.h" | 22 #include "chrome/browser/profiles/profile.h" |
23 #include "chrome/browser/ssl/bad_clock_blocking_page.h" | 23 #include "chrome/browser/ssl/bad_clock_blocking_page.h" |
24 #include "chrome/browser/ssl/ssl_blocking_page.h" | 24 #include "chrome/browser/ssl/ssl_blocking_page.h" |
25 #include "chrome/browser/ssl/ssl_cert_reporter.h" | 25 #include "chrome/browser/ssl/ssl_cert_reporter.h" |
26 #include "chrome/browser/ssl/ssl_error_assistant.pb.h" | 26 #include "chrome/browser/ssl/ssl_error_assistant.pb.h" |
27 #include "chrome/browser/ssl/superfish_blocking_page.h" | |
27 #include "chrome/common/features.h" | 28 #include "chrome/common/features.h" |
28 #include "chrome/grit/browser_resources.h" | 29 #include "chrome/grit/browser_resources.h" |
29 #include "components/network_time/network_time_tracker.h" | 30 #include "components/network_time/network_time_tracker.h" |
30 #include "components/ssl_errors/error_classification.h" | 31 #include "components/ssl_errors/error_classification.h" |
31 #include "components/ssl_errors/error_info.h" | 32 #include "components/ssl_errors/error_info.h" |
32 #include "content/public/browser/browser_thread.h" | 33 #include "content/public/browser/browser_thread.h" |
33 #include "content/public/browser/navigation_handle.h" | 34 #include "content/public/browser/navigation_handle.h" |
34 #include "content/public/browser/notification_service.h" | 35 #include "content/public/browser/notification_service.h" |
35 #include "content/public/browser/notification_source.h" | 36 #include "content/public/browser/notification_source.h" |
36 #include "content/public/browser/render_frame_host.h" | 37 #include "content/public/browser/render_frame_host.h" |
(...skipping 15 matching lines...) Expand all Loading... | |
52 const base::Feature kCaptivePortalInterstitial{ | 53 const base::Feature kCaptivePortalInterstitial{ |
53 "CaptivePortalInterstitial", base::FEATURE_ENABLED_BY_DEFAULT}; | 54 "CaptivePortalInterstitial", base::FEATURE_ENABLED_BY_DEFAULT}; |
54 | 55 |
55 const base::Feature kCaptivePortalCertificateList{ | 56 const base::Feature kCaptivePortalCertificateList{ |
56 "CaptivePortalCertificateList", base::FEATURE_DISABLED_BY_DEFAULT}; | 57 "CaptivePortalCertificateList", base::FEATURE_DISABLED_BY_DEFAULT}; |
57 #endif | 58 #endif |
58 | 59 |
59 const base::Feature kSSLCommonNameMismatchHandling{ | 60 const base::Feature kSSLCommonNameMismatchHandling{ |
60 "SSLCommonNameMismatchHandling", base::FEATURE_ENABLED_BY_DEFAULT}; | 61 "SSLCommonNameMismatchHandling", base::FEATURE_ENABLED_BY_DEFAULT}; |
61 | 62 |
63 const base::Feature kSuperfishInterstitial{"SuperfishInterstitial", | |
64 base::FEATURE_DISABLED_BY_DEFAULT}; | |
65 | |
62 // Default delay in milliseconds before displaying the SSL interstitial. | 66 // Default delay in milliseconds before displaying the SSL interstitial. |
63 // This can be changed in tests. | 67 // This can be changed in tests. |
64 // - If there is a name mismatch and a suggested URL available result arrives | 68 // - If there is a name mismatch and a suggested URL available result arrives |
65 // during this time, the user is redirected to the suggester URL. | 69 // during this time, the user is redirected to the suggester URL. |
66 // - If a "captive portal detected" result arrives during this time, | 70 // - If a "captive portal detected" result arrives during this time, |
67 // a captive portal interstitial is displayed. | 71 // a captive portal interstitial is displayed. |
68 // - Otherwise, an SSL interstitial is displayed. | 72 // - Otherwise, an SSL interstitial is displayed. |
69 const int64_t kInterstitialDelayInMilliseconds = 3000; | 73 const int64_t kInterstitialDelayInMilliseconds = 3000; |
70 | 74 |
71 const char kHistogram[] = "interstitial.ssl_error_handler"; | 75 const char kHistogram[] = "interstitial.ssl_error_handler"; |
72 | 76 |
73 // Records an UMA histogram for whether the Superfish SPKI was present in the | 77 bool IsSuperfish(const scoped_refptr<net::X509Certificate>& cert) { |
74 // certificate chain. | 78 // This is the fingerprint of the well-known Superfish certificate at |
75 void RecordSuperfishUMA(const net::HashValueVector& public_key_hashes) { | 79 // https://pastebin.com/WcXv8QcG. Superfish is identified by certificate |
76 // This is the SPKI hash of the well-known Superfish certificate at | 80 // fingerprint rather than SPKI because net::SSLInfo does not guarantee |
77 // https://pastebin.com/WcXv8QcG. | 81 // |public_key_hashes| (the SPKIs) to be populated if the certificate doesn't |
78 const char kSuperfishSPKI[] = | 82 // verify successfully. It so happens that Superfish uses the same certificate |
79 "sha256/S7jzW6HhJvjd4bDEIGJe2G3OYae92tveqauleP8TFF4="; | 83 // universally (not just the same public key), and calculating the fingerprint |
80 net::HashValue superfish_spki_hash_value; | 84 // is more convenient here than calculating the SPKI. |
81 if (!superfish_spki_hash_value.FromString(kSuperfishSPKI)) { | 85 const net::SHA256HashValue kSuperfishFingerprint{ |
82 NOTREACHED(); | 86 {0xB6, 0xFE, 0x91, 0x51, 0x40, 0x2B, 0xAD, 0x1C, 0x06, 0xD7, 0xE6, |
83 } | 87 0x6D, 0xB6, 0x7A, 0x26, 0xAA, 0x73, 0x56, 0xF2, 0xE6, 0xC6, 0x44, |
84 bool found_superfish = false; | 88 0xDB, 0xCF, 0x9F, 0x98, 0x96, 0x8F, 0xF6, 0x32, 0xE1, 0xB7}}; |
85 for (const auto& hash : public_key_hashes) { | 89 for (const net::X509Certificate::OSCertHandle& intermediate : |
86 if (hash == superfish_spki_hash_value) { | 90 cert->GetIntermediateCertificates()) { |
87 found_superfish = true; | 91 net::SHA256HashValue hash = |
88 break; | 92 net::X509Certificate::CalculateFingerprint256(intermediate); |
93 if (hash == kSuperfishFingerprint) { | |
94 return true; | |
89 } | 95 } |
90 } | 96 } |
97 return false; | |
98 } | |
99 | |
100 // Records an UMA histogram for whether the Superfish certificate was present in | |
101 // the certificate chain. | |
102 void RecordSuperfishUMA(const scoped_refptr<net::X509Certificate>& cert) { | |
91 UMA_HISTOGRAM_BOOLEAN("interstitial.ssl_error_handler.superfish", | 103 UMA_HISTOGRAM_BOOLEAN("interstitial.ssl_error_handler.superfish", |
92 found_superfish); | 104 IsSuperfish(cert)); |
93 } | 105 } |
94 | 106 |
95 // Adds a message to console after navigation commits and then, deletes itself. | 107 // Adds a message to console after navigation commits and then, deletes itself. |
96 // Also deletes itself if the navigation is stopped. | 108 // Also deletes itself if the navigation is stopped. |
97 class CommonNameMismatchRedirectObserver | 109 class CommonNameMismatchRedirectObserver |
98 : public content::WebContentsObserver, | 110 : public content::WebContentsObserver, |
99 public content::WebContentsUserData<CommonNameMismatchRedirectObserver> { | 111 public content::WebContentsUserData<CommonNameMismatchRedirectObserver> { |
100 public: | 112 public: |
101 ~CommonNameMismatchRedirectObserver() override {} | 113 ~CommonNameMismatchRedirectObserver() override {} |
102 | 114 |
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
440 std::move(ssl_cert_reporter_), ssl_info_, | 452 std::move(ssl_cert_reporter_), ssl_info_, |
441 callback_)) | 453 callback_)) |
442 ->Show(); | 454 ->Show(); |
443 #else | 455 #else |
444 NOTREACHED(); | 456 NOTREACHED(); |
445 #endif | 457 #endif |
446 } | 458 } |
447 | 459 |
448 void SSLErrorHandlerDelegateImpl::ShowSSLInterstitial() { | 460 void SSLErrorHandlerDelegateImpl::ShowSSLInterstitial() { |
449 // Show SSL blocking page. The interstitial owns the blocking page. | 461 // Show SSL blocking page. The interstitial owns the blocking page. |
450 (SSLBlockingPage::Create(web_contents_, cert_error_, ssl_info_, request_url_, | 462 if (base::FeatureList::IsEnabled(kSuperfishInterstitial) && |
451 options_mask_, base::Time::NowFromSystemTime(), | 463 IsSuperfish(ssl_info_.cert)) { |
452 std::move(ssl_cert_reporter_), callback_)) | 464 (SuperfishBlockingPage::Create(web_contents_, cert_error_, ssl_info_, |
453 ->Show(); | 465 request_url_, options_mask_, |
466 base::Time::NowFromSystemTime(), | |
467 std::move(ssl_cert_reporter_), callback_)) | |
468 ->Show(); | |
meacer
2017/06/22 19:06:18
nit: return early here, and remove the else to get
estark
2017/06/22 22:01:05
n/a
| |
469 } else { | |
470 (SSLBlockingPage::Create(web_contents_, cert_error_, ssl_info_, | |
471 request_url_, options_mask_, | |
472 base::Time::NowFromSystemTime(), | |
473 std::move(ssl_cert_reporter_), callback_)) | |
474 ->Show(); | |
475 } | |
454 } | 476 } |
455 | 477 |
456 void SSLErrorHandlerDelegateImpl::ShowBadClockInterstitial( | 478 void SSLErrorHandlerDelegateImpl::ShowBadClockInterstitial( |
457 const base::Time& now, | 479 const base::Time& now, |
458 ssl_errors::ClockState clock_state) { | 480 ssl_errors::ClockState clock_state) { |
459 // Show bad clock page. The interstitial owns the blocking page. | 481 // Show bad clock page. The interstitial owns the blocking page. |
460 (new BadClockBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_, | 482 (new BadClockBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_, |
461 now, clock_state, std::move(ssl_cert_reporter_), | 483 now, clock_state, std::move(ssl_cert_reporter_), |
462 callback_)) | 484 callback_)) |
463 ->Show(); | 485 ->Show(); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
556 request_url_(request_url), | 578 request_url_(request_url), |
557 callback_(callback), | 579 callback_(callback), |
558 weak_ptr_factory_(this) {} | 580 weak_ptr_factory_(this) {} |
559 | 581 |
560 SSLErrorHandler::~SSLErrorHandler() { | 582 SSLErrorHandler::~SSLErrorHandler() { |
561 } | 583 } |
562 | 584 |
563 void SSLErrorHandler::StartHandlingError() { | 585 void SSLErrorHandler::StartHandlingError() { |
564 RecordUMA(HANDLE_ALL); | 586 RecordUMA(HANDLE_ALL); |
565 | 587 |
566 RecordSuperfishUMA(ssl_info_.public_key_hashes); | 588 RecordSuperfishUMA(ssl_info_.cert); |
567 | 589 |
568 if (ssl_errors::ErrorInfo::NetErrorToErrorType(cert_error_) == | 590 if (ssl_errors::ErrorInfo::NetErrorToErrorType(cert_error_) == |
569 ssl_errors::ErrorInfo::CERT_DATE_INVALID) { | 591 ssl_errors::ErrorInfo::CERT_DATE_INVALID) { |
570 HandleCertDateInvalidError(); | 592 HandleCertDateInvalidError(); |
571 return; | 593 return; |
572 } | 594 } |
573 | 595 |
574 const net::CertStatus non_name_mismatch_errors = | 596 const net::CertStatus non_name_mismatch_errors = |
575 ssl_info_.cert_status ^ net::CERT_STATUS_COMMON_NAME_INVALID; | 597 ssl_info_.cert_status ^ net::CERT_STATUS_COMMON_NAME_INVALID; |
576 const bool only_error_is_name_mismatch = | 598 const bool only_error_is_name_mismatch = |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
795 network_time::NetworkTimeTracker* tracker = | 817 network_time::NetworkTimeTracker* tracker = |
796 g_config.Pointer()->network_time_tracker(); | 818 g_config.Pointer()->network_time_tracker(); |
797 ssl_errors::ClockState clock_state = ssl_errors::GetClockState(now, tracker); | 819 ssl_errors::ClockState clock_state = ssl_errors::GetClockState(now, tracker); |
798 if (clock_state == ssl_errors::CLOCK_STATE_FUTURE || | 820 if (clock_state == ssl_errors::CLOCK_STATE_FUTURE || |
799 clock_state == ssl_errors::CLOCK_STATE_PAST) { | 821 clock_state == ssl_errors::CLOCK_STATE_PAST) { |
800 ShowBadClockInterstitial(now, clock_state); | 822 ShowBadClockInterstitial(now, clock_state); |
801 return; // |this| is deleted after showing the interstitial. | 823 return; // |this| is deleted after showing the interstitial. |
802 } | 824 } |
803 ShowSSLInterstitial(); | 825 ShowSSLInterstitial(); |
804 } | 826 } |
OLD | NEW |