diff --git a/stuffer/s2n_stuffer.c b/stuffer/s2n_stuffer.c index a76a2f41546..134ec0ba9c8 100644 --- a/stuffer/s2n_stuffer.c +++ b/stuffer/s2n_stuffer.c @@ -323,6 +323,10 @@ int s2n_stuffer_write(struct s2n_stuffer *stuffer, const struct s2n_blob *in) int s2n_stuffer_write_bytes(struct s2n_stuffer *stuffer, const uint8_t *data, const uint32_t size) { + if (size == 0) { + return S2N_SUCCESS; + } + POSIX_ENSURE(S2N_MEM_IS_READABLE(data, size), S2N_ERR_SAFETY); POSIX_PRECONDITION(s2n_stuffer_validate(stuffer)); POSIX_GUARD(s2n_stuffer_skip_write(stuffer, size)); @@ -437,7 +441,13 @@ int s2n_stuffer_shift(struct s2n_stuffer *stuffer) POSIX_ENSURE_REF(stuffer); struct s2n_stuffer copy = *stuffer; POSIX_GUARD(s2n_stuffer_rewrite(©)); - uint8_t *data = stuffer->blob.data + stuffer->read_cursor; + + uint8_t *data = stuffer->blob.data; + /* Adding 0 to a NULL value is undefined behavior */ + if (stuffer->read_cursor != 0) { + data += stuffer->read_cursor; + } + uint32_t data_size = s2n_stuffer_data_available(stuffer); POSIX_GUARD(s2n_stuffer_write_bytes(©, data, data_size)); *stuffer = copy; diff --git a/tests/s2n_test.h b/tests/s2n_test.h index 7b79981355d..696ba68ed0d 100644 --- a/tests/s2n_test.h +++ b/tests/s2n_test.h @@ -200,7 +200,13 @@ int test_count; /* for use with S2N_RESULT */ #define EXPECT_OK( function_call ) EXPECT_TRUE( s2n_result_is_ok(function_call) ) -#define EXPECT_BYTEARRAY_EQUAL( p1, p2, l ) EXPECT_EQUAL( memcmp( (p1), (p2), (l) ), 0 ) +#define EXPECT_BYTEARRAY_EQUAL( p1, p2, l ) \ + do { \ + if (l != 0) { \ + EXPECT_EQUAL( memcmp( (p1), (p2), (l) ), 0 ); \ + } \ + } while (0) + #define EXPECT_BYTEARRAY_NOT_EQUAL( p1, p2, l ) EXPECT_NOT_EQUAL( memcmp( (p1), (p2), (l) ), 0 ) #define EXPECT_STRING_EQUAL( p1, p2 ) EXPECT_EQUAL( strcmp( (p1), (p2) ), 0 ) diff --git a/tests/testlib/s2n_test_server_client.c b/tests/testlib/s2n_test_server_client.c index ecaec2a752f..8ed01012c11 100644 --- a/tests/testlib/s2n_test_server_client.c +++ b/tests/testlib/s2n_test_server_client.c @@ -77,8 +77,13 @@ S2N_RESULT s2n_negotiate_test_server_and_client_with_early_data(struct s2n_conne bool server_early_done = false, client_early_done = false; do { if (!client_early_done) { + /* Adding 0 to a NULL value is undefined behavior */ + uint8_t *next_early_data_to_send = early_data_to_send->data; + if (total_data_sent != 0) { + next_early_data_to_send += total_data_sent; + } bool success = s2n_send_early_data(client_conn, - early_data_to_send->data + total_data_sent, + next_early_data_to_send, early_data_to_send->size - total_data_sent, &data_sent, &blocked) == S2N_SUCCESS; diff --git a/tests/unit/s2n_fingerprint_test.c b/tests/unit/s2n_fingerprint_test.c index 454a6b38a62..618d1ecc927 100644 --- a/tests/unit/s2n_fingerprint_test.c +++ b/tests/unit/s2n_fingerprint_test.c @@ -214,10 +214,10 @@ int main(int argc, char **argv) { /* Safety */ { - uint8_t output_value[1] = { 0 }; - EXPECT_ERROR_WITH_ERRNO( - s2n_fingerprint_hash_digest(NULL, output_value, sizeof(output_value)), - S2N_ERR_NULL); + struct s2n_fingerprint_hash hash = { 0 }; + struct s2n_blob output = { 0 }; + EXPECT_ERROR_WITH_ERRNO(s2n_fingerprint_hash_digest(NULL, &output), S2N_ERR_NULL); + EXPECT_ERROR_WITH_ERRNO(s2n_fingerprint_hash_digest(&hash, NULL), S2N_ERR_NULL); }; /* Digest successfully calculated */ @@ -229,10 +229,13 @@ int main(int argc, char **argv) EXPECT_OK(s2n_fingerprint_hash_add_str(&hash, test_str, test_str_len)); EXPECT_EQUAL(hash.hash->currently_in_hash, test_str_len); - uint8_t actual_digest[sizeof(test_str_digest)] = { 0 }; - EXPECT_OK(s2n_fingerprint_hash_digest(&hash, actual_digest, sizeof(actual_digest))); - EXPECT_BYTEARRAY_EQUAL(actual_digest, test_str_digest, sizeof(test_str_digest)); - EXPECT_EQUAL(hash.bytes_digested, test_str_len); + uint8_t digest_bytes[sizeof(test_str_digest)] = { 0 }; + struct s2n_blob actual_digest = { 0 }; + EXPECT_SUCCESS(s2n_blob_init(&actual_digest, digest_bytes, sizeof(digest_bytes))); + + EXPECT_OK(s2n_fingerprint_hash_digest(&hash, &actual_digest)); + EXPECT_BYTEARRAY_EQUAL(test_str_digest, actual_digest.data, actual_digest.size); + EXPECT_EQUAL(test_str_len, hash.bytes_digested); }; /* Hash can be reused after digest */ @@ -243,10 +246,14 @@ int main(int argc, char **argv) const size_t count = 10; for (size_t i = 0; i < count; i++) { - uint8_t actual_digest[sizeof(test_str_digest)] = { 0 }; + uint8_t digest_bytes[sizeof(test_str_digest)] = { 0 }; + struct s2n_blob actual_digest = { 0 }; + EXPECT_SUCCESS(s2n_blob_init(&actual_digest, digest_bytes, sizeof(digest_bytes))); + EXPECT_OK(s2n_fingerprint_hash_add_str(&hash, test_str, test_str_len)); - EXPECT_OK(s2n_fingerprint_hash_digest(&hash, actual_digest, sizeof(actual_digest))); - EXPECT_BYTEARRAY_EQUAL(actual_digest, test_str_digest, sizeof(test_str_digest)); + EXPECT_OK(s2n_fingerprint_hash_digest(&hash, &actual_digest)); + + EXPECT_BYTEARRAY_EQUAL(test_str_digest, actual_digest.data, actual_digest.size); } EXPECT_EQUAL(hash.bytes_digested, test_str_len * count); }; @@ -271,10 +278,10 @@ int main(int argc, char **argv) /* Test s2n_assert_grease_value */ { - EXPECT_TRUE(s2n_is_grease_value(0x0A0A)); - EXPECT_TRUE(s2n_is_grease_value(0xFAFA)); - EXPECT_FALSE(s2n_is_grease_value(0x0000)); - EXPECT_FALSE(s2n_is_grease_value(0x0001)); + EXPECT_TRUE(s2n_fingerprint_is_grease_value(0x0A0A)); + EXPECT_TRUE(s2n_fingerprint_is_grease_value(0xFAFA)); + EXPECT_FALSE(s2n_fingerprint_is_grease_value(0x0000)); + EXPECT_FALSE(s2n_fingerprint_is_grease_value(0x0001)); }; /* Test s2n_fingerprint_new / s2n_fingerprint_free */ diff --git a/tls/s2n_fingerprint.c b/tls/s2n_fingerprint.c index f31bc4aee08..548a69b34b9 100644 --- a/tls/s2n_fingerprint.c +++ b/tls/s2n_fingerprint.c @@ -187,7 +187,7 @@ static S2N_RESULT s2n_assert_grease_value(uint16_t val) *= https://raw.githubusercontent.com/FoxIO-LLC/ja4/v0.18.2/technical_details/JA4.md#details *# The program needs to ignore GREASE values anywhere it sees them */ -bool s2n_is_grease_value(uint16_t val) +bool s2n_fingerprint_is_grease_value(uint16_t val) { return s2n_result_is_ok(s2n_assert_grease_value(val)); } @@ -247,16 +247,17 @@ S2N_RESULT s2n_fingerprint_hash_add_bytes(struct s2n_fingerprint_hash *hash, return S2N_RESULT_OK; } -S2N_RESULT s2n_fingerprint_hash_digest(struct s2n_fingerprint_hash *hash, uint8_t *out, size_t out_size) +S2N_RESULT s2n_fingerprint_hash_digest(struct s2n_fingerprint_hash *hash, struct s2n_blob *out) { RESULT_ENSURE_REF(hash); RESULT_ENSURE_REF(hash->hash); + RESULT_ENSURE_REF(out); uint64_t bytes = 0; RESULT_GUARD_POSIX(s2n_hash_get_currently_in_hash_total(hash->hash, &bytes)); hash->bytes_digested += bytes; - RESULT_GUARD_POSIX(s2n_hash_digest(hash->hash, out, out_size)); + RESULT_GUARD_POSIX(s2n_hash_digest(hash->hash, out->data, out->size)); RESULT_GUARD_POSIX(s2n_hash_reset(hash->hash)); return S2N_RESULT_OK; } diff --git a/tls/s2n_fingerprint.h b/tls/s2n_fingerprint.h index 1752f211ec6..895155e0557 100644 --- a/tls/s2n_fingerprint.h +++ b/tls/s2n_fingerprint.h @@ -40,7 +40,7 @@ struct s2n_fingerprint_hash { S2N_RESULT s2n_fingerprint_hash_add_char(struct s2n_fingerprint_hash *hash, char c); S2N_RESULT s2n_fingerprint_hash_add_str(struct s2n_fingerprint_hash *hash, const char *str, size_t str_size); S2N_RESULT s2n_fingerprint_hash_add_bytes(struct s2n_fingerprint_hash *hash, const uint8_t *b, size_t size); -S2N_RESULT s2n_fingerprint_hash_digest(struct s2n_fingerprint_hash *hash, uint8_t *out, size_t out_size); +S2N_RESULT s2n_fingerprint_hash_digest(struct s2n_fingerprint_hash *hash, struct s2n_blob *out); bool s2n_fingerprint_hash_do_digest(struct s2n_fingerprint_hash *hash); struct s2n_fingerprint_method { @@ -52,6 +52,6 @@ struct s2n_fingerprint_method { extern struct s2n_fingerprint_method ja3_fingerprint; extern struct s2n_fingerprint_method ja4_fingerprint; -bool s2n_is_grease_value(uint16_t val); +bool s2n_fingerprint_is_grease_value(uint16_t val); S2N_RESULT s2n_fingerprint_parse_extension(struct s2n_stuffer *input, uint16_t *iana); S2N_RESULT s2n_fingerprint_get_legacy_version(struct s2n_client_hello *ch, uint16_t *version); diff --git a/tls/s2n_fingerprint_ja3.c b/tls/s2n_fingerprint_ja3.c index 76bd3b0c89e..1a820ba688d 100644 --- a/tls/s2n_fingerprint_ja3.c +++ b/tls/s2n_fingerprint_ja3.c @@ -32,10 +32,9 @@ static S2N_RESULT s2n_fingerprint_ja3_digest(struct s2n_fingerprint_hash *hash, } uint8_t digest_bytes[MD5_DIGEST_LENGTH] = { 0 }; - RESULT_GUARD(s2n_fingerprint_hash_digest(hash, digest_bytes, sizeof(digest_bytes))); - struct s2n_blob digest = { 0 }; RESULT_GUARD_POSIX(s2n_blob_init(&digest, digest_bytes, sizeof(digest_bytes))); + RESULT_GUARD(s2n_fingerprint_hash_digest(hash, &digest)); RESULT_GUARD(s2n_stuffer_write_hex(out, &digest)); return S2N_RESULT_OK; @@ -44,7 +43,7 @@ static S2N_RESULT s2n_fingerprint_ja3_digest(struct s2n_fingerprint_hash *hash, static S2N_RESULT s2n_fingerprint_ja3_iana(struct s2n_fingerprint_hash *hash, bool *is_list, uint16_t iana) { - if (s2n_is_grease_value(iana)) { + if (s2n_fingerprint_is_grease_value(iana)) { return S2N_RESULT_OK; } diff --git a/tls/s2n_fingerprint_ja4.c b/tls/s2n_fingerprint_ja4.c index c4e59c03a11..606caffe6a0 100644 --- a/tls/s2n_fingerprint_ja4.c +++ b/tls/s2n_fingerprint_ja4.c @@ -104,7 +104,7 @@ static S2N_RESULT s2n_fingerprint_ja4_digest(struct s2n_fingerprint_hash *hash, uint8_t digest_bytes[SHA256_DIGEST_LENGTH] = { 0 }; struct s2n_blob digest = { 0 }; RESULT_GUARD_POSIX(s2n_blob_init(&digest, digest_bytes, sizeof(digest_bytes))); - RESULT_GUARD(s2n_fingerprint_hash_digest(hash, digest.data, digest.size)); + RESULT_GUARD(s2n_fingerprint_hash_digest(hash, &digest)); /* JA4 digests are truncated */ RESULT_ENSURE_LTE(S2N_JA4_DIGEST_BYTE_LIMIT, digest.size); @@ -162,7 +162,7 @@ static S2N_RESULT s2n_fingerprint_get_extension_version(struct s2n_client_hello *= https://raw.githubusercontent.com/FoxIO-LLC/ja4/v0.18.2/technical_details/JA4.md#tls-version *# Remember to ignore GREASE values. */ - if (s2n_is_grease_value(version)) { + if (s2n_fingerprint_is_grease_value(version)) { continue; } /** @@ -344,7 +344,7 @@ static S2N_RESULT s2n_fingerprint_ja4_ciphers(struct s2n_fingerprint_hash *hash, *= https://raw.githubusercontent.com/FoxIO-LLC/ja4/v0.18.2/technical_details/JA4.md#number-of-ciphers *# Remember, ignore GREASE values. They don’t count. */ - if (s2n_is_grease_value(iana)) { + if (s2n_fingerprint_is_grease_value(iana)) { continue; } RESULT_GUARD(s2n_stuffer_write_uint16_hex(iana_list, iana)); @@ -409,7 +409,7 @@ static S2N_RESULT s2n_fingerprint_ja4_extensions(struct s2n_fingerprint_hash *ha *= https://raw.githubusercontent.com/FoxIO-LLC/ja4/v0.18.2/technical_details/JA4.md#number-of-extensions *# Ignore GREASE. */ - if (s2n_is_grease_value(iana)) { + if (s2n_fingerprint_is_grease_value(iana)) { continue; } @@ -470,7 +470,7 @@ static S2N_RESULT s2n_fingerprint_ja4_sig_algs(struct s2n_fingerprint_hash *hash while (s2n_stuffer_data_available(&sig_algs)) { uint16_t iana = 0; RESULT_GUARD_POSIX(s2n_stuffer_read_uint16(&sig_algs, &iana)); - if (s2n_is_grease_value(iana)) { + if (s2n_fingerprint_is_grease_value(iana)) { continue; } if (is_first) {