From c6881fe145376e2720d292a9a9e15c6af5ca565a Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Fri, 18 Nov 2016 16:11:38 -0500 Subject: [PATCH] Add option to enable/disable net security expiration (issue #1994) - Net security (CT, HSTS) expiration based on build age is now disabled by default. - Add new enable_net_security_expiration option to CefSettings and CefRequestContextSettings. --- include/internal/cef_types.h | 24 ++++ include/internal/cef_types_wrappers.h | 4 + libcef/browser/context.cc | 3 + .../net/url_request_context_getter_impl.cc | 15 ++- libcef/common/cef_switches.cc | 3 + libcef/common/cef_switches.h | 1 + patch/patch.cfg | 6 + .../net_security_expiration_1994.patch | 106 ++++++++++++++++++ 8 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 patch/patches/net_security_expiration_1994.patch diff --git a/include/internal/cef_types.h b/include/internal/cef_types.h index 73dccdeef..6201a47be 100644 --- a/include/internal/cef_types.h +++ b/include/internal/cef_types.h @@ -376,6 +376,19 @@ typedef struct _cef_settings_t { /// int ignore_certificate_errors; + /// + // Set to true (1) to enable date-based expiration of built in network + // security information (i.e. certificate transparency logs, HSTS preloading + // and pinning information). Enabling this option improves network security + // but may cause HTTPS load failures when using CEF binaries built more than + // 10 weeks in the past. See https://www.certificate-transparency.org/ and + // https://www.chromium.org/hsts for details. Also configurable using the + // "enable-net-security-expiration" command-line switch. Can be overridden for + // individual CefRequestContext instances via the + // CefRequestContextSettings.enable_net_security_expiration value. + /// + int enable_net_security_expiration; + /// // Opaque background color used for accelerated content. By default the // background color will be white. Only the RGB compontents of the specified @@ -443,6 +456,17 @@ typedef struct _cef_request_context_settings_t { /// int ignore_certificate_errors; + /// + // Set to true (1) to enable date-based expiration of built in network + // security information (i.e. certificate transparency logs, HSTS preloading + // and pinning information). Enabling this option improves network security + // but may cause HTTPS load failures when using CEF binaries built more than + // 10 weeks in the past. See https://www.certificate-transparency.org/ and + // https://www.chromium.org/hsts for details. Can be set globally using the + // CefSettings.enable_net_security_expiration value. + /// + int enable_net_security_expiration; + /// // Comma delimited ordered list of language codes without any whitespace that // will be used in the "Accept-Language" HTTP header. Can be set globally diff --git a/include/internal/cef_types_wrappers.h b/include/internal/cef_types_wrappers.h index 425481692..bbe348dfc 100644 --- a/include/internal/cef_types_wrappers.h +++ b/include/internal/cef_types_wrappers.h @@ -607,6 +607,8 @@ struct CefSettingsTraits { target->uncaught_exception_stack_size = src->uncaught_exception_stack_size; target->context_safety_implementation = src->context_safety_implementation; target->ignore_certificate_errors = src->ignore_certificate_errors; + target->enable_net_security_expiration = + src->enable_net_security_expiration; target->background_color = src->background_color; cef_string_set(src->accept_language_list.str, @@ -639,6 +641,8 @@ struct CefRequestContextSettingsTraits { target->persist_session_cookies = src->persist_session_cookies; target->persist_user_preferences = src->persist_user_preferences; target->ignore_certificate_errors = src->ignore_certificate_errors; + target->enable_net_security_expiration = + src->enable_net_security_expiration; cef_string_set(src->accept_language_list.str, src->accept_language_list.length, &target->accept_language_list, copy); } diff --git a/libcef/browser/context.cc b/libcef/browser/context.cc index d8930b57b..d8247aaf5 100644 --- a/libcef/browser/context.cc +++ b/libcef/browser/context.cc @@ -385,6 +385,9 @@ void CefContext::PopulateRequestContextSettings( settings->ignore_certificate_errors = settings_.ignore_certificate_errors || command_line->HasSwitch(switches::kIgnoreCertificateErrors); + settings->enable_net_security_expiration = + settings_.enable_net_security_expiration || + command_line->HasSwitch(switches::kEnableNetSecurityExpiration); CefString(&settings->accept_language_list) = CefString(&settings_.accept_language_list); } diff --git a/libcef/browser/net/url_request_context_getter_impl.cc b/libcef/browser/net/url_request_context_getter_impl.cc index d0de4874c..1235dd9d3 100644 --- a/libcef/browser/net/url_request_context_getter_impl.cc +++ b/libcef/browser/net/url_request_context_getter_impl.cc @@ -223,8 +223,12 @@ net::URLRequestContext* CefURLRequestContextGetterImpl::GetURLRequestContext() { storage_->set_host_resolver( net::HostResolver::CreateDefaultResolver(net_log_)); storage_->set_cert_verifier(net::CertVerifier::CreateDefault()); - storage_->set_transport_security_state( - base::WrapUnique(new net::TransportSecurityState)); + + std::unique_ptr transport_security_state( + new net::TransportSecurityState); + transport_security_state->set_enforce_net_security_expiration( + settings_.enable_net_security_expiration ? true : false); + storage_->set_transport_security_state(std::move(transport_security_state)); std::vector> ct_logs( net::ct::CreateLogVerifiersForKnownLogs()); @@ -233,8 +237,11 @@ net::URLRequestContext* CefURLRequestContextGetterImpl::GetURLRequestContext() { ct_verifier->AddLogs(ct_logs); storage_->set_cert_transparency_verifier(std::move(ct_verifier)); - storage_->set_ct_policy_enforcer( - base::WrapUnique(new net::CTPolicyEnforcer)); + std::unique_ptr ct_policy_enforcer( + new net::CTPolicyEnforcer); + ct_policy_enforcer->set_enforce_net_security_expiration( + settings_.enable_net_security_expiration ? true : false); + storage_->set_ct_policy_enforcer(std::move(ct_policy_enforcer)); std::unique_ptr system_proxy_service = ProxyServiceFactory::CreateProxyService( diff --git a/libcef/common/cef_switches.cc b/libcef/common/cef_switches.cc index d9ef2039d..492175d74 100644 --- a/libcef/common/cef_switches.cc +++ b/libcef/common/cef_switches.cc @@ -122,4 +122,7 @@ const char kPluginPolicy_Block[] = "block"; // Expose preferences used only by unit tests. const char kEnablePreferenceTesting[] = "enable-preference-testing"; +// Enable date-based expiration of built in network security information. +const char kEnableNetSecurityExpiration[] = "enable-net-security-expiration"; + } // namespace switches diff --git a/libcef/common/cef_switches.h b/libcef/common/cef_switches.h index 6ebc943f8..b8cf1094b 100644 --- a/libcef/common/cef_switches.h +++ b/libcef/common/cef_switches.h @@ -51,6 +51,7 @@ extern const char kPluginPolicy_Allow[]; extern const char kPluginPolicy_Detect[]; extern const char kPluginPolicy_Block[]; extern const char kEnablePreferenceTesting[]; +extern const char kEnableNetSecurityExpiration[]; } // namespace switches diff --git a/patch/patch.cfg b/patch/patch.cfg index a84710f56..aa893a703 100644 --- a/patch/patch.cfg +++ b/patch/patch.cfg @@ -282,4 +282,10 @@ patches = [ 'name': 'webui_2037', 'path': '../', }, + { + # Support an option to enable/disable net security expiration. + # https://bitbucket.org/chromiumembedded/cef/issues/1994 + 'name': 'net_security_expiration_1994', + 'path': '../', + }, ] diff --git a/patch/patches/net_security_expiration_1994.patch b/patch/patches/net_security_expiration_1994.patch new file mode 100644 index 000000000..2b9637f3e --- /dev/null +++ b/patch/patches/net_security_expiration_1994.patch @@ -0,0 +1,106 @@ +diff --git net/cert/ct_policy_enforcer.cc net/cert/ct_policy_enforcer.cc +index 42f631e..b02edb0 100644 +--- net/cert/ct_policy_enforcer.cc ++++ net/cert/ct_policy_enforcer.cc +@@ -36,15 +36,6 @@ namespace net { + + namespace { + +-// Returns true if the current build is recent enough to ensure that +-// built-in security information (e.g. CT Logs) is fresh enough. +-// TODO(eranm): Move to base or net/base +-bool IsBuildTimely() { +- const base::Time build_time = base::GetBuildTime(); +- // We consider built-in information to be timely for 10 weeks. +- return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; +-} +- + // Returns a rounded-down months difference of |start| and |end|, + // together with an indication of whether the last month was + // a full month, because the range starts specified in the policy +@@ -459,4 +450,13 @@ ct::EVPolicyCompliance CTPolicyEnforcer::DoesConformToCTEVPolicy( + return details.status; + } + ++bool CTPolicyEnforcer::IsBuildTimely() const { ++ if (!enforce_net_security_expiration_) ++ return true; ++ ++ const base::Time build_time = base::GetBuildTime(); ++ // We consider built-in information to be timely for 10 weeks. ++ return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; ++} ++ + } // namespace net +diff --git net/cert/ct_policy_enforcer.h net/cert/ct_policy_enforcer.h +index c732cee..1c80e81 100644 +--- net/cert/ct_policy_enforcer.h ++++ net/cert/ct_policy_enforcer.h +@@ -101,6 +101,17 @@ class NET_EXPORT CTPolicyEnforcer { + const ct::EVCertsWhitelist* ev_whitelist, + const SCTList& verified_scts, + const NetLogWithSource& net_log); ++ ++ void set_enforce_net_security_expiration(bool enforce) { ++ enforce_net_security_expiration_ = enforce; ++ } ++ ++ private: ++ // Returns true if the current build is recent enough to ensure that ++ // built-in security information (e.g. CT Logs) is fresh enough. ++ bool IsBuildTimely() const; ++ ++ bool enforce_net_security_expiration_ = true; + }; + + } // namespace net +diff --git net/http/transport_security_state.cc net/http/transport_security_state.cc +index a3f468d..8d1928f 100644 +--- net/http/transport_security_state.cc ++++ net/http/transport_security_state.cc +@@ -1374,8 +1374,10 @@ void TransportSecurityState::SetShouldRequireCTForTesting(bool* required) { + g_ct_required_for_testing = *required ? 1 : -1; + } + +-// static +-bool TransportSecurityState::IsBuildTimely() { ++bool TransportSecurityState::IsBuildTimely() const { ++ if (!enforce_net_security_expiration_) ++ return true; ++ + const base::Time build_time = base::GetBuildTime(); + // We consider built-in information to be timely for 10 weeks. + return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; +diff --git net/http/transport_security_state.h net/http/transport_security_state.h +index 3326ca2..a2de308 100644 +--- net/http/transport_security_state.h ++++ net/http/transport_security_state.h +@@ -472,6 +472,10 @@ class NET_EXPORT TransportSecurityState + // nullptr to reset. + static void SetShouldRequireCTForTesting(bool* required); + ++ void set_enforce_net_security_expiration(bool enforce) { ++ enforce_net_security_expiration_ = enforce; ++ } ++ + private: + friend class TransportSecurityStateTest; + FRIEND_TEST_ALL_PREFIXES(HttpSecurityHeadersTest, UpdateDynamicPKPOnly); +@@ -495,7 +499,7 @@ class NET_EXPORT TransportSecurityState + // IsBuildTimely returns true if the current build is new enough ensure that + // built in security information (i.e. HSTS preloading and pinning + // information) is timely. +- static bool IsBuildTimely(); ++ bool IsBuildTimely() const; + + // Helper method for actually checking pins. + PKPStatus CheckPublicKeyPinsImpl( +@@ -586,6 +590,8 @@ class NET_EXPORT TransportSecurityState + // True if public key pinning bypass is enabled for local trust anchors. + bool enable_pkp_bypass_for_local_trust_anchors_; + ++ bool enforce_net_security_expiration_ = true; ++ + ExpectCTReporter* expect_ct_reporter_ = nullptr; + + RequireCTDelegate* require_ct_delegate_ = nullptr;