Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2458)

Unified Diff: chrome/browser/ssl/ssl_error_handler.cc

Issue 2620203003: Add initial version of captive portal list checking. (Closed)
Patch Set: Fix Android tests Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ssl/ssl_error_handler.h ('k') | chrome/browser/ssl/ssl_error_handler_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ssl/ssl_error_handler.cc
diff --git a/chrome/browser/ssl/ssl_error_handler.cc b/chrome/browser/ssl/ssl_error_handler.cc
index 8ddc06febd5a7e15807327dca90f85aae9b8429d..5cbf4bec5bed7ce089f333d7b4ed0b15800d0614 100644
--- a/chrome/browser/ssl/ssl_error_handler.cc
+++ b/chrome/browser/ssl/ssl_error_handler.cc
@@ -5,12 +5,15 @@
#include "chrome/browser/ssl/ssl_error_handler.h"
#include <stdint.h>
+#include <unordered_set>
#include <utility>
#include "base/callback_helpers.h"
#include "base/feature_list.h"
+#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
#include "base/threading/non_thread_safe.h"
@@ -21,22 +24,27 @@
#include "chrome/browser/ssl/bad_clock_blocking_page.h"
#include "chrome/browser/ssl/ssl_blocking_page.h"
#include "chrome/browser/ssl/ssl_cert_reporter.h"
+#include "chrome/browser/ssl/ssl_error_assistant.pb.h"
#include "chrome/common/features.h"
+#include "chrome/grit/browser_resources.h"
#include "components/network_time/network_time_tracker.h"
#include "components/ssl_errors/error_classification.h"
#include "components/ssl_errors/error_info.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "net/base/net_errors.h"
+#include "ui/base/resource/resource_bundle.h"
#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
#include "chrome/browser/captive_portal/captive_portal_service.h"
#include "chrome/browser/captive_portal/captive_portal_service_factory.h"
#include "chrome/browser/captive_portal/captive_portal_tab_helper.h"
#include "chrome/browser/ssl/captive_portal_blocking_page.h"
+#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
#endif
namespace {
@@ -44,13 +52,14 @@ namespace {
#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
const base::Feature kCaptivePortalInterstitial{
"CaptivePortalInterstitial", base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kCaptivePortalCertificateList{
+ "CaptivePortalCertificateList", base::FEATURE_DISABLED_BY_DEFAULT};
#endif
const base::Feature kSSLCommonNameMismatchHandling{
"SSLCommonNameMismatchHandling", base::FEATURE_ENABLED_BY_DEFAULT};
-const char kHistogram[] = "interstitial.ssl_error_handler";
-
// Default delay in milliseconds before displaying the SSL interstitial.
// This can be changed in tests.
// - If there is a name mismatch and a suggested URL available result arrives
@@ -60,6 +69,8 @@ const char kHistogram[] = "interstitial.ssl_error_handler";
// - Otherwise, an SSL interstitial is displayed.
const int64_t kInterstitialDelayInMilliseconds = 3000;
+const char kHistogram[] = "interstitial.ssl_error_handler";
+
// Adds a message to console after navigation commits and then, deletes itself.
// Also deletes itself if the navigation is stopped.
class CommonNameMismatchRedirectObserver
@@ -126,6 +137,28 @@ void RecordUMA(SSLErrorHandler::UMAEvent event) {
bool IsCaptivePortalInterstitialEnabled() {
return base::FeatureList::IsEnabled(kCaptivePortalInterstitial);
}
+
+// Reads the SSL error assistant configuration from the resource bundle.
+bool ReadErrorAssistantProtoFromResourceBundle(
+ chrome_browser_ssl::SSLErrorAssistantConfig* proto) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ DCHECK(proto);
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+ base::StringPiece data =
+ bundle.GetRawDataResource(IDR_SSL_ERROR_ASSISTANT_PB);
+ google::protobuf::io::ArrayInputStream stream(data.data(), data.size());
+ return proto->ParseFromZeroCopyStream(&stream);
+}
+
+std::unique_ptr<std::unordered_set<std::string>> LoadCaptivePortalCertHashes(
+ const chrome_browser_ssl::SSLErrorAssistantConfig& proto) {
+ auto hashes = base::MakeUnique<std::unordered_set<std::string>>();
+ for (const chrome_browser_ssl::CaptivePortalCert& cert :
+ proto.captive_portal_cert()) {
+ hashes.get()->insert(cert.sha256_hash());
+ }
+ return hashes;
+}
#endif
bool IsSSLCommonNameMismatchHandlingEnabled() {
@@ -142,6 +175,15 @@ class ConfigSingleton : public base::NonThreadSafe {
base::Clock* clock() const;
network_time::NetworkTimeTracker* network_time_tracker() const;
+#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
+ // Returns true if any of the SHA256 hashes in |ssl_info| is of a captive
+ // portal certificate. The set of captive portal hashes is loaded on first
+ // use.
+ bool IsKnownCaptivePortalCert(const net::SSLInfo& ssl_info);
+#endif
+
+ // Testing methods:
+ void ResetForTesting();
void SetInterstitialDelayForTesting(const base::TimeDelta& delay);
void SetTimerStartedCallbackForTesting(
SSLErrorHandler::TimerStartedCallback* callback);
@@ -149,6 +191,11 @@ class ConfigSingleton : public base::NonThreadSafe {
void SetNetworkTimeTrackerForTesting(
network_time::NetworkTimeTracker* tracker);
+#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
+ void SetErrorAssistantProtoForTesting(
+ const chrome_browser_ssl::SSLErrorAssistantConfig& error_assistant_proto);
+#endif
+
private:
base::TimeDelta interstitial_delay_;
@@ -161,6 +208,13 @@ class ConfigSingleton : public base::NonThreadSafe {
base::Clock* testing_clock_ = nullptr;
network_time::NetworkTimeTracker* network_time_tracker_ = nullptr;
+
+#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
+ // SPKI hashes belonging to certs treated as captive portals. Null until the
+ // first time IsKnownCaptivePortalCert() or SetErrorAssistantProtoForTesting()
+ // is called.
+ std::unique_ptr<std::unordered_set<std::string>> captive_portal_spki_hashes_;
+#endif
};
ConfigSingleton::ConfigSingleton()
@@ -187,6 +241,17 @@ base::Clock* ConfigSingleton::clock() const {
return testing_clock_;
}
+void ConfigSingleton::ResetForTesting() {
+ interstitial_delay_ =
+ base::TimeDelta::FromMilliseconds(kInterstitialDelayInMilliseconds);
+ timer_started_callback_ = nullptr;
+ network_time_tracker_ = nullptr;
+ testing_clock_ = nullptr;
+#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
+ captive_portal_spki_hashes_.reset();
+#endif
+}
+
void ConfigSingleton::SetInterstitialDelayForTesting(
const base::TimeDelta& delay) {
interstitial_delay_ = delay;
@@ -207,6 +272,36 @@ void ConfigSingleton::SetNetworkTimeTrackerForTesting(
network_time_tracker_ = tracker;
}
+#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
+void ConfigSingleton::SetErrorAssistantProtoForTesting(
+ const chrome_browser_ssl::SSLErrorAssistantConfig& error_assistant_proto) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ DCHECK(!captive_portal_spki_hashes_);
+ captive_portal_spki_hashes_ =
+ LoadCaptivePortalCertHashes(error_assistant_proto);
+}
+
+bool ConfigSingleton::IsKnownCaptivePortalCert(const net::SSLInfo& ssl_info) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ if (!captive_portal_spki_hashes_) {
+ chrome_browser_ssl::SSLErrorAssistantConfig proto;
+ CHECK(ReadErrorAssistantProtoFromResourceBundle(&proto));
+ captive_portal_spki_hashes_ = LoadCaptivePortalCertHashes(proto);
+ }
+
+ for (const net::HashValue& hash_value : ssl_info.public_key_hashes) {
+ if (hash_value.tag != net::HASH_VALUE_SHA256) {
+ continue;
+ }
+ if (captive_portal_spki_hashes_->find(hash_value.ToString()) !=
+ captive_portal_spki_hashes_->end()) {
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
class SSLErrorHandlerDelegateImpl : public SSLErrorHandler::Delegate {
public:
SSLErrorHandlerDelegateImpl(
@@ -365,6 +460,11 @@ void SSLErrorHandler::HandleSSLError(
}
// static
+void SSLErrorHandler::ResetConfigForTesting() {
+ g_config.Pointer()->ResetForTesting();
+}
+
+// static
void SSLErrorHandler::SetInterstitialDelayForTesting(
const base::TimeDelta& delay) {
g_config.Pointer()->SetInterstitialDelayForTesting(delay);
@@ -396,6 +496,13 @@ bool SSLErrorHandler::IsTimerRunningForTesting() const {
return timer_.IsRunning();
}
+void SSLErrorHandler::SetErrorAssistantProtoForTesting(
+ const chrome_browser_ssl::SSLErrorAssistantConfig& config_proto) {
+#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
+ g_config.Pointer()->SetErrorAssistantProtoForTesting(config_proto);
+#endif
+}
+
SSLErrorHandler::SSLErrorHandler(
std::unique_ptr<Delegate> delegate,
content::WebContents* web_contents,
@@ -426,6 +533,17 @@ void SSLErrorHandler::StartHandlingError() {
return;
}
+#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
+ if (base::FeatureList::IsEnabled(kCaptivePortalCertificateList) &&
+ cert_error_ == net::ERR_CERT_COMMON_NAME_INVALID &&
+ g_config.Pointer()->IsKnownCaptivePortalCert(ssl_info_)) {
+ RecordUMA(CAPTIVE_PORTAL_CERT_FOUND);
+ ShowCaptivePortalInterstitial(
+ GURL(captive_portal::CaptivePortalDetector::kDefaultURL));
+ return;
+ }
+#endif
+
std::vector<std::string> dns_names;
ssl_info_.cert->GetDNSNames(&dns_names);
DCHECK(!dns_names.empty());
« no previous file with comments | « chrome/browser/ssl/ssl_error_handler.h ('k') | chrome/browser/ssl/ssl_error_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698