Skip to content

Commit

Permalink
Add an enterprise policy InsecureHashesinTLSHandshakesEnabled
Browse files Browse the repository at this point in the history
to control the use of insecure hashes in the TLS Handshake.

This policy allows Google Chrome to use legacy insecure hashes during the TLS
handshake process.

If this policy is not configured, Google Chrome will follow the default rollout
process for disallowing insecure hashes. If it is enabled, Google Chrome will
allow insecure hashes to be used by a server when negotiating a TLS
handshake. If it is disabled, Google Chrome will disallow insecure hashes to be
used by a server when negotiating a TLS handshake. This policy will be removed
in 119.

Bug: 658905
Change-Id: I76e6f766bb5dcbdfd1a742e47ea4064c721b2e02
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4350968
Reviewed-by: Alexander Hendrich <hendrich@chromium.org>
Commit-Queue: Bob Beck <bbe@google.com>
Cr-Commit-Position: refs/heads/main@{#1124314}
  • Loading branch information
Bob Beck authored and Chromium LUCI CQ committed Mar 30, 2023
1 parent 987784f commit 3c26b72
Show file tree
Hide file tree
Showing 16 changed files with 259 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,9 @@ const PolicyToPreferenceMapEntry kSimplePolicyMap[] = {
{ key::kThirdPartyStoragePartitioningBlockedForOrigins,
prefs::kManagedThirdPartyStoragePartitioningBlockedForOrigins,
base::Value::Type::LIST },
{ key::kInsecureHashesInTLSHandshakesEnabled,
prefs::kInsecureHashesInTLSHandshakesEnabled,
base::Value::Type::BOOLEAN },
// Policies for all platforms - End
#if BUILDFLAG(IS_ANDROID)
{ key::kAuthAndroidNegotiateAccountType,
Expand Down
103 changes: 103 additions & 0 deletions chrome/browser/policy/policy_network_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -262,4 +262,107 @@ IN_PROC_BROWSER_TEST_F(ECHPolicyTest, ECHEnabledPolicy) {
EXPECT_EQ(base::ASCIIToUTF16(kECHFailureTitle), result.title);
}

class SHA1DisabledPolicyTest : public SSLPolicyTest {
public:
SHA1DisabledPolicyTest() {
scoped_feature_list_.InitAndDisableFeature(
net::features::kSHA1ServerSignature);
}

private:
base::test::ScopedFeatureList scoped_feature_list_;
};

IN_PROC_BROWSER_TEST_F(SHA1DisabledPolicyTest, InsecureHashPolicy) {
net::SSLServerConfig ssl_config;
// Apply 0x303 to force TLS 1.2 and make the server limited to sha1.
ssl_config.version_min = 0x0303;
ssl_config.version_max = 0x0303;
ssl_config.signature_algorithm_for_testing = 0x0201;
ASSERT_TRUE(StartTestServer(ssl_config));

// Should be unable to load a page from the test server because the
// policy is unset, and the feature flag has disabled SHA1
EXPECT_FALSE(GetBooleanPref(prefs::kInsecureHashesInTLSHandshakesEnabled));
LoadResult result = LoadPage("/title2.html");
EXPECT_FALSE(result.success);

PolicyMap policies;
// Enable Insecure Handshake Hashes.
SetPolicy(&policies, key::kInsecureHashesInTLSHandshakesEnabled,
base::Value(true));
UpdateProviderPolicy(policies);
content::FlushNetworkServiceInstanceForTesting();

// Should be able to load a page from the test server because policy has
// overridden the disabled feature flag.
EXPECT_TRUE(GetBooleanPref(prefs::kInsecureHashesInTLSHandshakesEnabled));
result = LoadPage("/title2.html");
EXPECT_TRUE(result.success);
EXPECT_EQ(u"Title Of Awesomeness", result.title);

// Disable the policy.
SetPolicy(&policies, key::kInsecureHashesInTLSHandshakesEnabled,
base::Value(false));
UpdateProviderPolicy(policies);
content::FlushNetworkServiceInstanceForTesting();

// Page loads should now fail as the policy has disabled SHA1.
EXPECT_FALSE(GetBooleanPref(prefs::kInsecureHashesInTLSHandshakesEnabled));
result = LoadPage("/title3.html");
EXPECT_FALSE(result.success);
}

class SHA1EnabledPolicyTest : public SSLPolicyTest {
public:
SHA1EnabledPolicyTest() {
scoped_feature_list_.InitAndEnableFeature(
net::features::kSHA1ServerSignature);
}

private:
base::test::ScopedFeatureList scoped_feature_list_;
};

IN_PROC_BROWSER_TEST_F(SHA1EnabledPolicyTest, InsecureHashPolicy) {
net::SSLServerConfig ssl_config;
// Apply 0x303 to force TLS 1.2 and make the server limited to sha1.
ssl_config.version_min = 0x0303;
ssl_config.version_max = 0x0303;
ssl_config.signature_algorithm_for_testing = 0x0201;
ASSERT_TRUE(StartTestServer(ssl_config));

// With the policy unset, we should be able to load a page from the test
// server because SHA1 is allowed by feature flag.
EXPECT_FALSE(GetBooleanPref(prefs::kInsecureHashesInTLSHandshakesEnabled));
LoadResult result = LoadPage("/title2.html");
EXPECT_TRUE(result.success);
EXPECT_EQ(u"Title Of Awesomeness", result.title);

PolicyMap policies;
// Disable Insecure Handshake Hashes.
SetPolicy(&policies, key::kInsecureHashesInTLSHandshakesEnabled,
base::Value(false));
UpdateProviderPolicy(policies);
content::FlushNetworkServiceInstanceForTesting();

// We should no longer be able to load a page, as the policy has
// disabled insecure hashes..
EXPECT_FALSE(GetBooleanPref(prefs::kInsecureHashesInTLSHandshakesEnabled));
result = LoadPage("/title3.html");
EXPECT_FALSE(result.success);

// Enable Insecure Handshake Hashes.
SetPolicy(&policies, key::kInsecureHashesInTLSHandshakesEnabled,
base::Value(true));
UpdateProviderPolicy(policies);
content::FlushNetworkServiceInstanceForTesting();

// With the policy set, we should be able to load a page from the test server
EXPECT_TRUE(GetBooleanPref(prefs::kInsecureHashesInTLSHandshakesEnabled));
result = LoadPage("/title3.html");
EXPECT_TRUE(result.success);
EXPECT_EQ(u"Title Of More Awesomeness", result.title);
}

} // namespace policy
16 changes: 16 additions & 0 deletions chrome/browser/ssl/ssl_config_service_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ SSLConfigServiceManager::SSLConfigServiceManager(PrefService* local_state) {
local_state_callback);
ech_enabled_.Init(prefs::kEncryptedClientHelloEnabled, local_state,
local_state_callback);
insecure_hash_enabled_.Init(prefs::kInsecureHashesInTLSHandshakesEnabled,
local_state, local_state_callback);

local_state_change_registrar_.Init(local_state);
local_state_change_registrar_.Add(prefs::kCipherSuiteBlacklist,
Expand Down Expand Up @@ -173,6 +175,10 @@ void SSLConfigServiceManager::RegisterPrefs(PrefRegistrySimple* registry) {
default_context_config.cecpq2_enabled);
registry->RegisterBooleanPref(prefs::kEncryptedClientHelloEnabled,
default_context_config.ech_enabled);
// Default value for this pref doesn't matter since it is only used when
// managed.
registry->RegisterBooleanPref(prefs::kInsecureHashesInTLSHandshakesEnabled,
false);
}

void SSLConfigServiceManager::AddToNetworkContextParams(
Expand Down Expand Up @@ -242,6 +248,16 @@ network::mojom::SSLConfigPtr SSLConfigServiceManager::GetSSLConfigFromPrefs()
cecpq2_enabled_.GetValue() && variations_unrestricted_;
config->ech_enabled = ech_enabled_.GetValue();

if (insecure_hash_enabled_.IsManaged()) {
config->insecure_hash_enabled =
insecure_hash_enabled_.GetValue()
? network::mojom::insecure_hash_enabled_value::kEnabled
: network::mojom::insecure_hash_enabled_value::kDisabled;
} else {
config->insecure_hash_enabled =
network::mojom::insecure_hash_enabled_value::kUnset;
}

return config;
}

Expand Down
1 change: 1 addition & 0 deletions chrome/browser/ssl/ssl_config_service_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class SSLConfigServiceManager {
StringListPrefMember h2_client_cert_coalescing_host_patterns_;
BooleanPrefMember cecpq2_enabled_;
BooleanPrefMember ech_enabled_;
BooleanPrefMember insecure_hash_enabled_;

// The cached list of disabled SSL cipher suites.
std::vector<uint16_t> disabled_cipher_suites_;
Expand Down
4 changes: 4 additions & 0 deletions chrome/common/pref_names.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2247,6 +2247,10 @@ const char kCECPQ2Enabled[] = "ssl.cecpq2_enabled";
// If false, disable Encrypted ClientHello (ECH) in TLS connections.
const char kEncryptedClientHelloEnabled[] = "ssl.ech_enabled";

// If false, disallow insecure hashes for use in TLS Handshakes.
const char kInsecureHashesInTLSHandshakesEnabled[] =
"ssl.insecure_hash_enabled";

// Boolean that specifies whether the built-in asynchronous DNS client is used.
const char kBuiltInDnsClientEnabled[] = "async_dns.enabled";

Expand Down
1 change: 1 addition & 0 deletions chrome/common/pref_names.h
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,7 @@ extern const char kH2ClientCertCoalescingHosts[];
extern const char kHSTSPolicyBypassList[];
extern const char kCECPQ2Enabled[];
extern const char kEncryptedClientHelloEnabled[];
extern const char kInsecureHashesInTLSHandshakesEnabled[];

extern const char kBuiltInDnsClientEnabled[];
extern const char kDnsOverHttpsMode[];
Expand Down
2 changes: 1 addition & 1 deletion components/policy/resources/templates/policies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1093,7 +1093,7 @@ policies:
1092: ScreenCaptureWithoutGestureAllowedForOrigins
1093: FileOrDirectoryPickerWithoutGestureAllowedForOrigins
1094: AppLaunchAutomation

1095: InsecureHashesInTLSHandshakesEnabled
atomic_groups:
1: Homepage
2: RemoteAccess
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
caption: Insecure Hashes in TLS Handshakes Enabled
default: null
desc: |-
This policy allows <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> to use legacy insecure hashes during the TLS handshake process.
If this policy is not configured, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will follow the default rollout process for disallowing insecure hashes. If it is enabled, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will allow insecure hashes to be used by a server when negotiating a TLS handshake. If it is disabled, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will disallow insecure hashes to be used by a server when negotiating a TLS handshake. This policy will be removed in 119.
example_value: false
features:
dynamic_refresh: true
per_profile: false
items:
- caption: Use Default Value for Hashes Allowed in TLS Handshakes.
value: null
- caption: Do Not Allow Insecure Hashes in TLS Handshakes
value: false
- caption: Allow Insecure Hashes in TLS Handshakes
value: true
owners:
- bbe@chromium.org
- trusty-transport@chromium.org
schema:
type: boolean
supported_on:
- chrome.*:114-
- chrome_os:114-
- android:114-
- fuchsia:114-
tags:
- system-security
type: main
44 changes: 44 additions & 0 deletions components/policy/test/data/policy_test_cases.json
Original file line number Diff line number Diff line change
Expand Up @@ -22929,5 +22929,49 @@
}
}
]
},
"InsecureHashesInTLSHandshakesEnabled": {
"os": [
"win",
"linux",
"mac",
"chromeos_ash",
"chromeos_lacros",
"android",
"fuchsia"
],
"policy_pref_mapping_tests": [
{
"note": "Default value (no policies set).",
"prefs": {
"ssl.insecure_hash_enabled": {
"default_value": false,
"location": "local_state"
}
}
},
{
"policies": {
"InsecureHashesInTLSHandshakesEnabled": true
},
"prefs": {
"ssl.insecure_hash_enabled": {
"value": true,
"location": "local_state"
}
}
},
{
"policies": {
"InsecureHashesInTLSHandshakesEnabled": false
},
"prefs": {
"ssl.insecure_hash_enabled": {
"value": false,
"location": "local_state"
}
}
}
]
}
}
1 change: 0 additions & 1 deletion net/socket/socket_test_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,6 @@ SequencedSocketData::SequencedSocketData(const MockConnect& connect,
: SequencedSocketData(reads, writes) {
set_connect_data(connect);
}

MockRead SequencedSocketData::OnRead() {
CHECK_EQ(IoState::kIdle, read_state_);
CHECK(!helper_.AllReadDataConsumed())
Expand Down
2 changes: 1 addition & 1 deletion net/socket/ssl_connect_job.cc
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ int SSLConnectJob::DoSSLConnect() {
// on a potentially unreliably network connection.
ssl_config.disable_sha1_server_signatures =
disable_legacy_crypto_with_fallback_ ||
!base::FeatureList::IsEnabled(features::kSHA1ServerSignature);
!ssl_client_context()->config().InsecureHashesInTLSHandshakesEnabled();

if (ssl_client_context()->config().EncryptedClientHelloEnabled()) {
if (ech_retry_configs_) {
Expand Down
16 changes: 14 additions & 2 deletions net/ssl/ssl_config_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ bool SSLContextConfigsAreEqual(const net::SSLContextConfig& config1,
const net::SSLContextConfig& config2) {
return std::tie(config1.version_min, config1.version_max,
config1.disabled_cipher_suites, config1.cecpq2_enabled,
config1.ech_enabled) ==
config1.ech_enabled, config1.insecure_hash_enabled) ==
std::tie(config2.version_min, config2.version_max,
config2.disabled_cipher_suites, config2.cecpq2_enabled,
config2.ech_enabled);
config2.ech_enabled, config2.insecure_hash_enabled);
}

} // namespace
Expand All @@ -41,6 +41,18 @@ bool SSLContextConfig::EncryptedClientHelloEnabled() const {
base::FeatureList::IsEnabled(features::kEncryptedClientHello);
}

bool SSLContextConfig::InsecureHashesInTLSHandshakesEnabled() const {
switch (insecure_hash_enabled) {
case insecure_hash_enabled_value::kUnset:
return base::FeatureList::IsEnabled(features::kSHA1ServerSignature);
case insecure_hash_enabled_value::kEnabled:
return true;
case insecure_hash_enabled_value::kDisabled:
return false;
}
NOTREACHED();
}

SSLConfigService::SSLConfigService()
: observer_list_(base::ObserverListPolicy::EXISTING_ONLY) {}

Expand Down
14 changes: 14 additions & 0 deletions net/ssl/ssl_config_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ struct NET_EXPORT SSLContextConfig {
// EncryptedClientHelloEnabled returns whether ECH is enabled.
bool EncryptedClientHelloEnabled() const;

// Returns whether insecure hashes are allowed in TLS handshakes.
bool InsecureHashesInTLSHandshakesEnabled() const;

// The minimum and maximum protocol versions that are enabled.
// (Use the SSL_PROTOCOL_VERSION_xxx enumerators defined in ssl_config.h.)
// SSL 2.0/3.0 and TLS 1.0/1.1 are not supported. If version_max <
Expand All @@ -49,6 +52,17 @@ struct NET_EXPORT SSLContextConfig {
// ECH is enabled, use `EncryptedClientHelloEnabled` instead.
bool ech_enabled = true;

// If kEnabled, allows insecure hashes in TLS handshakes. If kDisabled,
// disallows insecure hashes in TLS handshakes. If kUnset use hashes
// determined by feature flags.
enum class insecure_hash_enabled_value {
kUnset,
kEnabled,
kDisabled,
};
insecure_hash_enabled_value insecure_hash_enabled =
insecure_hash_enabled_value::kUnset;

// ADDING MORE HERE? Don't forget to update `SSLContextConfigsAreEqual`.
};

Expand Down
11 changes: 11 additions & 0 deletions services/network/public/mojom/ssl_config.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ enum SSLVersion {
kTLS13,
};

enum insecure_hash_enabled_value {
kUnset,
kEnabled,
kDisabled,
};

// This is a combination of net::SSLContextConfig and
// net::CertVerifier::Config's fields. See those two classes for descriptions.
struct SSLConfig {
Expand Down Expand Up @@ -44,6 +50,11 @@ struct SSLConfig {
// If false, disables TLS Encrypted ClientHello (ECH). If true, the feature
// may be enabled or disabled, depending on feature flags.
bool ech_enabled = true;

// If kEnabled, allows insecure hashes in TLS handshakes. If kDisabled,
// disallows insecure hashes in TLS handshakes. If kUnset use hashes
// determined by feature flags.
insecure_hash_enabled_value insecure_hash_enabled = kUnset;
};

// Receives SSL configuration updates.
Expand Down
14 changes: 14 additions & 0 deletions services/network/ssl_config_type_converter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ net::SSLContextConfig MojoSSLConfigToSSLContextConfig(
net_config.disabled_cipher_suites = mojo_config->disabled_cipher_suites;
net_config.cecpq2_enabled = mojo_config->cecpq2_enabled;
net_config.ech_enabled = mojo_config->ech_enabled;
switch (mojo_config->insecure_hash_enabled) {
case network::mojom::insecure_hash_enabled_value::kUnset:
net_config.insecure_hash_enabled =
net::SSLContextConfig::insecure_hash_enabled_value::kUnset;
break;
case network::mojom::insecure_hash_enabled_value::kEnabled:
net_config.insecure_hash_enabled =
net::SSLContextConfig::insecure_hash_enabled_value::kEnabled;
break;
case network::mojom::insecure_hash_enabled_value::kDisabled:
net_config.insecure_hash_enabled =
net::SSLContextConfig::insecure_hash_enabled_value::kDisabled;
break;
}
return net_config;
}

Expand Down
Loading

0 comments on commit 3c26b72

Please sign in to comment.