From eaf49e631ef00e4d143dbfdb965978feb96eda04 Mon Sep 17 00:00:00 2001 From: 0x676e67 Date: Wed, 18 Jun 2025 12:36:34 +0800 Subject: [PATCH] feat(boring): sync updated extension permutation patch (#80) --- ...df6f03d85c901767250329c571db405122d5.patch | 325 +++++++++++++----- boring/src/ssl/connector.rs | 7 + boring/src/ssl/mod.rs | 69 +--- boring/src/ssl/test/extensions.rs | 11 - boring/src/ssl/test/mod.rs | 82 ++++- 5 files changed, 333 insertions(+), 161 deletions(-) delete mode 100644 boring/src/ssl/test/extensions.rs diff --git a/boring-sys/patches/boringssl-44b3df6f03d85c901767250329c571db405122d5.patch b/boring-sys/patches/boringssl-44b3df6f03d85c901767250329c571db405122d5.patch index 25943e21..b33c3bc2 100644 --- a/boring-sys/patches/boringssl-44b3df6f03d85c901767250329c571db405122d5.patch +++ b/boring-sys/patches/boringssl-44b3df6f03d85c901767250329c571db405122d5.patch @@ -4270,7 +4270,7 @@ index 4dd8841b1..23ffcd446 100644 #if defined(__cplusplus) } /* extern C */ diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h -index 53aa9b453..0000201ab 100644 +index 53aa9b453..e849406e4 100644 --- a/src/include/openssl/ssl.h +++ b/src/include/openssl/ssl.h @@ -718,6 +718,12 @@ OPENSSL_EXPORT int SSL_version(const SSL *ssl); @@ -4310,14 +4310,15 @@ index 53aa9b453..0000201ab 100644 // Certificate compression. // -@@ -4570,6 +4586,39 @@ OPENSSL_EXPORT void SSL_CTX_set_permute_extensions(SSL_CTX *ctx, int enabled); +@@ -4570,6 +4586,51 @@ OPENSSL_EXPORT void SSL_CTX_set_permute_extensions(SSL_CTX *ctx, int enabled); // permute extensions. For now, this is only implemented for the ClientHello. OPENSSL_EXPORT void SSL_set_permute_extensions(SSL *ssl, int enabled); -+// SSL_CTX_set_extension_permutation configures whether sockets on |ctx| should -+// permute extensions. For now, this is only implemented for the ClientHello. -+OPENSSL_EXPORT int SSL_CTX_set_extension_permutation(SSL_CTX* ctx, const uint8_t *permutation, -+ size_t permutation_len); ++// SSL_CTX_set_extension_order configures whether sockets on |ctx| ++// should make use of the provided extensions to define the order, ++// which is similar to SSL_CTX_set_permute_extensions but in a defined ++// order instead of a random one. ++OPENSSL_EXPORT int SSL_CTX_set_extension_order(SSL_CTX *ctx, const uint16_t *ids, int num); + +// SSL_set_record_size_limit configures whether sockets on |ssl| should +// send record size limit extension. @@ -4346,11 +4347,22 @@ index 53aa9b453..0000201ab 100644 +// SSL_set_aes_hw_override acts the same as +// |SSL_CTX_set_aes_override| but only configures a single |SSL*|. +OPENSSL_EXPORT void SSL_set_aes_hw_override(SSL *ssl, int override_value); ++ ++// SSL_CTX_set_prefer_chacha20 configures whether sockets on |ctx| should prefer ++// the ChaCha20 cipher suite over AES. This is only relevant for TLS 1.3 and ++// later, where ChaCha20 is not the default cipher suite. ++OPENSSL_EXPORT void SSL_CTX_set_prefer_chacha20(SSL_CTX *ctx, ++ int prefer_chacha20); ++ ++// SSL_set_prefer_chacha20 configures whether sockets on |ssl| should prefer ++// the ChaCha20 cipher suite over AES. This is only relevant for TLS 1.3 and ++// later, where ChaCha20 is not the default cipher suite. ++OPENSSL_EXPORT void SSL_set_prefer_chacha20(SSL *ssl, int prefer_chacha20); + // SSL_max_seal_overhead returns the maximum overhead, in bytes, of sealing a // record with |ssl|. OPENSSL_EXPORT size_t SSL_max_seal_overhead(const SSL *ssl); -@@ -4874,6 +4923,10 @@ OPENSSL_EXPORT int SSL_CTX_set1_sigalgs_list(SSL_CTX *ctx, const char *str); +@@ -4874,6 +4935,10 @@ OPENSSL_EXPORT int SSL_CTX_set1_sigalgs_list(SSL_CTX *ctx, const char *str); // more convenient to codesearch for specific algorithm values. OPENSSL_EXPORT int SSL_set1_sigalgs_list(SSL *ssl, const char *str); @@ -4361,7 +4373,7 @@ index 53aa9b453..0000201ab 100644 #define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)(arg))) #define SSL_get_app_data(s) (SSL_get_ex_data(s, 0)) #define SSL_SESSION_set_app_data(s, a) \ -@@ -4926,7 +4979,6 @@ DEFINE_STACK_OF(SSL_COMP) +@@ -4926,7 +4991,6 @@ DEFINE_STACK_OF(SSL_COMP) #define SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 0 #define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0 #define SSL_OP_NO_COMPRESSION 0 @@ -4369,7 +4381,7 @@ index 53aa9b453..0000201ab 100644 #define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0 #define SSL_OP_NO_SSLv2 0 #define SSL_OP_NO_SSLv3 0 -@@ -5779,6 +5831,7 @@ BSSL_NAMESPACE_END +@@ -5779,6 +5843,7 @@ BSSL_NAMESPACE_END #define SSL_R_ECH_REJECTED 319 #define SSL_R_INVALID_OUTER_EXTENSION 320 #define SSL_R_INCONSISTENT_ECH_NEGOTIATION 321 @@ -4420,7 +4432,7 @@ index 5c7e881bf..3c0770cf3 100644 crypto/pkcs8/test/no_encryption.p12 crypto/pkcs8/test/nss.p12 diff --git a/src/ssl/extensions.cc b/src/ssl/extensions.cc -index 5ee280221..d1ae70aa1 100644 +index 5ee280221..55c85c852 100644 --- a/src/ssl/extensions.cc +++ b/src/ssl/extensions.cc @@ -207,6 +207,10 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) { @@ -4793,55 +4805,81 @@ index 5ee280221..d1ae70aa1 100644 }; #define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension)) -@@ -3280,6 +3449,12 @@ static_assert(kNumExtensions <= +@@ -3278,6 +3447,74 @@ static_assert(kNumExtensions <= + sizeof(((SSL_HANDSHAKE *)NULL)->extensions.received) * 8, + "too many extensions for received bitset"); ++bool ssl_setup_extension_order(SSL_HANDSHAKE *hs) { ++ SSL *const ssl = hs->ssl; ++ if (ssl->ctx->extension_order.empty()) { ++ return ssl_setup_extension_permutation(hs); ++ } ++ ++ static_assert(kNumExtensions <= UINT8_MAX, ++ "extensions_permutation type is too small"); ++ Array permutation; ++ if (!permutation.Init(kNumExtensions)) { ++ return false; ++ } ++ ++ bool seen[kNumExtensions] = {0}; ++ int permIndex = 0; ++ ++ for (uint16_t id : ssl->ctx->extension_order) { ++ size_t j; ++ for (j = 0; j < kNumExtensions; j++) { ++ if (kExtensions[j].value == id) { ++ break; ++ } ++ } ++ if (j == kNumExtensions || seen[j]) { ++ continue; // Skip unknown or duplicate entries ++ } ++ seen[j] = true; ++ permutation[permIndex++] = j; ++ } ++ ++ size_t rem = kNumExtensions - permIndex; ++ if (rem == 0) { ++ hs->extension_permutation = std::move(permutation); ++ return true; ++ } ++ ++ size_t offset = permIndex; ++ for (size_t i = 0; i < kNumExtensions; i++) { ++ if (seen[i]) { ++ continue; // skip duplicate entries ++ } ++ seen[i] = true; ++ permutation[permIndex++] = i; ++ } ++ ++ if (rem > 1) { ++ size_t seeds_num = rem - 1; ++ uint32_t *seeds = static_cast(OPENSSL_malloc(seeds_num * sizeof(uint32_t))); ++ if (!seeds) { ++ permutation.Reset(); ++ return false; ++ } ++ if (!RAND_bytes(reinterpret_cast(seeds), seeds_num * sizeof(uint32_t))) { ++ permutation.Reset(); ++ OPENSSL_free(seeds); ++ return false; ++ } ++ for (size_t i = kNumExtensions - 1; i > offset; i--) { ++ size_t swap_idx = offset + (seeds[i - offset] % (i - offset)); ++ std::swap(permutation[i], permutation[swap_idx]); ++ } ++ OPENSSL_free(seeds); ++ } ++ ++ hs->extension_permutation = std::move(permutation); ++ return true; ++} ++ bool ssl_setup_extension_permutation(SSL_HANDSHAKE *hs) { if (!hs->config->permute_extensions) { -+ if (!hs->ssl->ctx->extension_permutation.empty()) { -+ Array permutation; -+ permutation.Init(hs->ssl->ctx->extension_permutation.size()); -+ permutation.CopyFrom(hs->ssl->ctx->extension_permutation); -+ hs->extension_permutation = std::move(permutation); -+ } return true; - } - -@@ -3357,10 +3532,16 @@ static bool ssl_add_clienthello_tlsext_inner(SSL_HANDSHAKE *hs, CBB *out, - } - } - -- for (size_t unpermuted = 0; unpermuted < kNumExtensions; unpermuted++) { -+ const size_t numExtensions = hs->extension_permutation.empty() -+ ? kNumExtensions -+ : hs->extension_permutation.size(); -+ for (size_t unpermuted = 0; unpermuted < numExtensions; unpermuted++) { - size_t i = hs->extension_permutation.empty() - ? unpermuted - : hs->extension_permutation[unpermuted]; -+ if (i >= kNumExtensions) { -+ continue; -+ } - const size_t len_before = CBB_len(&extensions); - const size_t len_compressed_before = CBB_len(compressed.get()); - if (!kExtensions[i].add_clienthello(hs, &extensions, compressed.get(), -@@ -3466,10 +3647,16 @@ bool ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, CBB *out_encoded, - } - - bool last_was_empty = false; -- for (size_t unpermuted = 0; unpermuted < kNumExtensions; unpermuted++) { -+ const size_t numExtensions = hs->extension_permutation.empty() -+ ? kNumExtensions -+ : hs->extension_permutation.size(); -+ for (size_t unpermuted = 0; unpermuted < numExtensions; unpermuted++) { - size_t i = hs->extension_permutation.empty() - ? unpermuted - : hs->extension_permutation[unpermuted]; -+ if (i >= kNumExtensions) { -+ continue; -+ } - const size_t len_before = CBB_len(&extensions); - if (!kExtensions[i].add_clienthello(hs, &extensions, &extensions, type)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION); diff --git a/src/ssl/handoff.cc b/src/ssl/handoff.cc index 6e5cc2da1..b1b31f3a7 100644 --- a/src/ssl/handoff.cc @@ -4983,7 +5021,7 @@ index 6e5cc2da1..b1b31f3a7 100644 ticket_age_skew < std::numeric_limits::min()) { return false; diff --git a/src/ssl/handshake_client.cc b/src/ssl/handshake_client.cc -index 971ebd0b1..27a8abfae 100644 +index 971ebd0b1..c34c7c677 100644 --- a/src/ssl/handshake_client.cc +++ b/src/ssl/handshake_client.cc @@ -158,6 +158,8 @@ @@ -4995,7 +5033,69 @@ index 971ebd0b1..27a8abfae 100644 #include #include #include -@@ -1119,7 +1121,26 @@ static enum ssl_hs_wait_t do_read_server_key_exchange(SSL_HANDSHAKE *hs) { +@@ -243,23 +245,35 @@ static bool ssl_write_client_cipher_list(const SSL_HANDSHAKE *hs, CBB *out, + // Add TLS 1.3 ciphers. Order ChaCha20-Poly1305 relative to AES-GCM based on + // hardware support. + if (hs->max_version >= TLS1_3_VERSION) { +- const bool has_aes_hw = ssl->config->aes_hw_override +- ? ssl->config->aes_hw_override_value +- : EVP_has_aes_hardware(); +- +- if ((!has_aes_hw && // +- !ssl_add_tls13_cipher(&child, +- TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff, +- ssl->config->tls13_cipher_policy)) || +- !ssl_add_tls13_cipher(&child, TLS1_3_CK_AES_128_GCM_SHA256 & 0xffff, +- ssl->config->tls13_cipher_policy) || +- !ssl_add_tls13_cipher(&child, TLS1_3_CK_AES_256_GCM_SHA384 & 0xffff, +- ssl->config->tls13_cipher_policy) || +- (has_aes_hw && // +- !ssl_add_tls13_cipher(&child, +- TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff, +- ssl->config->tls13_cipher_policy))) { +- return false; ++ if (ssl->config->prefer_chacha20) { ++ if (!ssl_add_tls13_cipher(&child, TLS1_3_CK_AES_128_GCM_SHA256 & 0xffff, ++ ssl->config->tls13_cipher_policy) || ++ !ssl_add_tls13_cipher(&child, ++ TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff, ++ ssl->config->tls13_cipher_policy) || ++ !ssl_add_tls13_cipher(&child, TLS1_3_CK_AES_256_GCM_SHA384 & 0xffff, ++ ssl->config->tls13_cipher_policy)) { ++ return false; ++ } ++ } else { ++ const bool has_aes_hw = ssl->config->aes_hw_override ++ ? ssl->config->aes_hw_override_value ++ : EVP_has_aes_hardware(); ++ ++ if ((!has_aes_hw && // ++ !ssl_add_tls13_cipher(&child, ++ TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff, ++ ssl->config->tls13_cipher_policy)) || ++ !ssl_add_tls13_cipher(&child, TLS1_3_CK_AES_128_GCM_SHA256 & 0xffff, ++ ssl->config->tls13_cipher_policy) || ++ !ssl_add_tls13_cipher(&child, TLS1_3_CK_AES_256_GCM_SHA384 & 0xffff, ++ ssl->config->tls13_cipher_policy) || ++ (has_aes_hw && // ++ !ssl_add_tls13_cipher(&child, ++ TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff, ++ ssl->config->tls13_cipher_policy))) { ++ return false; ++ } + } + } + +@@ -538,7 +552,7 @@ static enum ssl_hs_wait_t do_start_connect(SSL_HANDSHAKE *hs) { + } + + if (!ssl_setup_key_shares(hs, /*override_group_id=*/0) || +- !ssl_setup_extension_permutation(hs) || ++ !ssl_setup_extension_order(hs) || + !ssl_encrypt_client_hello(hs, MakeConstSpan(ech_enc, ech_enc_len)) || + !ssl_add_client_hello(hs)) { + return ssl_hs_error; +@@ -1119,7 +1133,26 @@ static enum ssl_hs_wait_t do_read_server_key_exchange(SSL_HANDSHAKE *hs) { hs->peer_psk_identity_hint.reset(raw); } @@ -5023,7 +5123,7 @@ index 971ebd0b1..27a8abfae 100644 // Parse the server parameters. uint8_t group_type; uint16_t group_id; -@@ -1477,6 +1498,58 @@ static enum ssl_hs_wait_t do_send_client_key_exchange(SSL_HANDSHAKE *hs) { +@@ -1477,6 +1510,58 @@ static enum ssl_hs_wait_t do_send_client_key_exchange(SSL_HANDSHAKE *hs) { !CBB_flush(&body)) { return ssl_hs_error; } @@ -5083,7 +5183,7 @@ index 971ebd0b1..27a8abfae 100644 CBB child; if (!CBB_add_u8_length_prefixed(&body, &child)) { diff --git a/src/ssl/internal.h b/src/ssl/internal.h -index 1e6da2153..2a342d768 100644 +index 1e6da2153..2025dcae0 100644 --- a/src/ssl/internal.h +++ b/src/ssl/internal.h @@ -323,6 +323,19 @@ class Array { @@ -5183,7 +5283,18 @@ index 1e6da2153..2a342d768 100644 // peer_key is the peer's ECDH key for a TLS 1.2 client. Array peer_key; -@@ -3058,6 +3101,10 @@ struct SSL_CONFIG { +@@ -2132,6 +2175,10 @@ bool tls13_process_new_session_ticket(SSL *ssl, const SSLMessage &msg); + bssl::UniquePtr tls13_create_session_with_ticket(SSL *ssl, + CBS *body); + ++// defined by the provided extension order, or falls back ++// to ssl_setup_extension_permutation otherwise. ++bool ssl_setup_extension_order(SSL_HANDSHAKE *hs); ++ + // ssl_setup_extension_permutation computes a ClientHello extension permutation + // for |hs|, if applicable. It returns true on success and false on error. + bool ssl_setup_extension_permutation(SSL_HANDSHAKE *hs); +@@ -3058,6 +3105,10 @@ struct SSL_CONFIG { // verify_sigalgs, if not empty, is the set of signature algorithms // accepted from the peer in decreasing order of preference. Array verify_sigalgs; @@ -5194,7 +5305,7 @@ index 1e6da2153..2a342d768 100644 // srtp_profiles is the list of configured SRTP protection profiles for // DTLS-SRTP. -@@ -3128,6 +3175,16 @@ struct SSL_CONFIG { +@@ -3128,6 +3179,20 @@ struct SSL_CONFIG { // of support for AES hw. The value is only considered if |aes_hw_override| is // true. bool aes_hw_override_value : 1; @@ -5208,10 +5319,14 @@ index 1e6da2153..2a342d768 100644 + + // key_shares_limit is the maximum number of key shares to send. + uint8_t key_shares_limit = 0; ++ ++ // prefer_chacha20 indicates that ChaCha20-Poly1305 ciphers should be ++ // preferred over AES-GCM ciphers. It is only effective on the client side. ++ bool prefer_chacha20 : 1; }; // From RFC 8446, used in determining PSK modes. -@@ -3696,6 +3753,10 @@ struct ssl_ctx_st { +@@ -3696,6 +3761,10 @@ struct ssl_ctx_st { // accepted from the peer in decreasing order of preference. bssl::Array verify_sigalgs; @@ -5222,7 +5337,18 @@ index 1e6da2153..2a342d768 100644 // retain_only_sha256_of_client_certs is true if we should compute the SHA256 // hash of the peer's certificate and then discard it to save memory and // session space. Only effective on the server side. -@@ -3748,6 +3809,15 @@ struct ssl_ctx_st { +@@ -3723,6 +3792,10 @@ struct ssl_ctx_st { + // permute_extensions is whether to permute extensions when sending messages. + bool permute_extensions : 1; + ++ // rama_ssl_extension_order, if not empty, will use this actions ++ // as the order to be used to write the ssl extensions. ++ bssl::Array extension_order; ++ + // allow_unknown_alpn_protos is whether the client allows unsolicited ALPN + // protocols from the peer. + bool allow_unknown_alpn_protos : 1; +@@ -3748,6 +3821,16 @@ struct ssl_ctx_st { // |aes_hw_override| is true. bool aes_hw_override_value : 1; @@ -5232,8 +5358,9 @@ index 1e6da2153..2a342d768 100644 + // key_shares limit is the maximum number of key shares to send. + uint8_t key_shares_limit = 0; + -+ // extension_permutation is the permutation of extensions to send. -+ bssl::Array extension_permutation; ++ // prefer_chacha20 indicates that ChaCha20-Poly1305 ciphers should be ++ // preferred over AES-GCM ciphers. It is only effective on the client side. ++ bool prefer_chacha20 : 1; + private: ~ssl_ctx_st(); @@ -6197,24 +6324,26 @@ index 09a9ad380..9c583b5ec 100644 return nullptr; } diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc -index 838761af5..6f96d6eee 100644 +index 838761af5..2707f0150 100644 --- a/src/ssl/ssl_lib.cc +++ b/src/ssl/ssl_lib.cc -@@ -537,7 +537,8 @@ ssl_ctx_st::ssl_ctx_st(const SSL_METHOD *ssl_method) +@@ -537,7 +537,9 @@ ssl_ctx_st::ssl_ctx_st(const SSL_METHOD *ssl_method) handoff(false), enable_early_data(false), aes_hw_override(false), - aes_hw_override_value(false) { + aes_hw_override_value(false), -+ key_shares_limit(0) { ++ key_shares_limit(0), ++ prefer_chacha20(false) { CRYPTO_MUTEX_init(&lock); CRYPTO_new_ex_data(&ex_data); } -@@ -660,11 +661,13 @@ SSL *SSL_new(SSL_CTX *ctx) { +@@ -660,11 +662,14 @@ SSL *SSL_new(SSL_CTX *ctx) { ssl->config->aes_hw_override = ctx->aes_hw_override; ssl->config->aes_hw_override_value = ctx->aes_hw_override_value; ssl->config->tls13_cipher_policy = ctx->tls13_cipher_policy; + ssl->config->key_shares_limit = ctx->key_shares_limit; ++ ssl->config->prefer_chacha20 = ctx->prefer_chacha20; if (!ssl->config->supported_group_list.CopyFrom(ctx->supported_group_list) || !ssl->config->alpn_client_proto_list.CopyFrom( @@ -6225,7 +6354,7 @@ index 838761af5..6f96d6eee 100644 return nullptr; } -@@ -684,6 +687,7 @@ SSL *SSL_new(SSL_CTX *ctx) { +@@ -684,6 +689,7 @@ SSL *SSL_new(SSL_CTX *ctx) { ssl->config->signed_cert_timestamps_enabled = ctx->signed_cert_timestamps_enabled; ssl->config->ocsp_stapling_enabled = ctx->ocsp_stapling_enabled; @@ -6233,18 +6362,19 @@ index 838761af5..6f96d6eee 100644 ssl->config->handoff = ctx->handoff; ssl->quic_method = ctx->quic_method; -@@ -707,7 +711,9 @@ SSL_CONFIG::SSL_CONFIG(SSL *ssl_arg) +@@ -707,7 +713,10 @@ SSL_CONFIG::SSL_CONFIG(SSL *ssl_arg) shed_handshake_config(false), jdk11_workaround(false), quic_use_legacy_codepoint(false), - permute_extensions(false) { + permute_extensions(false), + key_shares_limit(0), -+ alps_use_new_codepoint(false) { ++ alps_use_new_codepoint(false), ++ prefer_chacha20(false) { assert(ssl); } -@@ -2134,6 +2140,46 @@ void SSL_enable_ocsp_stapling(SSL *ssl) { +@@ -2134,6 +2143,62 @@ void SSL_enable_ocsp_stapling(SSL *ssl) { ssl->config->ocsp_stapling_enabled = true; } @@ -6287,11 +6417,27 @@ index 838761af5..6f96d6eee 100644 + ssl->config->aes_hw_override = true; + ssl->config->aes_hw_override_value = !!override_value; +} ++ ++void SSL_CTX_set_prefer_chacha20(SSL_CTX *ctx, int prefer_chacha20) { ++ if (!ctx) { ++ return; ++ } ++ ++ ctx->prefer_chacha20 = !!prefer_chacha20; ++} ++ ++void SSL_set_prefer_chacha20(SSL *ssl, int prefer_chacha20) { ++ if (!ssl->config) { ++ return; ++ } ++ ++ ssl->config->prefer_chacha20 = !!prefer_chacha20; ++} + void SSL_get0_signed_cert_timestamp_list(const SSL *ssl, const uint8_t **out, size_t *out_len) { SSL_SESSION *session = SSL_get_session(ssl); -@@ -2327,6 +2373,13 @@ int SSL_has_application_settings(const SSL *ssl) { +@@ -2327,6 +2392,13 @@ int SSL_has_application_settings(const SSL *ssl) { return session && session->has_application_settings; } @@ -6305,32 +6451,29 @@ index 838761af5..6f96d6eee 100644 int SSL_CTX_add_cert_compression_alg(SSL_CTX *ctx, uint16_t alg_id, ssl_cert_compression_func_t compress, ssl_cert_decompression_func_t decompress) { -@@ -2939,6 +2992,24 @@ void SSL_set_permute_extensions(SSL *ssl, int enabled) { +@@ -2939,6 +3011,21 @@ void SSL_set_permute_extensions(SSL *ssl, int enabled) { ssl->config->permute_extensions = !!enabled; } -+int SSL_CTX_set_extension_permutation(SSL_CTX *ctx, const uint8_t *permutation, size_t permutation_len) { -+ if (!permutation || permutation_len == 0) { -+ return 0; ++int SSL_CTX_set_extension_order(SSL_CTX *ctx, const uint16_t *ids, int num) { ++ Array order; ++ if (num > 0) { ++ if (!order.Init(num)) { ++ return 0; ++ } ++ int i; ++ for (i = 0; i < num; i++) { ++ order[i] = ids[i]; ++ } + } -+ -+ bssl::Array arr; -+ if (!arr.Init(permutation_len)) { -+ return 0; -+ } -+ -+ for (size_t i = 0; i < permutation_len; ++i) { -+ arr[i] = permutation[i]; -+ } -+ -+ ctx->extension_permutation = std::move(arr); -+ return !ctx->extension_permutation.empty(); ++ ctx->extension_order = std::move(order); ++ return 1; +} + int32_t SSL_get_ticket_age_skew(const SSL *ssl) { return ssl->s3->ticket_age_skew; } -@@ -3151,7 +3222,7 @@ namespace fips202205 { +@@ -3151,7 +3238,7 @@ namespace fips202205 { // Section 3.3.1 // "The server shall be configured to only use cipher suites that are // composed entirely of NIST approved algorithms" diff --git a/boring/src/ssl/connector.rs b/boring/src/ssl/connector.rs index ca834e78..22a001a1 100644 --- a/boring/src/ssl/connector.rs +++ b/boring/src/ssl/connector.rs @@ -287,6 +287,13 @@ impl ConnectConfiguration { unsafe { ffi::SSL_set_aes_hw_override(self.as_ptr(), enable as _) } } + /// Sets whether the aes chacha20 preference should be enabled. + #[cfg(not(feature = "fips"))] + #[corresponds(SSL_set_prefer_chacha20)] + pub fn set_prefer_chacha20(&mut self, enable: bool) { + unsafe { ffi::SSL_set_prefer_chacha20(self.as_ptr(), enable as _) } + } + /// Adds application settings. /// /// # Arguments diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 1d0fe4b8..6f31e56f 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -532,6 +532,7 @@ impl SelectCertError { /// **WARNING**: The current implementation of `From` is unsound, as it's possible to create an /// ExtensionType that is not defined by the impl. `From` will be deprecated in favor of `TryFrom` /// in the next major bump of the library. +#[repr(transparent)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct ExtensionType(u16); @@ -571,50 +572,6 @@ impl ExtensionType { pub const NEXT_PROTO_NEG: Self = Self(ffi::TLSEXT_TYPE_next_proto_neg as u16); pub const CHANNEL_ID: Self = Self(ffi::TLSEXT_TYPE_channel_id as u16); pub const RECORD_SIZE_LIMIT: Self = Self(ffi::TLSEXT_TYPE_record_size_limit as u16); - - /// The permutation of extension types used by BoringSSL. - pub const BORING_SSLEXTENSION_PERMUTATION: &[ExtensionType] = &[ - ExtensionType::SERVER_NAME, - ExtensionType::ENCRYPTED_CLIENT_HELLO, - ExtensionType::EXTENDED_MASTER_SECRET, - ExtensionType::RENEGOTIATE, - ExtensionType::SUPPORTED_GROUPS, - ExtensionType::EC_POINT_FORMATS, - ExtensionType::SESSION_TICKET, - ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION, - ExtensionType::STATUS_REQUEST, - ExtensionType::SIGNATURE_ALGORITHMS, - ExtensionType::NEXT_PROTO_NEG, - ExtensionType::CERTIFICATE_TIMESTAMP, - ExtensionType::CHANNEL_ID, - ExtensionType::SRTP, - ExtensionType::KEY_SHARE, - ExtensionType::PSK_KEY_EXCHANGE_MODES, - ExtensionType::EARLY_DATA, - ExtensionType::SUPPORTED_VERSIONS, - ExtensionType::COOKIE, - ExtensionType::QUIC_TRANSPORT_PARAMETERS_STANDARD, - ExtensionType::QUIC_TRANSPORT_PARAMETERS_LEGACY, - ExtensionType::CERT_COMPRESSION, - ExtensionType::DELEGATED_CREDENTIAL, - ExtensionType::APPLICATION_SETTINGS, - ExtensionType::APPLICATION_SETTINGS_NEW, - ExtensionType::RECORD_SIZE_LIMIT, - ]; - - /// Returns the index of the given extension type in the permutation. - pub const fn index_of(value: ExtensionType) -> Option { - let mut i = 0; - while i < Self::BORING_SSLEXTENSION_PERMUTATION.len() { - if i < Self::BORING_SSLEXTENSION_PERMUTATION.len() - && Self::BORING_SSLEXTENSION_PERMUTATION[i].0 == value.0 - { - return Some(i); - } - i += 1; - } - None - } } impl From for ExtensionType { @@ -1953,26 +1910,22 @@ impl SslContextBuilder { unsafe { ffi::SSL_CTX_set_aes_hw_override(self.as_ptr(), enable as _) } } + /// Sets whether the aes chacha20 preference should be enabled. + #[cfg(not(feature = "fips"))] + #[corresponds(SSL_CTX_set_prefer_chacha20)] + pub fn set_prefer_chacha20(&mut self, enable: bool) { + unsafe { ffi::SSL_CTX_set_prefer_chacha20(self.as_ptr(), enable as _) } + } + /// Sets the indices of the extensions to be permuted. - /// - /// The indices must be in the range [0, 25). - /// Extension duplication will be verified by the user. - /// If duplication occurs, TLS connection failure may occur. - #[corresponds(SSL_CTX_set_extension_permutation)] + #[corresponds(SSL_CTX_set_extension_order)] #[cfg(not(feature = "fips-compat"))] pub fn set_extension_permutation( &mut self, - shuffled: &[ExtensionType], + indices: &[ExtensionType], ) -> Result<(), ErrorStack> { - let mut indices = Vec::with_capacity(shuffled.len().div_ceil(2)); - for &ext in shuffled { - if let Some(index) = ExtensionType::index_of(ext) { - indices.push(index as u8); - } - } - unsafe { - cvt(ffi::SSL_CTX_set_extension_permutation( + cvt(ffi::SSL_CTX_set_extension_order( self.as_ptr(), indices.as_ptr() as *const _, indices.len() as _, diff --git a/boring/src/ssl/test/extensions.rs b/boring/src/ssl/test/extensions.rs deleted file mode 100644 index d731cb7b..00000000 --- a/boring/src/ssl/test/extensions.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::ssl::ExtensionType; - -#[test] -fn test_exntension_order_index() { - for (i, ext) in ExtensionType::BORING_SSLEXTENSION_PERMUTATION - .iter() - .enumerate() - { - assert_eq!(ExtensionType::index_of(*ext), Some(i)); - } -} diff --git a/boring/src/ssl/test/mod.rs b/boring/src/ssl/test/mod.rs index 5bf9497c..240fcca2 100644 --- a/boring/src/ssl/test/mod.rs +++ b/boring/src/ssl/test/mod.rs @@ -30,7 +30,6 @@ mod cert_verify; mod custom_verify; #[cfg(not(feature = "fips"))] mod ech; -mod extensions; mod private_key_method; mod server; mod session; @@ -1167,3 +1166,84 @@ fn test_ssl_set_compliance() { ssl.set_compliance_policy(CompliancePolicy::NONE) .expect_err("Testing expect err if set compliance policy to NONE"); } + +#[test] +fn set_extension_permutation() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + // firefox extension permutation + ctx.set_extension_permutation(&[ + ExtensionType::SERVER_NAME, + ExtensionType::EXTENDED_MASTER_SECRET, + ExtensionType::RENEGOTIATE, + ExtensionType::SUPPORTED_GROUPS, + ExtensionType::EC_POINT_FORMATS, + ExtensionType::SESSION_TICKET, + ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION, + ExtensionType::STATUS_REQUEST, + ExtensionType::DELEGATED_CREDENTIAL, + ExtensionType::CERTIFICATE_TIMESTAMP, + ExtensionType::KEY_SHARE, + ExtensionType::SUPPORTED_VERSIONS, + ExtensionType::SIGNATURE_ALGORITHMS, + ExtensionType::PSK_KEY_EXCHANGE_MODES, + ExtensionType::RECORD_SIZE_LIMIT, + ExtensionType::CERT_COMPRESSION, + ExtensionType::ENCRYPTED_CLIENT_HELLO, + ]) + .unwrap(); +} + +#[test] +fn test_connect_with_set_extension_permutation_client_ctx() { + let server = Server::builder(); + let server = server.build(); + + let mut client = server.client(); + // firefox extension permutation + client + .ctx() + .set_extension_permutation(&[ + ExtensionType::SERVER_NAME, + ExtensionType::EXTENDED_MASTER_SECRET, + ExtensionType::RENEGOTIATE, + ExtensionType::SUPPORTED_GROUPS, + ExtensionType::EC_POINT_FORMATS, + ExtensionType::SESSION_TICKET, + ExtensionType::APPLICATION_LAYER_PROTOCOL_NEGOTIATION, + ExtensionType::STATUS_REQUEST, + ExtensionType::DELEGATED_CREDENTIAL, + ExtensionType::CERTIFICATE_TIMESTAMP, + ExtensionType::KEY_SHARE, + ExtensionType::SUPPORTED_VERSIONS, + ExtensionType::SIGNATURE_ALGORITHMS, + ExtensionType::PSK_KEY_EXCHANGE_MODES, + ExtensionType::RECORD_SIZE_LIMIT, + ExtensionType::CERT_COMPRESSION, + ExtensionType::ENCRYPTED_CLIENT_HELLO, + ]) + .unwrap(); + let _ = client.connect(); +} + +#[test] +fn test_connect_with_set_extension_permutation_empty_client_ctx() { + let server = Server::builder(); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_extension_permutation(&[]).unwrap(); + let _ = client.connect(); +} + +#[test] +fn test_connect_with_set_extension_permutation_server_name_client_ctx() { + let server = Server::builder(); + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .set_extension_permutation(&[ExtensionType::SERVER_NAME]) + .unwrap(); + let _ = client.connect(); +}