feat(boring): sync updated extension permutation patch (#80)

This commit is contained in:
0x676e67 2025-06-18 12:36:34 +08:00 committed by GitHub
parent 4ba97ba54e
commit eaf49e631e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 333 additions and 161 deletions

View File

@ -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<uint8_t> 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<uint32_t *>(OPENSSL_malloc(seeds_num * sizeof(uint32_t)));
+ if (!seeds) {
+ permutation.Reset();
+ return false;
+ }
+ if (!RAND_bytes(reinterpret_cast<uint8_t *>(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<uint8_t> 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<int32_t>::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 <openssl/ec_key.h>
#include <openssl/ecdsa.h>
#include <openssl/err.h>
@@ -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<uint8_t> 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<SSL_SESSION> 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<uint16_t> 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<uint16_t> 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<uint16_t> 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<uint8_t> 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) {
+int SSL_CTX_set_extension_order(SSL_CTX *ctx, const uint16_t *ids, int num) {
+ Array<uint16_t> order;
+ if (num > 0) {
+ if (!order.Init(num)) {
+ return 0;
+ }
+
+ bssl::Array<uint8_t> arr;
+ if (!arr.Init(permutation_len)) {
+ return 0;
+ int i;
+ for (i = 0; i < num; i++) {
+ order[i] = ids[i];
+ }
+
+ 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"

View File

@ -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

View File

@ -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<usize> {
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<u16> 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 _,

View File

@ -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));
}
}

View File

@ -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();
}