Skip to content

Commit 1f9a9c6

Browse files
author
Boquan Fang
committed
refactor: replace s2n_raw_write and add large client hello test
1 parent 9e0259b commit 1f9a9c6

File tree

5 files changed

+167
-17
lines changed

5 files changed

+167
-17
lines changed

crypto/s2n_ecc_evp.c

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -412,22 +412,18 @@ int s2n_ecc_evp_write_params_point(struct s2n_ecc_evp_params *ecc_evp_params, st
412412
POSIX_ENSURE_REF(out);
413413

414414
#if EVP_APIS_SUPPORTED
415-
struct s2n_blob point_blob = { 0 };
416415
uint8_t *encoded_point = NULL;
417416

418417
size_t size = EVP_PKEY_get1_tls_encodedpoint(ecc_evp_params->evp_pkey, &encoded_point);
419418
if (size != ecc_evp_params->negotiated_curve->share_size) {
420419
OPENSSL_free(encoded_point);
421420
POSIX_BAIL(S2N_ERR_ECDHE_SERIALIZING);
422421
} else {
423-
point_blob.data = s2n_stuffer_raw_write(out, ecc_evp_params->negotiated_curve->share_size);
424-
POSIX_ENSURE_REF(point_blob.data);
425-
POSIX_CHECKED_MEMCPY(point_blob.data, encoded_point, size);
422+
POSIX_GUARD(s2n_stuffer_write_bytes(out, encoded_point, size));
426423
OPENSSL_free(encoded_point);
427424
}
428425
#else
429-
uint8_t point_len;
430-
struct s2n_blob point_blob = { 0 };
426+
uint8_t point_len = 0;
431427

432428
DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(ecc_evp_params->evp_pkey), EC_KEY_free_pointer);
433429
S2N_ERROR_IF(ec_key == NULL, S2N_ERR_ECDHE_UNSUPPORTED_CURVE);
@@ -437,11 +433,19 @@ int s2n_ecc_evp_write_params_point(struct s2n_ecc_evp_params *ecc_evp_params, st
437433

438434
POSIX_GUARD(s2n_ecc_evp_calculate_point_length(point, group, &point_len));
439435
S2N_ERROR_IF(point_len != ecc_evp_params->negotiated_curve->share_size, S2N_ERR_ECDHE_SERIALIZING);
440-
point_blob.data = s2n_stuffer_raw_write(out, point_len);
441-
POSIX_ENSURE_REF(point_blob.data);
442-
point_blob.size = point_len;
443436

444-
POSIX_GUARD(s2n_ecc_evp_write_point_data_snug(point, group, &point_blob));
437+
/* A safer way to do s2n_stuffer_raw_write without tainted the out stuffer */
438+
POSIX_GUARD(s2n_stuffer_reserve_space(out, point_len));
439+
struct s2n_stuffer copy = *out;
440+
{
441+
struct s2n_blob point_blob = { 0 };
442+
point_blob.data = s2n_stuffer_raw_write(&copy, point_len);
443+
POSIX_ENSURE_REF(point_blob.data);
444+
point_blob.size = point_len;
445+
446+
POSIX_GUARD(s2n_ecc_evp_write_point_data_snug(point, group, &point_blob));
447+
}
448+
out->write_cursor += point_len;
445449
#endif
446450
return 0;
447451
}
@@ -456,8 +460,14 @@ int s2n_ecc_evp_write_params(struct s2n_ecc_evp_params *ecc_evp_params, struct s
456460
POSIX_ENSURE_REF(written);
457461

458462
uint8_t key_share_size = ecc_evp_params->negotiated_curve->share_size;
459-
/* Remember where the written data starts */
460-
written->data = s2n_stuffer_raw_write(out, 0);
463+
/**
464+
* Remember where the written data starts with
465+
* a safer way to do s2n_stuffer_raw_write without tainted the out stuffer.
466+
*/
467+
struct s2n_stuffer copy = *out;
468+
{
469+
written->data = s2n_stuffer_raw_write(&copy, 0);
470+
}
461471
POSIX_ENSURE_REF(written->data);
462472

463473
POSIX_GUARD(s2n_stuffer_write_uint8(out, TLS_EC_CURVE_TYPE_NAMED));

tests/unit/s2n_client_hello_test.c

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@
4444
#define COMPRESSION_METHODS 0x00, 0x01, 0x02, 0x03, 0x04
4545
#define COMPRESSION_METHODS_LEN 0x05
4646

47+
#define CIPHER_SUITES_MAX_LENGTH (UINT16_MAX - 2)
48+
#define NUM_OF_CIPHER_SUITES_TO_DROP 150
49+
#define MAXIMUM_NUM_OF_CIPHER_SUITES (CIPHER_SUITES_MAX_LENGTH / S2N_TLS_CIPHER_SUITE_LEN)
50+
/* Drop 150 cipher suites from max, so that the total handshake message length won't exceed 64KB */
51+
#define REDUCED_CIPHER_SUITE_COUNT (MAXIMUM_NUM_OF_CIPHER_SUITES - NUM_OF_CIPHER_SUITES_TO_DROP)
52+
/* Reducing cipher suites by 150 creates approximately 300 bytes margin below maximum handshake length */
53+
#define ESTMATIED_MAX_HANDSHAKE_LENGTH_MARGIN (NUM_OF_CIPHER_SUITES_TO_DROP * S2N_TLS_CIPHER_SUITE_LEN)
54+
4755
int s2n_parse_client_hello(struct s2n_connection *conn);
4856
S2N_RESULT s2n_client_hello_get_raw_extension(uint16_t extension_iana,
4957
struct s2n_blob *raw_extensions, struct s2n_blob *extension);
@@ -1953,6 +1961,138 @@ int main(int argc, char **argv)
19531961
};
19541962
};
19551963

