Skip to content

Commit 4b15a4b

Browse files
authored
refactor: move stuffer hex methods out of testlib (#4653)
1 parent 138e3ec commit 4b15a4b

14 files changed

+801
-321
lines changed

error/s2n_errno.c

+1
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ static const char *no_such_error = "Internal s2n error";
312312
ERR_ENTRY(S2N_ERR_MISSING_CLIENT_CERT, "Server requires client certificate") \
313313
ERR_ENTRY(S2N_ERR_INVALID_SERIALIZED_CONNECTION, "Serialized connection is invalid"); \
314314
ERR_ENTRY(S2N_ERR_TOO_MANY_CAS, "Too many certificate authorities in trust store"); \
315+
ERR_ENTRY(S2N_ERR_BAD_HEX, "Could not parse malformed hex string"); \
315316
/* clang-format on */
316317

317318
#define ERR_STR_CASE(ERR, str) \

error/s2n_errno.h

+1
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ typedef enum {
237237
S2N_ERR_LIBCRYPTO_VERSION_NUMBER_MISMATCH,
238238
S2N_ERR_LIBCRYPTO_VERSION_NAME_MISMATCH,
239239
S2N_ERR_OSSL_PROVIDER,
240+
S2N_ERR_BAD_HEX,
240241
S2N_ERR_TEST_ASSERTION,
241242
S2N_ERR_T_INTERNAL_END,
242243

stuffer/s2n_stuffer.h

+17
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,23 @@ int S2N_RESULT_MUST_USE s2n_stuffer_write_vector_size(struct s2n_stuffer_reserva
154154
/* Copy one stuffer to another */
155155
int s2n_stuffer_copy(struct s2n_stuffer *from, struct s2n_stuffer *to, uint32_t len);
156156

157+
/* Convert between hex strings and raw bytes.
158+
*
159+
* When reading hex, the characters can be uppercase or lowercase.
160+
* When writing hex, lowercase characters are used.
161+
*
162+
* Examples:
163+
* "1234567890ABCdef" == [ 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef ]
164+
* "FF" == 255 or [ 0xff ]
165+
* "0001" == 1 or [ 0x00, 0x01 ]
166+
*/
167+
S2N_RESULT s2n_stuffer_read_hex(struct s2n_stuffer *bytes_out, const struct s2n_blob *hex_in);
168+
S2N_RESULT s2n_stuffer_write_hex(struct s2n_stuffer *hex_out, const struct s2n_blob *bytes_in);
169+
S2N_RESULT s2n_stuffer_read_uint8_hex(struct s2n_stuffer *stuffer, uint8_t *u);
170+
S2N_RESULT s2n_stuffer_write_uint8_hex(struct s2n_stuffer *stuffer, uint8_t u);
171+
S2N_RESULT s2n_stuffer_read_uint16_hex(struct s2n_stuffer *stuffer, uint16_t *u);
172+
S2N_RESULT s2n_stuffer_write_uint16_hex(struct s2n_stuffer *stuffer, uint16_t u);
173+
157174
/* Read and write base64 */
158175
int s2n_stuffer_read_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *out);
159176
int s2n_stuffer_write_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *in);

stuffer/s2n_stuffer_hex.c

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
#include "error/s2n_errno.h"
17+
#include "stuffer/s2n_stuffer.h"
18+
#include "utils/s2n_safety.h"
19+
20+
static const uint8_t value_to_hex[16] = {
21+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
22+
};
23+
24+
static const uint8_t hex_to_value[] = {
25+
/* clang-format off */
26+
['0'] = 0, ['1'] = 1, ['2'] = 2, ['3'] = 3, ['4'] = 4,
27+
['5'] = 5, ['6'] = 6, ['7'] = 7, ['8'] = 8, ['9'] = 9,
28+
['a'] = 10, ['b'] = 11, ['c'] = 12, ['d'] = 13, ['e'] = 14, ['f'] = 15,
29+
['A'] = 10, ['B'] = 11, ['C'] = 12, ['D'] = 13, ['E'] = 14, ['F'] = 15,
30+
/* clang-format on */
31+
};
32+
33+
static S2N_RESULT s2n_stuffer_hex_digit_from_char(uint8_t c, uint8_t *i)
34+
{
35+
RESULT_ENSURE(c < s2n_array_len(hex_to_value), S2N_ERR_BAD_HEX);
36+
/* Invalid characters map to 0 in hex_to_value, but so does '0'. */
37+
if (hex_to_value[c] == 0) {
38+
RESULT_ENSURE(c == '0', S2N_ERR_BAD_HEX);
39+
}
40+
*i = hex_to_value[c];
41+
return S2N_RESULT_OK;
42+
}
43+
44+
S2N_RESULT s2n_stuffer_read_hex(struct s2n_stuffer *bytes_out, const struct s2n_blob *hex_in)
45+
{
46+
RESULT_PRECONDITION(s2n_stuffer_validate(bytes_out));
47+
RESULT_PRECONDITION(s2n_blob_validate(hex_in));
48+
49+
size_t hex_size = hex_in->size;
50+
size_t bytes_size = hex_in->size / 2;
51+
RESULT_ENSURE(hex_size % 2 == 0, S2N_ERR_BAD_HEX);
52+
if (hex_size == 0) {
53+
return S2N_RESULT_OK;
54+
}
55+
56+
RESULT_GUARD_POSIX(s2n_stuffer_reserve_space(bytes_out, bytes_size));
57+
uint8_t *out = bytes_out->blob.data + bytes_out->write_cursor;
58+
uint8_t *in = hex_in->data;
59+
60+
for (size_t i = 0; i < bytes_size; i++) {
61+
uint8_t hex_high = 0, hex_low = 0;
62+
RESULT_GUARD(s2n_stuffer_hex_digit_from_char(in[(i * 2)], &hex_high));
63+
RESULT_GUARD(s2n_stuffer_hex_digit_from_char(in[(i * 2) + 1], &hex_low));
64+
out[i] = (hex_high * 16) + hex_low;
65+
}
66+
67+
RESULT_GUARD_POSIX(s2n_stuffer_skip_write(bytes_out, bytes_size));
68+
return S2N_RESULT_OK;
69+
}
70+
71+
S2N_RESULT s2n_stuffer_write_hex(struct s2n_stuffer *hex_out, const struct s2n_blob *bytes_in)
72+
{
73+
RESULT_PRECONDITION(s2n_stuffer_validate(hex_out));
74+
RESULT_PRECONDITION(s2n_blob_validate(bytes_in));
75+
76+
size_t bytes_size = bytes_in->size;
77+
size_t hex_size = bytes_size * 2;
78+
79+
RESULT_GUARD_POSIX(s2n_stuffer_reserve_space(hex_out, hex_size));
80+
uint8_t *out = hex_out->blob.data + hex_out->write_cursor;
81+
uint8_t *in = bytes_in->data;
82+
83+
for (size_t i = 0; i < bytes_size; i++) {
84+
out[(i * 2)] = value_to_hex[(in[i] >> 4)];
85+
out[(i * 2) + 1] = value_to_hex[(in[i] & 0x0f)];
86+
}
87+
88+
RESULT_GUARD_POSIX(s2n_stuffer_skip_write(hex_out, hex_size));
89+
return S2N_RESULT_OK;
90+
}
91+
92+
static S2N_RESULT s2n_stuffer_hex_read_n_bytes(struct s2n_stuffer *stuffer, uint8_t n, uint64_t *u)
93+
{
94+
RESULT_ENSURE_LTE(n, sizeof(uint64_t));
95+
RESULT_ENSURE_REF(u);
96+
97+
uint8_t hex_data[16] = { 0 };
98+
struct s2n_blob b = { 0 };
99+
RESULT_GUARD_POSIX(s2n_blob_init(&b, hex_data, n * 2));
100+
101+
RESULT_ENSURE_REF(stuffer);
102+
RESULT_ENSURE(s2n_stuffer_read(stuffer, &b) == S2N_SUCCESS, S2N_ERR_BAD_HEX);
103+
104+
/* Start with u = 0 */
105+
*u = 0;
106+
for (size_t i = 0; i < b.size; i++) {
107+
*u <<= 4;
108+
uint8_t hex = 0;
109+
RESULT_GUARD(s2n_stuffer_hex_digit_from_char(b.data[i], &hex));
110+
*u += hex;
111+
}
112+
113+
return S2N_RESULT_OK;
114+
}
115+
116+
S2N_RESULT s2n_stuffer_read_uint16_hex(struct s2n_stuffer *stuffer, uint16_t *u)
117+
{
118+
RESULT_ENSURE_REF(u);
119+
uint64_t u64 = 0;
120+
RESULT_GUARD(s2n_stuffer_hex_read_n_bytes(stuffer, sizeof(uint16_t), &u64));
121+
RESULT_ENSURE_LTE(u64, UINT16_MAX);
122+
*u = u64;
123+
return S2N_RESULT_OK;
124+
}
125+
126+
S2N_RESULT s2n_stuffer_read_uint8_hex(struct s2n_stuffer *stuffer, uint8_t *u)
127+
{
128+
RESULT_ENSURE_REF(u);
129+
uint64_t u64 = 0;
130+
RESULT_GUARD(s2n_stuffer_hex_read_n_bytes(stuffer, sizeof(uint8_t), &u64));
131+
RESULT_ENSURE_LTE(u64, UINT8_MAX);
132+
*u = u64;
133+
return S2N_RESULT_OK;
134+
}
135+
136+
static S2N_RESULT s2n_stuffer_hex_write_n_bytes(struct s2n_stuffer *stuffer, uint8_t n, uint64_t u)
137+
{
138+
RESULT_ENSURE_LTE(n, sizeof(uint64_t));
139+
140+
uint8_t hex_data[16] = { 0 };
141+
struct s2n_blob b = { 0 };
142+
RESULT_GUARD_POSIX(s2n_blob_init(&b, hex_data, n * 2));
143+
144+
for (size_t i = b.size; i > 0; i--) {
145+
b.data[i - 1] = value_to_hex[u & 0x0f];
146+
u >>= 4;
147+
}
148+
149+
RESULT_GUARD_POSIX(s2n_stuffer_write(stuffer, &b));
150+
return S2N_RESULT_OK;
151+
}
152+
153+
S2N_RESULT s2n_stuffer_write_uint16_hex(struct s2n_stuffer *stuffer, uint16_t u)
154+
{
155+
return s2n_stuffer_hex_write_n_bytes(stuffer, sizeof(uint16_t), u);
156+
}
157+
158+
S2N_RESULT s2n_stuffer_write_uint8_hex(struct s2n_stuffer *stuffer, uint8_t u)
159+
{
160+
return s2n_stuffer_hex_write_n_bytes(stuffer, sizeof(uint8_t), u);
161+
}

0 commit comments

Comments
 (0)