fips-20260721: cherry-pick Make BoringSSL handling of "unusable" EchConfigLists configurable (cherry picked from commit 59e89e9132799b287fea2b5c95988621a1365130) Currently, BoringSSL will silently ignore EchConfigsLists it considers "unusable". An EchConfigList is considered "unusable" if we are in one of the following scenarios: 1. The max TLS version supported by the client is < 1.3 2. No EchConfig provided in the EchConfigList is supported by BoringSSL. This happens when every EchConfig provided contains an unsupported/unrecognized cyphers/parameters (e.g., an unknown HPKE Key Encapsulation Mechanism). In these scenarios, instead of falling back onto GREASE ECH (if enabled), return an error to the caller. The caller can then decide to either retry with an empty EchConfigList or fail the connection. Bug: 542983348, b:450001346 Change-Id: Ie6fbaf19c2eff3541309e9de60f2ce500a20a0f9 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/100387 Reviewed-by: Xiangfei Ding <xfding@google.com>
diff --git a/crypto/err/ssl.errordata b/crypto/err/ssl.errordata index 4f1d77a..0ee34ae 100644 --- a/crypto/err/ssl.errordata +++ b/crypto/err/ssl.errordata
@@ -255,6 +255,7 @@ SSL,239,UNSUPPORTED_ELLIPTIC_CURVE SSL,240,UNSUPPORTED_PROTOCOL SSL,252,UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY +SSL,337,UNUSABLE_ECH_CONFIG_LIST SSL,241,WRONG_CERTIFICATE_TYPE SSL,242,WRONG_CIPHER_RETURNED SSL,243,WRONG_CURVE
diff --git a/gen/crypto/err_data.cc b/gen/crypto/err_data.cc index e20e7e7..006aa94 100644 --- a/gen/crypto/err_data.cc +++ b/gen/crypto/err_data.cc
@@ -206,51 +206,51 @@ 0x283500f7, 0x28358cc1, 0x2836099a, - 0x2c3234ce, + 0x2c3234e7, 0x2c329443, - 0x2c3334dc, - 0x2c33b4ee, - 0x2c343502, - 0x2c34b514, - 0x2c35352f, - 0x2c35b541, - 0x2c363571, + 0x2c3334f5, + 0x2c33b507, + 0x2c34351b, + 0x2c34b52d, + 0x2c353548, + 0x2c35b55a, + 0x2c36358a, 0x2c36833a, - 0x2c37357e, - 0x2c37b5aa, - 0x2c3835e8, - 0x2c38b5ff, - 0x2c39361d, - 0x2c39b62d, - 0x2c3a363f, - 0x2c3ab653, - 0x2c3b3664, - 0x2c3bb683, + 0x2c373597, + 0x2c37b5c3, + 0x2c383601, + 0x2c38b618, + 0x2c393636, + 0x2c39b646, + 0x2c3a3658, + 0x2c3ab66c, + 0x2c3b367d, + 0x2c3bb69c, 0x2c3c1455, 0x2c3c946b, - 0x2c3d36c8, + 0x2c3d36e1, 0x2c3d9484, - 0x2c3e36f2, - 0x2c3eb700, - 0x2c3f3718, - 0x2c3fb730, - 0x2c40375a, + 0x2c3e370b, + 0x2c3eb719, + 0x2c3f3731, + 0x2c3fb749, + 0x2c403773, 0x2c409330, - 0x2c41376b, - 0x2c41b77e, + 0x2c413784, + 0x2c41b797, 0x2c4212f6, - 0x2c42b78f, + 0x2c42b7a8, 0x2c43076d, - 0x2c43b675, - 0x2c4435bd, - 0x2c44b73d, - 0x2c453554, - 0x2c45b590, - 0x2c46360d, - 0x2c46b697, - 0x2c4736ac, - 0x2c47b6e5, - 0x2c4835cf, + 0x2c43b68e, + 0x2c4435d6, + 0x2c44b756, + 0x2c45356d, + 0x2c45b5a9, + 0x2c463626, + 0x2c46b6b0, + 0x2c4736c5, + 0x2c47b6fe, + 0x2c4835e8, 0x30320000, 0x30328015, 0x3033001f, @@ -529,15 +529,15 @@ 0x40773263, 0x4077b2bf, 0x407832da, - 0x4078b313, - 0x4079332a, - 0x4079b340, - 0x407a336c, - 0x407ab37f, - 0x407b3394, - 0x407bb3a6, - 0x407c33d7, - 0x407cb3e0, + 0x4078b32c, + 0x40793343, + 0x4079b359, + 0x407a3385, + 0x407ab398, + 0x407b33ad, + 0x407bb3bf, + 0x407c33f0, + 0x407cb3f9, 0x407d2a6e, 0x407da2f7, 0x407e32ef, @@ -566,7 +566,7 @@ 0x40899c67, 0x408a2ced, 0x408a9a85, - 0x408b33bb, + 0x408b33d4, 0x408bb0ff, 0x408c2692, 0x408d2006, @@ -586,7 +586,7 @@ 0x40941f32, 0x4094ad06, 0x40952872, - 0x4095b34c, + 0x4095b365, 0x4096305c, 0x4096a282, 0x409723d4, @@ -624,6 +624,7 @@ 0x40a7324b, 0x40a7a40e, 0x40a8232c, + 0x40a8b313, 0x41f42ba7, 0x41f92c39, 0x41fe2b2c, @@ -713,71 +714,71 @@ 0x4c41954d, 0x4c4216b6, 0x4c429495, - 0x503237a1, - 0x5032b7b0, - 0x503337bb, - 0x5033b7cb, - 0x503437e4, - 0x5034b7fe, - 0x5035380c, - 0x5035b822, - 0x50363834, - 0x5036b84a, - 0x50373863, - 0x5037b876, - 0x5038388e, - 0x5038b89f, - 0x503938b4, - 0x5039b8c8, - 0x503a38e8, - 0x503ab8fe, - 0x503b3916, - 0x503bb928, - 0x503c3944, - 0x503cb95b, - 0x503d3974, - 0x503db98a, - 0x503e3997, - 0x503eb9ad, - 0x503f39bf, + 0x503237ba, + 0x5032b7c9, + 0x503337d4, + 0x5033b7e4, + 0x503437fd, + 0x5034b817, + 0x50353825, + 0x5035b83b, + 0x5036384d, + 0x5036b863, + 0x5037387c, + 0x5037b88f, + 0x503838a7, + 0x5038b8b8, + 0x503938cd, + 0x5039b8e1, + 0x503a3901, + 0x503ab917, + 0x503b392f, + 0x503bb941, + 0x503c395d, + 0x503cb974, + 0x503d398d, + 0x503db9a3, + 0x503e39b0, + 0x503eb9c6, + 0x503f39d8, 0x503f83b3, - 0x504039d2, - 0x5040b9e2, - 0x504139fc, - 0x5041ba0b, - 0x50423a25, - 0x5042ba42, - 0x50433a52, - 0x5043ba62, - 0x50443a7f, + 0x504039eb, + 0x5040b9fb, + 0x50413a15, + 0x5041ba24, + 0x50423a3e, + 0x5042ba5b, + 0x50433a6b, + 0x5043ba7b, + 0x50443a98, 0x50448469, - 0x50453a93, - 0x5045bab1, - 0x50463ac4, - 0x5046bada, - 0x50473aec, - 0x5047bb01, - 0x50483b27, - 0x5048bb35, - 0x50493b48, - 0x5049bb5d, - 0x504a3b73, - 0x504abb83, - 0x504b3ba3, - 0x504bbbb6, - 0x504c3bd9, - 0x504cbc07, - 0x504d3c34, - 0x504dbc51, - 0x504e3c6c, - 0x504ebc88, - 0x504f3c9a, - 0x504fbcb1, - 0x50503cc0, + 0x50453aac, + 0x5045baca, + 0x50463add, + 0x5046baf3, + 0x50473b05, + 0x5047bb1a, + 0x50483b40, + 0x5048bb4e, + 0x50493b61, + 0x5049bb76, + 0x504a3b8c, + 0x504abb9c, + 0x504b3bbc, + 0x504bbbcf, + 0x504c3bf2, + 0x504cbc20, + 0x504d3c4d, + 0x504dbc6a, + 0x504e3c85, + 0x504ebca1, + 0x504f3cb3, + 0x504fbcca, + 0x50503cd9, 0x50508729, - 0x50513cd3, - 0x5051ba71, - 0x50523c19, + 0x50513cec, + 0x5051ba8a, + 0x50523c32, 0x58321011, 0x68320fd3, 0x68328d2b, @@ -822,19 +823,19 @@ 0x7c32130c, 0x80321560, 0x80328090, - 0x8033349d, + 0x803334b6, 0x803380b9, - 0x803434ac, - 0x8034b414, - 0x80353432, - 0x8035b4c0, - 0x80363474, - 0x8036b423, - 0x80373466, - 0x8037b401, - 0x80383487, - 0x8038b443, - 0x80393458, + 0x803434c5, + 0x8034b42d, + 0x8035344b, + 0x8035b4d9, + 0x8036348d, + 0x8036b43c, + 0x8037347f, + 0x8037b41a, + 0x803834a0, + 0x8038b45c, + 0x80393471, 0x84320bb0, 0x84328bc9, }; @@ -1436,6 +1437,7 @@ "UNSUPPORTED_ELLIPTIC_CURVE\0" "UNSUPPORTED_PROTOCOL\0" "UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY\0" + "UNUSABLE_ECH_CONFIG_LIST\0" "WRONG_CERTIFICATE_TYPE\0" "WRONG_CIPHER_RETURNED\0" "WRONG_CURVE\0"
diff --git a/include/openssl/prefix_symbols.h b/include/openssl/prefix_symbols.h index d46dc70..efa6f1d 100644 --- a/include/openssl/prefix_symbols.h +++ b/include/openssl/prefix_symbols.h
@@ -2399,6 +2399,7 @@ #pragma redefine_extname SSL_set_quic_use_legacy_codepoint BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set_quic_use_legacy_codepoint) #pragma redefine_extname SSL_set_quiet_shutdown BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set_quiet_shutdown) #pragma redefine_extname SSL_set_read_ahead BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set_read_ahead) +#pragma redefine_extname SSL_set_reject_unusable_ech_config BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set_reject_unusable_ech_config) #pragma redefine_extname SSL_set_renegotiate_mode BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set_renegotiate_mode) #pragma redefine_extname SSL_set_resumption_across_names_enabled BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set_resumption_across_names_enabled) #pragma redefine_extname SSL_set_retain_only_sha256_of_client_certs BORINGSSL_ADD_USER_LABEL_AND_PREFIX(SSL_set_retain_only_sha256_of_client_certs) @@ -5532,6 +5533,7 @@ #define SSL_set_quic_use_legacy_codepoint BORINGSSL_ADD_PREFIX(SSL_set_quic_use_legacy_codepoint) #define SSL_set_quiet_shutdown BORINGSSL_ADD_PREFIX(SSL_set_quiet_shutdown) #define SSL_set_read_ahead BORINGSSL_ADD_PREFIX(SSL_set_read_ahead) +#define SSL_set_reject_unusable_ech_config BORINGSSL_ADD_PREFIX(SSL_set_reject_unusable_ech_config) #define SSL_set_renegotiate_mode BORINGSSL_ADD_PREFIX(SSL_set_renegotiate_mode) #define SSL_set_resumption_across_names_enabled BORINGSSL_ADD_PREFIX(SSL_set_resumption_across_names_enabled) #define SSL_set_retain_only_sha256_of_client_certs BORINGSSL_ADD_PREFIX(SSL_set_retain_only_sha256_of_client_certs)
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 56682da..e450fad 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h
@@ -4598,6 +4598,11 @@ // ECH extension when no supported ECHConfig is available. OPENSSL_EXPORT void SSL_set_enable_ech_grease(SSL *ssl, int enable); +// SSL_set_reject_unusable_ech_config configures whether the client will fail +// the handshake if a valid, supported ECHConfig cannot be selected to offer +// ECH. +OPENSSL_EXPORT void SSL_set_reject_unusable_ech_config(SSL *ssl, int enable); + // SSL_set1_ech_config_list configures `ssl` to, as a client, offer ECH with the // specified configuration. `ech_config_list` should contain a serialized // ECHConfigList structure. It returns one on success and zero on error. @@ -7100,6 +7105,7 @@ #define SSL_R_UNSUPPORTED_CERTIFICATE 334 #define SSL_R_MISSING_KEY 335 #define SSL_R_INVALID_RAW_PUBLIC_KEY 336 +#define SSL_R_UNUSABLE_ECH_CONFIG_LIST 337 #define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000 #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/ssl/encrypted_client_hello.cc b/ssl/encrypted_client_hello.cc index 46ba196..0cf1fc3 100644 --- a/ssl/encrypted_client_hello.cc +++ b/ssl/encrypted_client_hello.cc
@@ -656,6 +656,10 @@ *out_enc_len = 0; if (hs->max_version < TLS1_3_VERSION) { // ECH requires TLS 1.3. + if (hs->config->reject_unusable_ech_config) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNUSABLE_ECH_CONFIG_LIST); + return false; + } return true; } @@ -708,6 +712,11 @@ } } + if (hs->config->reject_unusable_ech_config && !hs->selected_ech_config) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNUSABLE_ECH_CONFIG_LIST); + return false; + } + return true; } @@ -901,6 +910,14 @@ ssl_impl->config->ech_grease_enabled = !!enable; } +void SSL_set_reject_unusable_ech_config(SSL *ssl, int enable) { + auto *ssl_impl = FromOpaque(ssl); + if (!ssl_impl->config) { + return; + } + ssl_impl->config->reject_unusable_ech_config = !!enable; +} + int SSL_set1_ech_config_list(SSL *ssl, const uint8_t *ech_config_list, size_t ech_config_list_len) { auto *ssl_impl = FromOpaque(ssl);
diff --git a/ssl/internal.h b/ssl/internal.h index 74c6c2e..c5dd0fb 100644 --- a/ssl/internal.h +++ b/ssl/internal.h
@@ -3504,6 +3504,10 @@ // ClientHello. bool ech_grease_enabled : 1; + // reject_unusable_ech_config controls whether the client will fail the + // handshake if ECH cannot be offered. + bool reject_unusable_ech_config : 1; + // Enable signed certificate time stamps. Currently client only. bool signed_cert_timestamps_enabled : 1;
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc index e05f91b..eb55f7a 100644 --- a/ssl/ssl_lib.cc +++ b/ssl/ssl_lib.cc
@@ -583,6 +583,7 @@ SSL_CONFIG::SSL_CONFIG(SSLImpl *ssl_arg) : ssl(ssl_arg), ech_grease_enabled(false), + reject_unusable_ech_config(false), signed_cert_timestamps_enabled(false), ocsp_stapling_enabled(false), channel_id_enabled(false),
diff --git a/ssl/test/runner/ech_tests.go b/ssl/test/runner/ech_tests.go index 22ee8ec..48382e4 100644 --- a/ssl/test/runner/ech_tests.go +++ b/ssl/test/runner/ech_tests.go
@@ -2420,5 +2420,108 @@ }, expectations: connectionExpectations{echAccepted: true}, }) + unsupportedConfig := generateServerECHConfig(&ECHConfig{ + ConfigID: 42, + KEM: 0x9999, + CipherSuites: []HPKECipherSuite{{KDF: 0x1111, AEAD: 0x2222}}, + }) + testCases = append(testCases, testCase{ + testType: clientTest, + protocol: protocol, + name: prefix + "ECH-Client-RejectUnusableConfig-Success", + config: Config{ + MinVersion: VersionTLS13, + MaxVersion: VersionTLS13, + ServerECHConfigs: []ServerECHConfig{echConfig}, + Credential: &echSecretCertificate, + }, + flags: []string{ + "-reject-unusable-ech-config", + "-ech-config-list", base64FlagValue(CreateECHConfigList(echConfig.ECHConfig.Raw)), + "-host-name", "secret.example", + "-expect-ech-accept", + }, + expectations: connectionExpectations{echAccepted: true}, + }) + testCases = append(testCases, testCase{ + testType: clientTest, + protocol: protocol, + name: prefix + "ECH-Client-RejectUnusableConfig-UnsupportedConfig", + config: Config{ + MinVersion: VersionTLS13, + MaxVersion: VersionTLS13, + }, + flags: []string{ + "-reject-unusable-ech-config", + "-ech-config-list", base64FlagValue(CreateECHConfigList(unsupportedConfig.ECHConfig.Raw)), + }, + shouldFail: true, + expectedError: ":UNUSABLE_ECH_CONFIG_LIST:", + }) + testCases = append(testCases, testCase{ + testType: clientTest, + protocol: protocol, + name: prefix + "ECH-Client-RejectUnusableConfig-PartialUnsupportedConfig", + config: Config{ + MinVersion: VersionTLS13, + MaxVersion: VersionTLS13, + ServerECHConfigs: []ServerECHConfig{echConfig}, + Credential: &echSecretCertificate, + }, + flags: []string{ + "-reject-unusable-ech-config", + "-ech-config-list", base64FlagValue(CreateECHConfigList(unsupportedConfig.ECHConfig.Raw, echConfig.ECHConfig.Raw)), + "-host-name", "secret.example", + "-expect-ech-accept", + }, + expectations: connectionExpectations{echAccepted: true}, + }) + testCases = append(testCases, testCase{ + testType: clientTest, + protocol: protocol, + name: prefix + "ECH-Client-RejectUnusableConfig-Unset", + config: Config{ + MinVersion: VersionTLS13, + MaxVersion: VersionTLS13, + }, + flags: []string{ + "-reject-unusable-ech-config", + }, + shouldFail: true, + expectedError: ":UNUSABLE_ECH_CONFIG_LIST:", + }) + if protocol == tls { + testCases = append(testCases, testCase{ + testType: clientTest, + protocol: protocol, + name: prefix + "ECH-Client-RejectUnusableConfig-TLS12", + config: Config{ + MaxVersion: VersionTLS12, + }, + flags: []string{ + "-reject-unusable-ech-config", + "-max-version", strconv.Itoa(VersionTLS12), + "-ech-config-list", base64FlagValue(CreateECHConfigList(echConfig.ECHConfig.Raw)), + }, + shouldFail: true, + expectedError: ":UNUSABLE_ECH_CONFIG_LIST:", + }) + } else if protocol == dtls { + testCases = append(testCases, testCase{ + testType: clientTest, + protocol: protocol, + name: prefix + "ECH-Client-RejectUnusableConfig-TLS12", + config: Config{ + MaxVersion: VersionDTLS12, + }, + flags: []string{ + "-reject-unusable-ech-config", + "-max-version", strconv.Itoa(VersionDTLS12), + "-ech-config-list", base64FlagValue(CreateECHConfigList(echConfig.ECHConfig.Raw)), + }, + shouldFail: true, + expectedError: ":UNUSABLE_ECH_CONFIG_LIST:", + }) + } } }
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc index c15b2ab..9e09491 100644 --- a/ssl/test/test_config.cc +++ b/ssl/test/test_config.cc
@@ -351,6 +351,8 @@ StringFlag("-trust-cert", &TestConfig::trust_cert), StringFlag("-expect-server-name", &TestConfig::expect_server_name), BoolFlag("-enable-ech-grease", &TestConfig::enable_ech_grease), + BoolFlag("-reject-unusable-ech-config", + &TestConfig::reject_unusable_ech_config), Base64VectorFlag("-ech-server-config", &TestConfig::ech_server_configs), Base64VectorFlag("-ech-server-key", &TestConfig::ech_server_keys), IntVectorFlag("-ech-is-retry-config", &TestConfig::ech_is_retry_config), @@ -2452,6 +2454,9 @@ if (enable_ech_grease) { SSL_set_enable_ech_grease(ssl.get(), 1); } + if (reject_unusable_ech_config) { + SSL_set_reject_unusable_ech_config(ssl.get(), 1); + } if (!ech_config_list.empty() && !SSL_set1_ech_config_list(ssl.get(), ech_config_list.data(), ech_config_list.size())) {
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h index f781a59..56d347c 100644 --- a/ssl/test/test_config.h +++ b/ssl/test/test_config.h
@@ -79,6 +79,7 @@ std::string trust_cert; std::string expect_server_name; bool enable_ech_grease = false; + bool reject_unusable_ech_config = false; std::vector<std::vector<uint8_t>> ech_server_configs; std::vector<std::vector<uint8_t>> ech_server_keys; std::vector<int> ech_is_retry_config;