1964+
/* Test: Client Hello is slightly less than 64KB */
1965+
{
1966+
DEFER_CLEANUP(struct s2n_config *client_config = s2n_config_new(), s2n_config_ptr_free);
1967+
EXPECT_NOT_NULL(client_config);
1968+
1969+
DEFER_CLEANUP(struct s2n_config *server_config = s2n_config_new(), s2n_config_ptr_free);
1970+
EXPECT_NOT_NULL(server_config);
1971+
1972+
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, chain_and_key));
1973+
1974+
struct s2n_cipher_suite *test_cipher_suites[REDUCED_CIPHER_SUITE_COUNT] = { 0 };
1975+
1976+
for (int i = 0; i < REDUCED_CIPHER_SUITE_COUNT; i++) {
1977+
test_cipher_suites[i] = &s2n_rsa_with_aes_128_gcm_sha256;
1978+
}
1979+
1980+
const struct s2n_cipher_preferences test_cipher_suites_preferences = {
1981+
.count = s2n_array_len(test_cipher_suites),
1982+
.suites = test_cipher_suites,
1983+
};
1984+
1985+
struct s2n_security_policy test_security_policy = {
1986+
.minimum_protocol_version = S2N_TLS12,
1987+
.cipher_preferences = &test_cipher_suites_preferences,
1988+
.kem_preferences = &kem_preferences_null,
1989+
.signature_preferences = &s2n_signature_preferences_20240501,
1990+
.ecc_preferences = &s2n_ecc_preferences_20240501,
1991+
.rules = {
1992+
[S2N_PERFECT_FORWARD_SECRECY] = true,
1993+
},
1994+
};
1995+
1996+
EXPECT_SUCCESS(s2n_config_disable_x509_verification(client_config));
1997+
1998+
DEFER_CLEANUP(struct s2n_connection *client = s2n_connection_new(S2N_CLIENT),
1999+
s2n_connection_ptr_free);
2000+
EXPECT_NOT_NULL(client);
2001+
EXPECT_SUCCESS(s2n_connection_set_config(client, client_config));
2002+
EXPECT_SUCCESS(s2n_connection_set_blinding(client, S2N_SELF_SERVICE_BLINDING));
2003+
client->security_policy_override = &test_security_policy;
2004+
2005+
DEFER_CLEANUP(struct s2n_connection *server = s2n_connection_new(S2N_SERVER),
2006+
s2n_connection_ptr_free);
2007+
EXPECT_NOT_NULL(server);
2008+
EXPECT_SUCCESS(s2n_connection_set_config(server, server_config));
2009+
EXPECT_SUCCESS(s2n_connection_set_blinding(server, S2N_SELF_SERVICE_BLINDING));
2010+
server->security_policy_override = &test_security_policy;
2011+
2012+
DEFER_CLEANUP(struct s2n_test_io_stuffer_pair io_pair = { 0 }, s2n_io_stuffer_pair_free);
2013+
EXPECT_OK(s2n_io_stuffer_pair_init(&io_pair));
2014+
EXPECT_OK(s2n_connections_set_io_stuffer_pair(client, server, &io_pair));
2015+
2016+
EXPECT_OK(s2n_negotiate_test_server_and_client_until_message(server, client, SERVER_HELLO));
2017+
2018+
/* handshake.io shouldn't be tainted after sending and receiving large client hello */
2019+
EXPECT_TRUE(client->handshake.io.tainted == 0);
2020+
EXPECT_TRUE(server->handshake.io.tainted == 0);
2021+
2022+
struct s2n_client_hello *client_hello = s2n_connection_get_client_hello(server);
2023+
EXPECT_NOT_NULL(client_hello);
2024+
uint32_t handshake_max_len_margin = S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH - s2n_client_hello_get_raw_message_length(client_hello);
2025+
/* Size of Client Hello is less than 300 bytes from the maximum handshake length */
2026+
EXPECT_TRUE(handshake_max_len_margin < ESTMATIED_MAX_HANDSHAKE_LENGTH_MARGIN);
2027+
}
2028+
2029+
/* Test: Client Hello is larger than 64KB */
2030+
{
2031+
DEFER_CLEANUP(struct s2n_config *client_config = s2n_config_new(), s2n_config_ptr_free);
2032+
EXPECT_NOT_NULL(client_config);
2033+
2034+
DEFER_CLEANUP(struct s2n_config *server_config = s2n_config_new(), s2n_config_ptr_free);
2035+
EXPECT_NOT_NULL(server_config);
2036+
2037+
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_config, chain_and_key));
2038+
2039+
struct s2n_cipher_suite *test_cipher_suites[MAXIMUM_NUM_OF_CIPHER_SUITES] = { 0 };
2040+
2041+
for (int i = 0; i < MAXIMUM_NUM_OF_CIPHER_SUITES; i++) {
2042+
test_cipher_suites[i] = &s2n_rsa_with_aes_128_gcm_sha256;
2043+
}
2044+
2045+
/* We append the maximun number of cipher suites, so that the Client Hello size grows beyond 64KB */
2046+
const struct s2n_cipher_preferences test_cipher_suites_preferences = {
2047+
.count = s2n_array_len(test_cipher_suites),
2048+
.suites = test_cipher_suites,
2049+
};
2050+
2051+
struct s2n_security_policy test_security_policy = {
2052+
.minimum_protocol_version = S2N_TLS12,
2053+
.cipher_preferences = &test_cipher_suites_preferences,
2054+
.kem_preferences = &kem_preferences_null,
2055+
.signature_preferences = &s2n_signature_preferences_20240501,
2056+
.ecc_preferences = &s2n_ecc_preferences_20240501,
2057+
.rules = {
2058+
[S2N_PERFECT_FORWARD_SECRECY] = true,
2059+
},
2060+
};
2061+
2062+
EXPECT_SUCCESS(s2n_config_disable_x509_verification(client_config));
2063+
2064+
DEFER_CLEANUP(struct s2n_connection *client = s2n_connection_new(S2N_CLIENT),
2065+
s2n_connection_ptr_free);
2066+
EXPECT_NOT_NULL(client);
2067+
EXPECT_SUCCESS(s2n_connection_set_config(client, client_config));
2068+
EXPECT_SUCCESS(s2n_connection_set_blinding(client, S2N_SELF_SERVICE_BLINDING));
2069+
client->security_policy_override = &test_security_policy;
2070+
2071+
DEFER_CLEANUP(struct s2n_connection *server = s2n_connection_new(S2N_SERVER),
2072+
s2n_connection_ptr_free);
2073+
EXPECT_NOT_NULL(server);
2074+
EXPECT_SUCCESS(s2n_connection_set_config(server, server_config));
2075+
EXPECT_SUCCESS(s2n_connection_set_blinding(server, S2N_SELF_SERVICE_BLINDING));
2076+
server->security_policy_override = &test_security_policy;
2077+
2078+
DEFER_CLEANUP(struct s2n_test_io_stuffer_pair io_pair = { 0 }, s2n_io_stuffer_pair_free);
2079+
EXPECT_OK(s2n_io_stuffer_pair_init(&io_pair));
2080+
EXPECT_OK(s2n_connections_set_io_stuffer_pair(client, server, &io_pair));
2081+
2082+
s2n_blocked_status blocked = S2N_NOT_BLOCKED;
2083+
2084+
/* Write Client Hello into io_pair.server_in */
2085+
s2n_negotiate(client, &blocked);
2086+
2087+
/* The size of Client Hello exceeds S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH */
2088+
EXPECT_TRUE(io_pair.server_in.write_cursor > S2N_MAXIMUM_HANDSHAKE_MESSAGE_LENGTH);
2089+
EXPECT_ERROR_WITH_ERRNO(s2n_negotiate_test_server_and_client_until_message(server, client, SERVER_HELLO), S2N_ERR_BAD_MESSAGE);
2090+
2091+
/* handshake.io shouldn't be tainted after sending and receiving large client hello */
2092+
EXPECT_TRUE(client->handshake.io.tainted == 0);
2093+
EXPECT_TRUE(server->handshake.io.tainted == 0);
2094+
}
2095+
19562096
EXPECT_SUCCESS(s2n_cert_chain_and_key_free(chain_and_key));
19572097
EXPECT_SUCCESS(s2n_cert_chain_and_key_free(ecdsa_chain_and_key));
19582098
END_TEST();

