Skip to content

Commit

Permalink
refactor: move stuffer hex methods out of testlib (#4653)
Browse files Browse the repository at this point in the history
  • Loading branch information
lrstewart authored Jul 23, 2024
1 parent 138e3ec commit ead2266
Show file tree
Hide file tree
Showing 14 changed files with 801 additions and 321 deletions.
1 change: 1 addition & 0 deletions error/s2n_errno.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
1 change: 1 addition & 0 deletions error/s2n_errno.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down
17 changes: 17 additions & 0 deletions stuffer/s2n_stuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
161 changes: 161 additions & 0 deletions stuffer/s2n_stuffer_hex.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* 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_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;
}

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 = 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));
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;
uint8_t hex = 0;
RESULT_GUARD(s2n_stuffer_hex_digit_from_char(b.data[i], &hex));
*u += hex;
}

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));
RESULT_ENSURE_LTE(u64, UINT16_MAX);
*u = u64;
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));
RESULT_ENSURE_LTE(u64, UINT8_MAX);
*u = u64;
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);
}
Loading

0 comments on commit ead2266

Please sign in to comment.