From 463b17e2262687b5f9604a771f79343202a47134 Mon Sep 17 00:00:00 2001 From: Lindsay Stewart Date: Wed, 17 Jul 2024 09:45:35 -0700 Subject: [PATCH 1/2] refactor: move stuffer hex methods out of testlib --- error/s2n_errno.c | 1 + error/s2n_errno.h | 1 + stuffer/s2n_stuffer.h | 17 + stuffer/s2n_stuffer_hex.c | 160 ++++++ tests/testlib/s2n_stuffer_hex.c | 198 -------- tests/testlib/s2n_stuffer_testlib.c | 35 ++ tests/testlib/s2n_testlib.h | 13 +- tests/unit/s2n_fingerprint_test.c | 2 +- tests/unit/s2n_hash_test.c | 18 +- tests/unit/s2n_hmac_test.c | 28 +- tests/unit/s2n_self_talk_key_log_test.c | 4 +- tests/unit/s2n_ssl_prf_test.c | 8 +- tests/unit/s2n_stuffer_hex_test.c | 628 +++++++++++++++++++++--- tests/unit/s2n_tls13_prf_test.c | 8 +- 14 files changed, 800 insertions(+), 321 deletions(-) create mode 100644 stuffer/s2n_stuffer_hex.c delete mode 100644 tests/testlib/s2n_stuffer_hex.c create mode 100644 tests/testlib/s2n_stuffer_testlib.c diff --git a/error/s2n_errno.c b/error/s2n_errno.c index 49aab545c09..ebc5eca84a7 100644 --- a/error/s2n_errno.c +++ b/error/s2n_errno.c @@ -312,6 +312,7 @@ static const char *no_such_error = "Internal s2n error"; ERR_ENTRY(S2N_ERR_MISSING_CLIENT_CERT, "Server requires client certificate") \ ERR_ENTRY(S2N_ERR_INVALID_SERIALIZED_CONNECTION, "Serialized connection is invalid"); \ ERR_ENTRY(S2N_ERR_TOO_MANY_CAS, "Too many certificate authorities in trust store"); \ + ERR_ENTRY(S2N_ERR_BAD_HEX, "Could not parse malformed hex string"); \ /* clang-format on */ #define ERR_STR_CASE(ERR, str) \ diff --git a/error/s2n_errno.h b/error/s2n_errno.h index 838f7d10388..9e8a752e183 100644 --- a/error/s2n_errno.h +++ b/error/s2n_errno.h @@ -237,6 +237,7 @@ typedef enum { S2N_ERR_LIBCRYPTO_VERSION_NUMBER_MISMATCH, S2N_ERR_LIBCRYPTO_VERSION_NAME_MISMATCH, S2N_ERR_OSSL_PROVIDER, + S2N_ERR_BAD_HEX, S2N_ERR_TEST_ASSERTION, S2N_ERR_T_INTERNAL_END, diff --git a/stuffer/s2n_stuffer.h b/stuffer/s2n_stuffer.h index 9a8fc37ae31..c91e5211289 100644 --- a/stuffer/s2n_stuffer.h +++ b/stuffer/s2n_stuffer.h @@ -154,6 +154,23 @@ int S2N_RESULT_MUST_USE s2n_stuffer_write_vector_size(struct s2n_stuffer_reserva /* Copy one stuffer to another */ int s2n_stuffer_copy(struct s2n_stuffer *from, struct s2n_stuffer *to, uint32_t len); +/* Convert between hex strings and raw bytes. + * + * When reading hex, the characters can be uppercase or lowercase. + * When writing hex, lowercase characters are used. + * + * Examples: + * "1234567890ABCdef" == [ 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef ] + * "FF" == 255 or [ 0xff ] + * "0001" == 1 or [ 0x00, 0x01 ] + */ +S2N_RESULT s2n_stuffer_read_hex(struct s2n_stuffer *bytes_out, const struct s2n_blob *hex_in); +S2N_RESULT s2n_stuffer_write_hex(struct s2n_stuffer *hex_out, const struct s2n_blob *bytes_in); +S2N_RESULT s2n_stuffer_read_uint8_hex(struct s2n_stuffer *stuffer, uint8_t *u); +S2N_RESULT s2n_stuffer_write_uint8_hex(struct s2n_stuffer *stuffer, uint8_t u); +S2N_RESULT s2n_stuffer_read_uint16_hex(struct s2n_stuffer *stuffer, uint16_t *u); +S2N_RESULT s2n_stuffer_write_uint16_hex(struct s2n_stuffer *stuffer, uint16_t u); + /* Read and write base64 */ int s2n_stuffer_read_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *out); int s2n_stuffer_write_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *in); diff --git a/stuffer/s2n_stuffer_hex.c b/stuffer/s2n_stuffer_hex.c new file mode 100644 index 00000000000..63256855b81 --- /dev/null +++ b/stuffer/s2n_stuffer_hex.c @@ -0,0 +1,160 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include "error/s2n_errno.h" +#include "stuffer/s2n_stuffer.h" +#include "utils/s2n_safety.h" + +static const uint8_t value_to_hex[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +}; + +static const uint8_t hex_to_value[] = { + /* clang-format off */ + ['0'] = 0, ['1'] = 1, ['2'] = 2, ['3'] = 3, ['4'] = 4, + ['5'] = 5, ['6'] = 6, ['7'] = 7, ['8'] = 8, ['9'] = 9, + ['a'] = 10, ['b'] = 11, ['c'] = 12, ['d'] = 13, ['e'] = 14, ['f'] = 15, + ['A'] = 10, ['B'] = 11, ['C'] = 12, ['D'] = 13, ['E'] = 14, ['F'] = 15, + /* clang-format on */ +}; + +static S2N_RESULT s2n_stuffer_hex_validate_char(uint8_t c) +{ + RESULT_ENSURE(c < s2n_array_len(hex_to_value), S2N_ERR_BAD_HEX); + if (hex_to_value[c] == 0) { + RESULT_ENSURE(c == '0', S2N_ERR_BAD_HEX); + } + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_stuffer_read_hex(struct s2n_stuffer *bytes_out, const struct s2n_blob *hex_in) +{ + RESULT_PRECONDITION(s2n_stuffer_validate(bytes_out)); + RESULT_PRECONDITION(s2n_blob_validate(hex_in)); + + size_t hex_size = hex_in->size; + size_t bytes_size = hex_in->size / 2; + RESULT_ENSURE(hex_size % 2 == 0, S2N_ERR_BAD_HEX); + if (hex_size == 0) { + return S2N_RESULT_OK; + } + + RESULT_GUARD_POSIX(s2n_stuffer_reserve_space(bytes_out, bytes_size)); + uint8_t *out = bytes_out->blob.data + bytes_out->write_cursor; + uint8_t *in = hex_in->data; + + for (size_t i = 0; i < bytes_size; i++) { + uint8_t hex_high = in[(i * 2)]; + RESULT_GUARD(s2n_stuffer_hex_validate_char(hex_high)); + + uint8_t hex_low = in[(i * 2) + 1]; + RESULT_GUARD(s2n_stuffer_hex_validate_char(hex_low)); + + out[i] = hex_to_value[hex_low]; + out[i] += hex_to_value[hex_high] * 16; + } + + RESULT_GUARD_POSIX(s2n_stuffer_skip_write(bytes_out, bytes_size)); + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_stuffer_write_hex(struct s2n_stuffer *hex_out, const struct s2n_blob *bytes_in) +{ + RESULT_PRECONDITION(s2n_stuffer_validate(hex_out)); + RESULT_PRECONDITION(s2n_blob_validate(bytes_in)); + + size_t bytes_size = bytes_in->size; + size_t hex_size = bytes_size * 2; + + RESULT_GUARD_POSIX(s2n_stuffer_reserve_space(hex_out, hex_size)); + uint8_t *out = hex_out->blob.data + hex_out->write_cursor; + uint8_t *in = bytes_in->data; + + for (size_t i = 0; i < bytes_size; i++) { + out[(i * 2)] = value_to_hex[(in[i] >> 4)]; + out[(i * 2) + 1] = value_to_hex[(in[i] & 0x0f)]; + } + + RESULT_GUARD_POSIX(s2n_stuffer_skip_write(hex_out, hex_size)); + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_stuffer_hex_read_n_bytes(struct s2n_stuffer *stuffer, uint8_t n, uint64_t *u) +{ + RESULT_ENSURE_LTE(n, sizeof(uint64_t)); + RESULT_ENSURE_REF(u); + + uint8_t hex_data[16] = { 0 }; + struct s2n_blob b = { 0 }; + RESULT_GUARD_POSIX(s2n_blob_init(&b, hex_data, n * 2)); + + RESULT_ENSURE_REF(stuffer); + RESULT_ENSURE(s2n_stuffer_read(stuffer, &b) == S2N_SUCCESS, S2N_ERR_BAD_HEX); + + /* Start with u = 0 */ + *u = 0; + for (size_t i = 0; i < b.size; i++) { + *u <<= 4; + RESULT_GUARD(s2n_stuffer_hex_validate_char(b.data[i])); + *u |= hex_to_value[b.data[i]]; + } + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_stuffer_read_uint16_hex(struct s2n_stuffer *stuffer, uint16_t *u) +{ + RESULT_ENSURE_REF(u); + uint64_t u64 = 0; + RESULT_GUARD(s2n_stuffer_hex_read_n_bytes(stuffer, sizeof(uint16_t), &u64)); + *u = u64 & 0xffff; + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_stuffer_read_uint8_hex(struct s2n_stuffer *stuffer, uint8_t *u) +{ + RESULT_ENSURE_REF(u); + uint64_t u64 = 0; + RESULT_GUARD(s2n_stuffer_hex_read_n_bytes(stuffer, sizeof(uint8_t), &u64)); + *u = u64 & 0xff; + return S2N_RESULT_OK; +} + +static S2N_RESULT s2n_stuffer_hex_write_n_bytes(struct s2n_stuffer *stuffer, uint8_t n, uint64_t u) +{ + RESULT_ENSURE_LTE(n, sizeof(uint64_t)); + + uint8_t hex_data[16] = { 0 }; + struct s2n_blob b = { 0 }; + RESULT_GUARD_POSIX(s2n_blob_init(&b, hex_data, n * 2)); + + for (size_t i = b.size; i > 0; i--) { + b.data[i - 1] = value_to_hex[u & 0x0f]; + u >>= 4; + } + + RESULT_GUARD_POSIX(s2n_stuffer_write(stuffer, &b)); + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_stuffer_write_uint16_hex(struct s2n_stuffer *stuffer, uint16_t u) +{ + return s2n_stuffer_hex_write_n_bytes(stuffer, sizeof(uint16_t), u); +} + +S2N_RESULT s2n_stuffer_write_uint8_hex(struct s2n_stuffer *stuffer, uint8_t u) +{ + return s2n_stuffer_hex_write_n_bytes(stuffer, sizeof(uint8_t), u); +} diff --git a/tests/testlib/s2n_stuffer_hex.c b/tests/testlib/s2n_stuffer_hex.c deleted file mode 100644 index c09f4fe584f..00000000000 --- a/tests/testlib/s2n_stuffer_hex.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -#include - -#include "error/s2n_errno.h" -#include "stuffer/s2n_stuffer.h" -#include "testlib/s2n_testlib.h" -#include "utils/s2n_safety.h" - -static uint8_t hex[16] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' -}; - -/** - * Helper function: read n bits of hex data. - */ -static int s2n_stuffer_read_n_bits_hex(struct s2n_stuffer *stuffer, uint8_t n, uint64_t *u) -{ - uint8_t hex_data[16] = { 0 }; - struct s2n_blob b = { 0 }; - POSIX_GUARD(s2n_blob_init(&b, hex_data, n / 4)); - - POSIX_GUARD(s2n_stuffer_read(stuffer, &b)); - - /* Start with u = 0 */ - *u = 0; - - for (size_t i = 0; i < b.size; i++) { - *u <<= 4; - if (b.data[i] >= '0' && b.data[i] <= '9') { - *u |= b.data[i] - '0'; - } else if (b.data[i] >= 'a' && b.data[i] <= 'f') { - *u |= b.data[i] - 'a' + 10; - } else if (b.data[i] >= 'A' && b.data[i] <= 'F') { - *u |= b.data[i] - 'A' + 10; - } else { - POSIX_BAIL(S2N_ERR_BAD_MESSAGE); - } - } - - return 0; -} - -int s2n_stuffer_read_hex(struct s2n_stuffer *stuffer, struct s2n_stuffer *out, uint32_t n) -{ - POSIX_ENSURE_GTE(s2n_stuffer_space_remaining(out), n); - - for (size_t i = 0; i < n; i++) { - uint8_t c = 0; - POSIX_GUARD(s2n_stuffer_read_uint8_hex(stuffer, &c)); - POSIX_GUARD(s2n_stuffer_write_uint8(out, c)); - } - - return 0; -} - -int s2n_stuffer_write_hex(struct s2n_stuffer *stuffer, struct s2n_stuffer *in, uint32_t n) -{ - POSIX_ENSURE_GTE(s2n_stuffer_space_remaining(stuffer), n * 2); - - for (size_t i = 0; i < n; i++) { - uint8_t c = 0; - POSIX_GUARD(s2n_stuffer_read_uint8(in, &c)); - POSIX_GUARD(s2n_stuffer_write_uint8_hex(stuffer, c)); - } - - return 0; -} - -int s2n_stuffer_read_uint64_hex(struct s2n_stuffer *stuffer, uint64_t *u) -{ - return s2n_stuffer_read_n_bits_hex(stuffer, 64, u); -} - -int s2n_stuffer_read_uint32_hex(struct s2n_stuffer *stuffer, uint32_t *u) -{ - uint64_t u64 = 0; - - POSIX_GUARD(s2n_stuffer_read_n_bits_hex(stuffer, 32, &u64)); - - *u = u64 & 0xffffffff; - - return 0; -} - -int s2n_stuffer_read_uint16_hex(struct s2n_stuffer *stuffer, uint16_t *u) -{ - uint64_t u64 = 0; - - POSIX_GUARD(s2n_stuffer_read_n_bits_hex(stuffer, 16, &u64)); - - *u = u64 & 0xffff; - - return 0; -} - -int s2n_stuffer_read_uint8_hex(struct s2n_stuffer *stuffer, uint8_t *u) -{ - uint64_t u64 = 0; - - POSIX_GUARD(s2n_stuffer_read_n_bits_hex(stuffer, 8, &u64)); - - *u = u64 & 0xff; - - return 0; -} - -/** - * Private helper: write n (up to 64) bits of hex data - */ -static int s2n_stuffer_write_n_bits_hex(struct s2n_stuffer *stuffer, uint8_t n, uint64_t u) -{ - uint8_t hex_data[16] = { 0 }; - struct s2n_blob b = { 0 }; - POSIX_GUARD(s2n_blob_init(&b, hex_data, n / 4)); - - POSIX_ENSURE_LTE(n, 64); - - for (size_t i = b.size; i > 0; i--) { - b.data[i - 1] = hex[u & 0x0f]; - u >>= 4; - } - - POSIX_GUARD(s2n_stuffer_write(stuffer, &b)); - - return 0; -} - -int s2n_stuffer_write_uint64_hex(struct s2n_stuffer *stuffer, uint64_t u) -{ - return s2n_stuffer_write_n_bits_hex(stuffer, 64, u); -} - -int s2n_stuffer_write_uint32_hex(struct s2n_stuffer *stuffer, uint32_t u) -{ - return s2n_stuffer_write_n_bits_hex(stuffer, 32, u); -} - -int s2n_stuffer_write_uint16_hex(struct s2n_stuffer *stuffer, uint16_t u) -{ - return s2n_stuffer_write_n_bits_hex(stuffer, 16, u); -} - -int s2n_stuffer_write_uint8_hex(struct s2n_stuffer *stuffer, uint8_t u) -{ - return s2n_stuffer_write_n_bits_hex(stuffer, 8, u); -} - -int s2n_stuffer_alloc_ro_from_hex_string(struct s2n_stuffer *stuffer, const char *str) -{ - if (strlen(str) % 2) { - POSIX_BAIL(S2N_ERR_SIZE_MISMATCH); - } - - POSIX_GUARD(s2n_stuffer_alloc(stuffer, strlen(str) / 2)); - - for (size_t i = 0; i < strlen(str); i += 2) { - uint8_t u = 0; - - if (str[i] >= '0' && str[i] <= '9') { - u = str[i] - '0'; - } else if (str[i] >= 'a' && str[i] <= 'f') { - u = str[i] - 'a' + 10; - } else if (str[i] >= 'A' && str[i] <= 'F') { - u = str[i] - 'A' + 10; - } else { - POSIX_BAIL(S2N_ERR_BAD_MESSAGE); - } - u <<= 4; - - if (str[i + 1] >= '0' && str[i + 1] <= '9') { - u |= str[i + 1] - '0'; - } else if (str[i + 1] >= 'a' && str[i + 1] <= 'f') { - u |= str[i + 1] - 'a' + 10; - } else if (str[i + 1] >= 'A' && str[i + 1] <= 'F') { - u |= str[i + 1] - 'A' + 10; - } else { - POSIX_BAIL(S2N_ERR_BAD_MESSAGE); - } - - POSIX_GUARD(s2n_stuffer_write_uint8(stuffer, u)); - } - - return 0; -} diff --git a/tests/testlib/s2n_stuffer_testlib.c b/tests/testlib/s2n_stuffer_testlib.c new file mode 100644 index 00000000000..60e911fb854 --- /dev/null +++ b/tests/testlib/s2n_stuffer_testlib.c @@ -0,0 +1,35 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include + +#include "error/s2n_errno.h" +#include "stuffer/s2n_stuffer.h" +#include "testlib/s2n_testlib.h" +#include "utils/s2n_safety.h" + +int s2n_stuffer_alloc_ro_from_hex_string(struct s2n_stuffer *stuffer, const char *str) +{ + DEFER_CLEANUP(struct s2n_blob hex = { 0 }, s2n_free); + /* Copying the hex into heap memory to handle the 'const' isn't exactly efficient, + * but for a testlib method it is sufficient. + */ + POSIX_GUARD(s2n_alloc(&hex, strlen(str))); + POSIX_CHECKED_MEMCPY(hex.data, str, hex.size); + + POSIX_GUARD(s2n_stuffer_alloc(stuffer, strlen(str) / 2)); + POSIX_GUARD_RESULT(s2n_stuffer_read_hex(stuffer, &hex)); + return S2N_SUCCESS; +} diff --git a/tests/testlib/s2n_testlib.h b/tests/testlib/s2n_testlib.h index e05da3eefc5..eea219b71dc 100644 --- a/tests/testlib/s2n_testlib.h +++ b/tests/testlib/s2n_testlib.h @@ -23,18 +23,7 @@ extern const struct s2n_ecc_preferences ecc_preferences_for_retry; extern const struct s2n_security_policy security_policy_test_tls13_retry; -/* Read and write hex */ -int s2n_stuffer_read_hex(struct s2n_stuffer *stuffer, struct s2n_stuffer *out, uint32_t n); -int s2n_stuffer_read_uint8_hex(struct s2n_stuffer *stuffer, uint8_t *u); -int s2n_stuffer_read_uint16_hex(struct s2n_stuffer *stuffer, uint16_t *u); -int s2n_stuffer_read_uint32_hex(struct s2n_stuffer *stuffer, uint32_t *u); -int s2n_stuffer_read_uint64_hex(struct s2n_stuffer *stuffer, uint64_t *u); - -int s2n_stuffer_write_hex(struct s2n_stuffer *stuffer, struct s2n_stuffer *in, uint32_t n); -int s2n_stuffer_write_uint8_hex(struct s2n_stuffer *stuffer, uint8_t u); -int s2n_stuffer_write_uint16_hex(struct s2n_stuffer *stuffer, uint16_t u); -int s2n_stuffer_write_uint32_hex(struct s2n_stuffer *stuffer, uint32_t u); -int s2n_stuffer_write_uint64_hex(struct s2n_stuffer *stuffer, uint64_t u); +/* Stuffer methods for testing */ int s2n_stuffer_alloc_ro_from_hex_string(struct s2n_stuffer *stuffer, const char *str); void s2n_print_connection(struct s2n_connection *conn, const char *marker); diff --git a/tests/unit/s2n_fingerprint_test.c b/tests/unit/s2n_fingerprint_test.c index 316a69eae62..0d108390d65 100644 --- a/tests/unit/s2n_fingerprint_test.c +++ b/tests/unit/s2n_fingerprint_test.c @@ -597,7 +597,7 @@ int main(int argc, char **argv) EXPECT_EQUAL(output_size, legacy_output_size * 2); for (size_t i = 0; i < legacy_output_size; i++) { uint8_t output_byte = 0; - EXPECT_SUCCESS(s2n_stuffer_read_uint8_hex(&output_stuffer, &output_byte)); + EXPECT_OK(s2n_stuffer_read_uint8_hex(&output_stuffer, &output_byte)); EXPECT_EQUAL(output_byte, legacy_output[i]); } }; diff --git a/tests/unit/s2n_hash_test.c b/tests/unit/s2n_hash_test.c index d9514e960b8..929108a2c40 100644 --- a/tests/unit/s2n_hash_test.c +++ b/tests/unit/s2n_hash_test.c @@ -76,7 +76,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 16; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from command line md5sum */ @@ -117,7 +117,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 20; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from command line sha1sum */ @@ -130,7 +130,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 20; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from command line sha1sum */ @@ -172,7 +172,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 20; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from command line sha1sum */ @@ -194,7 +194,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 20; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from command line sha1sum */ @@ -229,7 +229,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 28; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from command line sha224sum */ @@ -259,7 +259,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 32; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from command line sha256sum */ @@ -290,7 +290,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 48; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from command line sha384sum */ @@ -325,7 +325,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 64; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from command line sha512sum */ diff --git a/tests/unit/s2n_hmac_test.c b/tests/unit/s2n_hmac_test.c index 75a4955778f..74fe6fc9033 100644 --- a/tests/unit/s2n_hmac_test.c +++ b/tests/unit/s2n_hmac_test.c @@ -58,7 +58,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 16; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from Go */ @@ -71,7 +71,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 16; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from Go */ @@ -91,7 +91,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 20; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from Go */ @@ -104,7 +104,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 20; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from Go */ @@ -124,7 +124,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 16; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from python */ @@ -144,7 +144,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 20; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from python */ @@ -155,7 +155,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 20; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from python */ @@ -172,7 +172,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 20; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from python */ @@ -185,7 +185,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 20; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from python */ @@ -200,7 +200,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 20; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from python */ @@ -226,7 +226,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 28; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from python */ @@ -245,7 +245,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 32; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from python */ @@ -264,7 +264,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 48; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from python */ @@ -283,7 +283,7 @@ int main(int argc, char **argv) EXPECT_SUCCESS(s2n_stuffer_init(&output, &out)); for (int i = 0; i < 64; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&output, digest_pad[i])); } /* Reference value from python */ diff --git a/tests/unit/s2n_self_talk_key_log_test.c b/tests/unit/s2n_self_talk_key_log_test.c index 9712b05a49e..b0269bf0175 100644 --- a/tests/unit/s2n_self_talk_key_log_test.c +++ b/tests/unit/s2n_self_talk_key_log_test.c @@ -180,7 +180,9 @@ int main(int argc, char **argv) DEFER_CLEANUP(struct s2n_stuffer decoded, s2n_stuffer_free); EXPECT_SUCCESS(s2n_stuffer_alloc(&decoded, sizeof(bytes))); - EXPECT_SUCCESS(s2n_stuffer_read_hex(&encoded, &decoded, sizeof(bytes))); + + encoded.blob.size = s2n_stuffer_data_available(&encoded); + EXPECT_OK(s2n_stuffer_read_hex(&decoded, &encoded.blob)); uint8_t *out = s2n_stuffer_raw_read(&decoded, s2n_stuffer_data_available(&decoded)); EXPECT_NOT_NULL(out); diff --git a/tests/unit/s2n_ssl_prf_test.c b/tests/unit/s2n_ssl_prf_test.c index c4cdfa8356c..2eaa262b113 100644 --- a/tests/unit/s2n_ssl_prf_test.c +++ b/tests/unit/s2n_ssl_prf_test.c @@ -68,17 +68,17 @@ int main(int argc, char **argv) /* Parse the hex */ for (int i = 0; i < 48; i++) { uint8_t c = 0; - EXPECT_SUCCESS(s2n_stuffer_read_uint8_hex(&premaster_secret_in, &c)); + EXPECT_OK(s2n_stuffer_read_uint8_hex(&premaster_secret_in, &c)); conn->secrets.version.tls12.rsa_premaster_secret[i] = c; } for (int i = 0; i < 32; i++) { uint8_t c = 0; - EXPECT_SUCCESS(s2n_stuffer_read_uint8_hex(&client_random_in, &c)); + EXPECT_OK(s2n_stuffer_read_uint8_hex(&client_random_in, &c)); conn->handshake_params.client_random[i] = c; } for (int i = 0; i < 32; i++) { uint8_t c = 0; - EXPECT_SUCCESS(s2n_stuffer_read_uint8_hex(&server_random_in, &c)); + EXPECT_OK(s2n_stuffer_read_uint8_hex(&server_random_in, &c)); conn->handshake_params.server_random[i] = c; } @@ -90,7 +90,7 @@ int main(int argc, char **argv) /* Convert the master secret to hex */ for (int i = 0; i < 48; i++) { - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&master_secret_hex_out, conn->secrets.version.tls12.master_secret[i])); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&master_secret_hex_out, conn->secrets.version.tls12.master_secret[i])); } EXPECT_EQUAL(memcmp(master_secret_hex_pad, master_secret_hex_in, sizeof(master_secret_hex_pad)), 0); diff --git a/tests/unit/s2n_stuffer_hex_test.c b/tests/unit/s2n_stuffer_hex_test.c index d46c6f2645e..527e9243c84 100644 --- a/tests/unit/s2n_stuffer_hex_test.c +++ b/tests/unit/s2n_stuffer_hex_test.c @@ -16,100 +16,572 @@ #include "s2n_test.h" #include "stuffer/s2n_stuffer.h" #include "testlib/s2n_testlib.h" -#include "utils/s2n_random.h" int main(int argc, char **argv) { - uint8_t pad[100]; - struct s2n_blob b = { 0 }; - EXPECT_SUCCESS(s2n_blob_init(&b, pad, sizeof(pad))); - struct s2n_stuffer stuffer = { 0 }; - uint8_t u8 = 0; - uint16_t u16 = 0; - uint32_t u32 = 0; - uint64_t u64 = 0; - BEGIN_TEST(); - EXPECT_SUCCESS(s2n_disable_tls13_in_test()); - /* Create a 100 byte stuffer */ - EXPECT_SUCCESS(s2n_stuffer_init(&stuffer, &b)); + /* Test: Safety */ + { + struct s2n_stuffer stuffer = { 0 }; + struct s2n_blob blob = { 0 }; - /* Try to write 51 1-byte ints bytes */ - for (uint8_t i = 0; i < 50; i++) { - uint8_t value = i * (0xff / 50); - EXPECT_SUCCESS(s2n_stuffer_write_uint8_hex(&stuffer, value)); - } - EXPECT_FAILURE(s2n_stuffer_write_uint8_hex(&stuffer, 1)); + /* s2n_stuffer_read_hex */ + EXPECT_ERROR_WITH_ERRNO(s2n_stuffer_read_hex(&stuffer, NULL), S2N_ERR_NULL); + EXPECT_ERROR_WITH_ERRNO(s2n_stuffer_read_hex(NULL, &blob), S2N_ERR_NULL); - /* Read those back, and expect the same results */ - for (int8_t i = 0; i < 50; i++) { - uint8_t value = i * (0xff / 50); - EXPECT_SUCCESS(s2n_stuffer_read_uint8_hex(&stuffer, &u8)); - EXPECT_EQUAL(u8, value); - } - EXPECT_FAILURE(s2n_stuffer_read_uint8_hex(&stuffer, &u8)); + /* s2n_stuffer_write_hex */ + EXPECT_ERROR_WITH_ERRNO(s2n_stuffer_write_hex(&stuffer, NULL), S2N_ERR_NULL); + EXPECT_ERROR_WITH_ERRNO(s2n_stuffer_write_hex(NULL, &blob), S2N_ERR_NULL); - /* Try to write 26 2-byte ints bytes */ - EXPECT_SUCCESS(s2n_stuffer_wipe(&stuffer)); - for (uint16_t i = 0; i < 25; i++) { - uint16_t value = i * (0xffff / 25); - EXPECT_SUCCESS(s2n_stuffer_write_uint16_hex(&stuffer, value)); - } - EXPECT_FAILURE(s2n_stuffer_write_uint16_hex(&stuffer, 1)); + /* s2n_stuffer_read_uint8_hex */ + uint8_t value_u8 = 0; + EXPECT_ERROR_WITH_ERRNO(s2n_stuffer_read_uint8_hex(&stuffer, NULL), S2N_ERR_NULL); + EXPECT_ERROR_WITH_ERRNO(s2n_stuffer_read_uint8_hex(NULL, &value_u8), S2N_ERR_NULL); - /* Read those back, and expect the same results */ - for (uint16_t i = 0; i < 25; i++) { - uint16_t value = i * (0xffff / 25); - EXPECT_SUCCESS(s2n_stuffer_read_uint16_hex(&stuffer, &u16)); - EXPECT_EQUAL(value, u16); - } - EXPECT_FAILURE(s2n_stuffer_read_uint16_hex(&stuffer, &u16)); - - /* Try to write 13 4-byte ints bytes */ - EXPECT_SUCCESS(s2n_stuffer_wipe(&stuffer)); - EXPECT_SUCCESS(s2n_stuffer_init(&stuffer, &b)); - for (uint32_t i = 0; i < 12; i++) { - uint32_t value = i * (0xffffffff / 12); - EXPECT_SUCCESS(s2n_stuffer_write_uint32_hex(&stuffer, value)); + /* s2n_stuffer_write_uint8_hex */ + EXPECT_ERROR_WITH_ERRNO(s2n_stuffer_write_uint8_hex(NULL, 0), S2N_ERR_NULL); + + /* s2n_stuffer_read_uint16_hex */ + uint16_t value_u16 = 0; + EXPECT_ERROR_WITH_ERRNO(s2n_stuffer_read_uint16_hex(&stuffer, NULL), S2N_ERR_NULL); + EXPECT_ERROR_WITH_ERRNO(s2n_stuffer_read_uint16_hex(NULL, &value_u16), S2N_ERR_NULL); + + /* s2n_stuffer_write_uint16_hex */ + EXPECT_ERROR_WITH_ERRNO(s2n_stuffer_write_uint16_hex(NULL, 0), S2N_ERR_NULL); } - EXPECT_FAILURE(s2n_stuffer_write_uint32_hex(&stuffer, 1)); - /* Read those back, and expect the same results */ - for (uint32_t i = 0; i < 12; i++) { - uint32_t value = i * (0xffffffff / 12); - EXPECT_SUCCESS(s2n_stuffer_read_uint32_hex(&stuffer, &u32)); - EXPECT_EQUAL(value, u32); + /* Test hex with uint8 */ + { + const size_t expected_size = 2; + struct { + const uint8_t num; + const char *hex; + } test_cases[] = { + /* Test first digit */ + { .num = 0, .hex = "00" }, + { .num = 1, .hex = "01" }, + { .num = 5, .hex = "05" }, + { .num = 15, .hex = "0f" }, + /* Test second digit */ + { .num = 0x10, .hex = "10" }, + { .num = 0x50, .hex = "50" }, + { .num = 0xf0, .hex = "f0" }, + /* Test all numbers */ + { .num = 0x12, .hex = "12" }, + { .num = 0x34, .hex = "34" }, + { .num = 0x56, .hex = "56" }, + { .num = 0x78, .hex = "78" }, + { .num = 0x90, .hex = "90" }, + /* Test all letters */ + { .num = 0xab, .hex = "ab" }, + { .num = 0xcd, .hex = "cd" }, + { .num = 0xef, .hex = "ef" }, + /* Test mix of numbers and letters */ + { .num = 0x1a, .hex = "1a" }, + { .num = 0x9f, .hex = "9f" }, + /* Test high values */ + { .num = UINT8_MAX - 1, .hex = "fe" }, + { .num = UINT8_MAX, .hex = "ff" }, + }; + for (size_t i = 0; i < s2n_array_len(test_cases); i++) { + /* Test s2n_stuffer_write_uint8_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer hex = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&hex, 0)); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&hex, test_cases[i].num)); + + size_t actual_size = s2n_stuffer_data_available(&hex); + EXPECT_EQUAL(actual_size, expected_size); + EXPECT_EQUAL(strlen(test_cases[i].hex), expected_size); + + const char *actual_hex = s2n_stuffer_raw_read(&hex, actual_size); + EXPECT_BYTEARRAY_EQUAL(actual_hex, test_cases[i].hex, actual_size); + }; + + /* Test s2n_stuffer_read_uint8_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer hex = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_alloc(&hex, expected_size)); + EXPECT_SUCCESS(s2n_stuffer_write_text(&hex, test_cases[i].hex, expected_size)); + + uint8_t actual_num = 0; + EXPECT_OK(s2n_stuffer_read_uint8_hex(&hex, &actual_num)); + EXPECT_EQUAL(actual_num, test_cases[i].num); + EXPECT_FALSE(s2n_stuffer_data_available(&hex)); + }; + + /* Test s2n_stuffer_write_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer num_in = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_alloc(&num_in, sizeof(uint8_t))); + EXPECT_SUCCESS(s2n_stuffer_write_uint8(&num_in, test_cases[i].num)); + + DEFER_CLEANUP(struct s2n_stuffer hex_out = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&hex_out, 0)); + EXPECT_OK(s2n_stuffer_write_hex(&hex_out, &num_in.blob)); + + size_t actual_size = s2n_stuffer_data_available(&hex_out); + EXPECT_EQUAL(actual_size, expected_size); + EXPECT_EQUAL(strlen(test_cases[i].hex), expected_size); + + const char *actual_hex = s2n_stuffer_raw_read(&hex_out, actual_size); + EXPECT_BYTEARRAY_EQUAL(actual_hex, test_cases[i].hex, actual_size); + }; + + /* Test s2n_stuffer_read_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer hex_in = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_alloc(&hex_in, expected_size)); + EXPECT_SUCCESS(s2n_stuffer_write_text(&hex_in, test_cases[i].hex, expected_size)); + + DEFER_CLEANUP(struct s2n_stuffer num_out = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&num_out, 0)); + EXPECT_OK(s2n_stuffer_read_hex(&num_out, &hex_in.blob)); + + uint8_t actual_num = 0; + EXPECT_SUCCESS(s2n_stuffer_read_uint8(&num_out, &actual_num)); + EXPECT_EQUAL(actual_num, test_cases[i].num); + EXPECT_FALSE(s2n_stuffer_data_available(&num_out)); + }; + } + }; + + /* Test hex with uint16 */ + { + const size_t expected_size = 4; + struct { + uint16_t num; + const char *hex; + } test_cases[] = { + /* Test first digit */ + { .num = 0, .hex = "0000" }, + { .num = 1, .hex = "0001" }, + { .num = 5, .hex = "0005" }, + { .num = 15, .hex = "000f" }, + /* Test second digit */ + { .num = 0x10, .hex = "0010" }, + { .num = 0x50, .hex = "0050" }, + { .num = 0xf0, .hex = "00f0" }, + /* Test third digit */ + { .num = 0x0100, .hex = "0100" }, + { .num = 0x0500, .hex = "0500" }, + { .num = 0x0f00, .hex = "0f00" }, + /* Test fourth digit */ + { .num = 0x1000, .hex = "1000" }, + { .num = 0x5000, .hex = "5000" }, + { .num = 0xf000, .hex = "f000" }, + /* Test all numbers */ + { .num = 0x1234, .hex = "1234" }, + { .num = 0x5678, .hex = "5678" }, + { .num = 0x9012, .hex = "9012" }, + /* Test all letters */ + { .num = 0xabcd, .hex = "abcd" }, + { .num = 0xefab, .hex = "efab" }, + /* Test mix of numbers and letters */ + { .num = 0x1a2b, .hex = "1a2b" }, + { .num = 0x8e9f, .hex = "8e9f" }, + /* Test high values */ + { .num = UINT16_MAX - 1, .hex = "fffe" }, + { .num = UINT16_MAX, .hex = "ffff" }, + }; + for (size_t i = 0; i < s2n_array_len(test_cases); i++) { + /* Test s2n_stuffer_write_uint16_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer hex = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&hex, 0)); + EXPECT_OK(s2n_stuffer_write_uint16_hex(&hex, test_cases[i].num)); + + size_t actual_size = s2n_stuffer_data_available(&hex); + EXPECT_EQUAL(actual_size, expected_size); + EXPECT_EQUAL(strlen(test_cases[i].hex), expected_size); + + const char *actual_hex = s2n_stuffer_raw_read(&hex, actual_size); + EXPECT_BYTEARRAY_EQUAL(actual_hex, test_cases[i].hex, actual_size); + }; + + /* Test s2n_stuffer_read_uint16_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer hex = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_alloc(&hex, expected_size)); + EXPECT_SUCCESS(s2n_stuffer_write_text(&hex, test_cases[i].hex, expected_size)); + + uint16_t actual_num = 0; + EXPECT_OK(s2n_stuffer_read_uint16_hex(&hex, &actual_num)); + EXPECT_EQUAL(actual_num, test_cases[i].num); + EXPECT_FALSE(s2n_stuffer_data_available(&hex)); + }; + + /* Test s2n_stuffer_write_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer num_in = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_alloc(&num_in, sizeof(uint16_t))); + EXPECT_SUCCESS(s2n_stuffer_write_uint16(&num_in, test_cases[i].num)); + + DEFER_CLEANUP(struct s2n_stuffer hex_out = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&hex_out, 0)); + EXPECT_OK(s2n_stuffer_write_hex(&hex_out, &num_in.blob)); + + size_t actual_size = s2n_stuffer_data_available(&hex_out); + EXPECT_EQUAL(actual_size, expected_size); + EXPECT_EQUAL(strlen(test_cases[i].hex), expected_size); + + const char *actual_hex = s2n_stuffer_raw_read(&hex_out, actual_size); + EXPECT_BYTEARRAY_EQUAL(actual_hex, test_cases[i].hex, actual_size); + }; + + /* Test s2n_stuffer_read_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer hex_in = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_alloc(&hex_in, expected_size)); + EXPECT_SUCCESS(s2n_stuffer_write_text(&hex_in, test_cases[i].hex, expected_size)); + + DEFER_CLEANUP(struct s2n_stuffer num_out = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&num_out, 0)); + EXPECT_OK(s2n_stuffer_read_hex(&num_out, &hex_in.blob)); + + uint16_t actual_num = 0; + EXPECT_SUCCESS(s2n_stuffer_read_uint16(&num_out, &actual_num)); + EXPECT_EQUAL(actual_num, test_cases[i].num); + EXPECT_FALSE(s2n_stuffer_data_available(&num_out)); + }; + } + }; + + /* Test longer series of bytes */ + { + struct { + uint8_t bytes[50]; + uint8_t bytes_size; + const char *hex; + } test_cases[] = { + /* clang-format off */ + { + .bytes = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef }, + .bytes_size = 8, + .hex = "1234567890abcdef", + }, + { + .bytes = { 0 }, + .bytes_size = 4, + .hex = "00000000", + }, + { + .bytes = { 0xff, 0x11, 0x22, 0x55, 0xaa }, + .bytes_size = 5, + .hex = "ff112255aa", + }, + { + .bytes = { 0x10, 0x10, 0x10, 0x10 }, + .bytes_size = 4, + .hex = "10101010", + }, + { + .bytes = { 0x00, 0x00, 0x01 }, + .bytes_size = 3, + .hex = "000001", + }, + { + .bytes = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef }, + .bytes_size = 16, + .hex = "1234567890abcdef" + "0000000000000000", + }, + { + .bytes = { + 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, + 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0x01, + 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0x02, + 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0x03, + }, + .bytes_size = 8 * 4, + .hex = + "1234567890abcdef" + "1234567890abcd01" + "1234567890abcd02" + "1234567890abcd03", + }, + /* clang-format on */ + }; + + for (size_t i = 0; i < s2n_array_len(test_cases); i++) { + size_t hex_size = strlen(test_cases[i].hex); + EXPECT_EQUAL(test_cases[i].bytes_size * 2, hex_size); + + /* Test s2n_stuffer_write_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer num_in = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_alloc(&num_in, test_cases[i].bytes_size)); + EXPECT_SUCCESS(s2n_stuffer_write_bytes(&num_in, + test_cases[i].bytes, test_cases[i].bytes_size)); + + DEFER_CLEANUP(struct s2n_stuffer hex_out = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&hex_out, 0)); + EXPECT_OK(s2n_stuffer_write_hex(&hex_out, &num_in.blob)); + + size_t actual_size = s2n_stuffer_data_available(&hex_out); + EXPECT_EQUAL(actual_size, hex_size); + + const char *actual_hex = s2n_stuffer_raw_read(&hex_out, actual_size); + EXPECT_BYTEARRAY_EQUAL(actual_hex, test_cases[i].hex, actual_size); + }; + + /* Test s2n_stuffer_read_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer hex_in = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_alloc(&hex_in, hex_size)); + EXPECT_SUCCESS(s2n_stuffer_write_text(&hex_in, test_cases[i].hex, hex_size)); + + DEFER_CLEANUP(struct s2n_stuffer num_out = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&num_out, 0)); + EXPECT_OK(s2n_stuffer_read_hex(&num_out, &hex_in.blob)); + + size_t actual_size = s2n_stuffer_data_available(&num_out); + EXPECT_EQUAL(actual_size, test_cases[i].bytes_size); + + const uint8_t *actual_bytes = s2n_stuffer_raw_read(&num_out, actual_size); + EXPECT_BYTEARRAY_EQUAL(actual_bytes, test_cases[i].bytes, actual_size); + }; + } + }; + + /* Test bad hex string */ + { + /* Test bad uint8 hex */ + { + const char *test_hexes[] = { + /* clang-format off */ + /* one good hex as a control */ + "FFFFFF", + /* too short */ + "", "0", "1", + /* invalid characters: symbols <'0' */ + "0/", "!0", + /* invalid characters: symbols >'9', <'A' */ + "0:", "@0", + /* invalid characters: symbols >'Z', <'a' */ + "0[", "`0", + /* invalid characters: symbols >'z' */ + "0{", "~0", + /* invalid characters: non-hex letters */ + "0g", "z0", "0G", "Z0", + /* clang-format on */ + }; + + for (size_t i = 0; i < s2n_array_len(test_hexes); i++) { + const char *test_hex = test_hexes[i]; + + /* Test s2n_stuffer_read_uint8_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer hex = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_alloc(&hex, strlen(test_hex))); + EXPECT_SUCCESS(s2n_stuffer_write_str(&hex, test_hex)); + + uint8_t actual_num = 0; + if (i == 0) { + EXPECT_OK(s2n_stuffer_read_uint8_hex(&hex, &actual_num)); + } else { + EXPECT_ERROR_WITH_ERRNO( + s2n_stuffer_read_uint8_hex(&hex, &actual_num), + S2N_ERR_BAD_HEX); + } + }; + + /* Test s2n_stuffer_read_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer hex = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_alloc(&hex, strlen(test_hex))); + EXPECT_SUCCESS(s2n_stuffer_write_str(&hex, test_hex)); + + DEFER_CLEANUP(struct s2n_stuffer out = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&out, 0)); + if (i == 0) { + EXPECT_OK(s2n_stuffer_read_hex(&out, &hex.blob)); + } else if (strlen(test_hex) == 0) { + /* Unlike s2n_stuffer_read_uint8_hex, read_hex accepts + * empty input since it has no size expectations */ + EXPECT_OK(s2n_stuffer_read_hex(&out, &hex.blob)); + } else { + EXPECT_ERROR_WITH_ERRNO( + s2n_stuffer_read_hex(&out, &hex.blob), + S2N_ERR_BAD_HEX); + } + }; + } + }; + + /* Test bad uint16 hex */ + { + const char *test_hexes[] = { + /* clang-format off */ + /* one good hex as a control */ + "FFFFFF", + /* too short */ + "", "0", "1", "00", "01", "000", "001", + /* invalid characters: symbols <'0' */ + "000/", "00!0", "0.00", "#000", + /* invalid characters: symbols >'9', <'A' */ + "000:", "00@0", "0?00", ";000", + /* invalid characters: symbols >'Z', <'a' */ + "000[", "00`0", "0_00", "^000", + /* invalid characters: symbols >'z' */ + "000{", "00~0", "0}00", "|000", + /* invalid characters: non-hex letters */ + "000g", "00z0", "000G", "00Z0", "0Y00", "S000", + /* clang-format on */ + }; + + for (size_t i = 0; i < s2n_array_len(test_hexes); i++) { + const char *test_hex = test_hexes[i]; + + /* Test s2n_stuffer_read_uint16_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer hex = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_alloc(&hex, strlen(test_hex))); + EXPECT_SUCCESS(s2n_stuffer_write_str(&hex, test_hex)); + + uint16_t actual_num = 0; + if (i == 0) { + EXPECT_OK(s2n_stuffer_read_uint16_hex(&hex, &actual_num)); + } else { + EXPECT_ERROR_WITH_ERRNO( + s2n_stuffer_read_uint16_hex(&hex, &actual_num), + S2N_ERR_BAD_HEX); + } + }; + + /* Test s2n_stuffer_read_hex */ + { + DEFER_CLEANUP(struct s2n_stuffer hex = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_alloc(&hex, strlen(test_hex))); + EXPECT_SUCCESS(s2n_stuffer_write_str(&hex, test_hex)); + + DEFER_CLEANUP(struct s2n_stuffer out = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&out, 0)); + if (i == 0) { + EXPECT_OK(s2n_stuffer_read_hex(&out, &hex.blob)); + } else if (strlen(test_hex) < sizeof(uint16_t) * 2 + && strlen(test_hex) % 2 == 0) { + /* Unlike s2n_stuffer_read_uint16_hex, read_hex accepts + * input of any valid size */ + EXPECT_OK(s2n_stuffer_read_hex(&out, &hex.blob)); + } else { + EXPECT_ERROR_WITH_ERRNO( + s2n_stuffer_read_hex(&out, &hex.blob), + S2N_ERR_BAD_HEX); + } + }; + } + }; } - EXPECT_FAILURE(s2n_stuffer_read_uint32_hex(&stuffer, &u32)); - /* Try to write 7 8-byte ints bytes */ - EXPECT_SUCCESS(s2n_stuffer_wipe(&stuffer)); - for (uint64_t i = 0; i < 6; i++) { - uint64_t value = i * (0xffffffffffffffff / 6); - EXPECT_SUCCESS(s2n_stuffer_write_uint64_hex(&stuffer, value)); + /* Test converting to and from all uint8_t */ + for (size_t i = 0; i <= UINT8_MAX; i++) { + DEFER_CLEANUP(struct s2n_stuffer hex = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&hex, 0)); + EXPECT_OK(s2n_stuffer_write_uint8_hex(&hex, i)); + + uint8_t value = 0; + EXPECT_OK(s2n_stuffer_read_uint8_hex(&hex, &value)); + EXPECT_EQUAL(value, i); } - EXPECT_FAILURE(s2n_stuffer_write_uint64_hex(&stuffer, 1)); - /* Read those back, and expect the same results */ - for (uint64_t i = 0; i < 6; i++) { - uint64_t value = i * (0xffffffffffffffff / 6); - EXPECT_SUCCESS(s2n_stuffer_read_uint64_hex(&stuffer, &u64)); - EXPECT_EQUAL(value, u64); + /* Test converting to and from all uint16_t */ + for (size_t i = 0; i <= UINT16_MAX; i++) { + DEFER_CLEANUP(struct s2n_stuffer hex = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&hex, 0)); + EXPECT_OK(s2n_stuffer_write_uint16_hex(&hex, i)); + + uint16_t value = 0; + EXPECT_OK(s2n_stuffer_read_uint16_hex(&hex, &value)); + EXPECT_EQUAL(value, i); } - EXPECT_FAILURE(s2n_stuffer_read_uint64_hex(&stuffer, &u64)); - - EXPECT_SUCCESS(s2n_stuffer_wipe(&stuffer)); - uint8_t hex[] = "f0F0Zz"; - struct s2n_blob text = { 0 }; - EXPECT_SUCCESS(s2n_blob_init(&text, hex, strlen((char *) hex))); - EXPECT_SUCCESS(s2n_stuffer_write(&stuffer, &text)); - - EXPECT_SUCCESS(s2n_stuffer_read_uint8_hex(&stuffer, &u8)); - EXPECT_EQUAL(u8, 240); - EXPECT_SUCCESS(s2n_stuffer_read_uint8_hex(&stuffer, &u8)); - EXPECT_EQUAL(u8, 240); - EXPECT_FAILURE(s2n_stuffer_read_uint8_hex(&stuffer, &u8)); + + /* Test reading and writing multiple values with different methods */ + { + const uint8_t values_u8[] = { + /* clang-format off */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, + 0x12, 0x34, 0x56, 0x78, 0x90, 0x00, + 0xab, 0xbc, 0xcd, 0xde, 0xef, 0x00, + /* clang-format on */ + }; + const uint16_t values_u16[] = { + /* clang-format off */ + 0x0001, 0x0203, 0x0400, + 0x1234, 0x5678, 0x9000, + 0xabbc, 0xcdde, 0xef00, + /* clang-format on */ + }; + const size_t bytes_size = sizeof(values_u8); + const char hex_str[] = + "000102030400" + "123456789000" + "abbccddeef00"; + + enum s2n_test_hex_method { + S2N_TEST_U8 = 0, + S2N_TEST_U16, + S2N_TEST_N, + S2N_TEST_HEX_METHOD_COUNT + }; + + for (size_t writer_i = 0; writer_i < S2N_TEST_HEX_METHOD_COUNT; writer_i++) { + for (size_t reader_i = 0; reader_i < S2N_TEST_HEX_METHOD_COUNT; reader_i++) { + DEFER_CLEANUP(struct s2n_stuffer hex = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&hex, 0)); + + if (writer_i == S2N_TEST_U8) { + for (size_t i = 0; i < sizeof(values_u8); i++) { + EXPECT_OK(s2n_stuffer_write_uint8_hex(&hex, values_u8[i])); + } + } else if (writer_i == S2N_TEST_U16) { + for (size_t i = 0; i < s2n_array_len(values_u16); i++) { + EXPECT_OK(s2n_stuffer_write_uint16_hex(&hex, values_u16[i])); + } + } else if (writer_i == S2N_TEST_N) { + DEFER_CLEANUP(struct s2n_stuffer input = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_alloc(&input, bytes_size)); + EXPECT_SUCCESS(s2n_stuffer_write_bytes(&input, values_u8, bytes_size)); + + EXPECT_OK(s2n_stuffer_write_hex(&hex, &input.blob)); + } else { + FAIL_MSG("unknown hex method"); + } + + size_t written = s2n_stuffer_data_available(&hex); + EXPECT_EQUAL(written, strlen(hex_str)); + EXPECT_BYTEARRAY_EQUAL(hex_str, hex.blob.data, written); + + if (reader_i == S2N_TEST_U8) { + for (size_t i = 0; i < sizeof(values_u8); i++) { + uint8_t byte = 0; + EXPECT_OK(s2n_stuffer_read_uint8_hex(&hex, &byte)); + EXPECT_EQUAL(byte, values_u8[i]); + } + EXPECT_FALSE(s2n_stuffer_data_available(&hex)); + } else if (reader_i == S2N_TEST_U16) { + for (size_t i = 0; i < s2n_array_len(values_u16); i++) { + uint16_t value = 0; + EXPECT_OK(s2n_stuffer_read_uint16_hex(&hex, &value)); + EXPECT_EQUAL(value, values_u16[i]); + } + EXPECT_FALSE(s2n_stuffer_data_available(&hex)); + } else if (reader_i == S2N_TEST_N) { + DEFER_CLEANUP(struct s2n_stuffer output = { 0 }, s2n_stuffer_free); + EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&output, 0)); + + hex.blob.size = s2n_stuffer_data_available(&hex); + EXPECT_OK(s2n_stuffer_read_hex(&output, &hex.blob)); + + EXPECT_EQUAL(s2n_stuffer_data_available(&output), sizeof(values_u8)); + EXPECT_BYTEARRAY_EQUAL(values_u8, output.blob.data, sizeof(values_u8)); + } else { + FAIL_MSG("unknown hex method"); + } + } + } + }; END_TEST(); } diff --git a/tests/unit/s2n_tls13_prf_test.c b/tests/unit/s2n_tls13_prf_test.c index 2231a642627..411e4c2bf2c 100644 --- a/tests/unit/s2n_tls13_prf_test.c +++ b/tests/unit/s2n_tls13_prf_test.c @@ -76,25 +76,25 @@ int main(int argc, char **argv) /* Parse the hex */ for (size_t i = 0; i < sizeof(client_handshake_message); i++) { uint8_t c = 0; - EXPECT_SUCCESS(s2n_stuffer_read_uint8_hex(&client_handshake_message_in, &c)); + EXPECT_OK(s2n_stuffer_read_uint8_hex(&client_handshake_message_in, &c)); client_handshake_message[i] = c; } for (size_t i = 0; i < sizeof(server_handshake_message); i++) { uint8_t c = 0; - EXPECT_SUCCESS(s2n_stuffer_read_uint8_hex(&server_handshake_message_in, &c)); + EXPECT_OK(s2n_stuffer_read_uint8_hex(&server_handshake_message_in, &c)); server_handshake_message[i] = c; } for (size_t i = 0; i < sizeof(expected_secret); i++) { uint8_t c = 0; - EXPECT_SUCCESS(s2n_stuffer_read_uint8_hex(&expected_secret_in, &c)); + EXPECT_OK(s2n_stuffer_read_uint8_hex(&expected_secret_in, &c)); expected_secret[i] = c; } for (size_t i = 0; i < sizeof(expected_expanded); i++) { uint8_t c = 0; - EXPECT_SUCCESS(s2n_stuffer_read_uint8_hex(&expected_expanded_in, &c)); + EXPECT_OK(s2n_stuffer_read_uint8_hex(&expected_expanded_in, &c)); expected_expanded[i] = c; } From 4cb15d5b8371abdf35a8e46837d44eb9567c3c7b Mon Sep 17 00:00:00 2001 From: Lindsay Stewart Date: Sun, 21 Jul 2024 23:23:58 -0700 Subject: [PATCH 2/2] Pr comments --- stuffer/s2n_stuffer_hex.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/stuffer/s2n_stuffer_hex.c b/stuffer/s2n_stuffer_hex.c index 63256855b81..c503e31932f 100644 --- a/stuffer/s2n_stuffer_hex.c +++ b/stuffer/s2n_stuffer_hex.c @@ -30,12 +30,14 @@ static const uint8_t hex_to_value[] = { /* clang-format on */ }; -static S2N_RESULT s2n_stuffer_hex_validate_char(uint8_t c) +static S2N_RESULT s2n_stuffer_hex_digit_from_char(uint8_t c, uint8_t *i) { RESULT_ENSURE(c < s2n_array_len(hex_to_value), S2N_ERR_BAD_HEX); + /* Invalid characters map to 0 in hex_to_value, but so does '0'. */ if (hex_to_value[c] == 0) { RESULT_ENSURE(c == '0', S2N_ERR_BAD_HEX); } + *i = hex_to_value[c]; return S2N_RESULT_OK; } @@ -56,14 +58,10 @@ S2N_RESULT s2n_stuffer_read_hex(struct s2n_stuffer *bytes_out, const struct s2n_ uint8_t *in = hex_in->data; for (size_t i = 0; i < bytes_size; i++) { - uint8_t hex_high = in[(i * 2)]; - RESULT_GUARD(s2n_stuffer_hex_validate_char(hex_high)); - - uint8_t hex_low = in[(i * 2) + 1]; - RESULT_GUARD(s2n_stuffer_hex_validate_char(hex_low)); - - out[i] = hex_to_value[hex_low]; - out[i] += hex_to_value[hex_high] * 16; + uint8_t hex_high = 0, hex_low = 0; + RESULT_GUARD(s2n_stuffer_hex_digit_from_char(in[(i * 2)], &hex_high)); + RESULT_GUARD(s2n_stuffer_hex_digit_from_char(in[(i * 2) + 1], &hex_low)); + out[i] = (hex_high * 16) + hex_low; } RESULT_GUARD_POSIX(s2n_stuffer_skip_write(bytes_out, bytes_size)); @@ -107,8 +105,9 @@ static S2N_RESULT s2n_stuffer_hex_read_n_bytes(struct s2n_stuffer *stuffer, uint *u = 0; for (size_t i = 0; i < b.size; i++) { *u <<= 4; - RESULT_GUARD(s2n_stuffer_hex_validate_char(b.data[i])); - *u |= hex_to_value[b.data[i]]; + uint8_t hex = 0; + RESULT_GUARD(s2n_stuffer_hex_digit_from_char(b.data[i], &hex)); + *u += hex; } return S2N_RESULT_OK; @@ -119,7 +118,8 @@ S2N_RESULT s2n_stuffer_read_uint16_hex(struct s2n_stuffer *stuffer, uint16_t *u) RESULT_ENSURE_REF(u); uint64_t u64 = 0; RESULT_GUARD(s2n_stuffer_hex_read_n_bytes(stuffer, sizeof(uint16_t), &u64)); - *u = u64 & 0xffff; + RESULT_ENSURE_LTE(u64, UINT16_MAX); + *u = u64; return S2N_RESULT_OK; } @@ -128,7 +128,8 @@ S2N_RESULT s2n_stuffer_read_uint8_hex(struct s2n_stuffer *stuffer, uint8_t *u) RESULT_ENSURE_REF(u); uint64_t u64 = 0; RESULT_GUARD(s2n_stuffer_hex_read_n_bytes(stuffer, sizeof(uint8_t), &u64)); - *u = u64 & 0xff; + RESULT_ENSURE_LTE(u64, UINT8_MAX); + *u = u64; return S2N_RESULT_OK; }