tls/extensions/s2n_client_early_data_indication.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ static S2N_RESULT s2n_early_data_config_is_possible(struct s2n_connection *conn)
7171

7272
/* Early data must require a supported cipher */
7373
bool match = false;
74-
for (uint8_t i = 0; i < cipher_preferences->count; i++) {
74+
for (size_t i = 0; i < cipher_preferences->count; i++) {
7575
if (cipher_preferences->suites[i] == early_data_config->cipher_suite) {
7676
match = true;
7777
break;

tls/s2n_cipher_preferences.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
#include "tls/s2n_tls13.h"
2323

2424
struct s2n_cipher_preferences {
25-
uint8_t count;
25+
uint16_t count;
2626
struct s2n_cipher_suite **suites;
2727
bool allow_chacha20_boosting;
2828
};

tls/s2n_security_policies.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,7 +1509,7 @@ bool s2n_ecc_is_extension_required(const struct s2n_security_policy *security_po
15091509
if (cipher_preferences == NULL) {
15101510
return false;
15111511
}
1512-
for (uint8_t i = 0; i < cipher_preferences->count; i++) {
1512+
for (size_t i = 0; i < cipher_preferences->count; i++) {
15131513
if (s2n_cipher_suite_requires_ecc_extension(cipher_preferences->suites[i])) {
15141514
return true;
15151515
}
@@ -1540,7 +1540,7 @@ bool s2n_pq_kem_is_extension_required(const struct s2n_security_policy *security
15401540
if (cipher_preferences == NULL) {
15411541
return false;
15421542
}
1543-
for (uint8_t i = 0; i < cipher_preferences->count; i++) {
1543+
for (size_t i = 0; i < cipher_preferences->count; i++) {
15441544
if (s2n_cipher_suite_requires_pq_extension(cipher_preferences->suites[i])) {
15451545
return true;
15461546
}
@@ -1569,7 +1569,7 @@ bool s2n_security_policy_supports_tls13(const struct s2n_security_policy *securi
15691569
return false;
15701570
}
15711571

1572-
for (uint8_t i = 0; i < cipher_preferences->count; i++) {
1572+
for (size_t i = 0; i < cipher_preferences->count; i++) {
15731573
if (cipher_preferences->suites[i]->minimum_required_tls_version >= S2N_TLS13) {
15741574
return true;
15751575
}

0 commit comments

Comments
 (0)