1/* BEGIN_HEADER */
2#include <alignment.h>
3
4#include <stdint.h>
5
6#if defined(__clang__)
7#pragma clang diagnostic ignored "-Wunreachable-code"
8#endif
9
10/*
11 * Convert a string of the form "abcd" (case-insensitive) to a uint64_t.
12 */
13int parse_hex_string(char *hex_string, uint64_t *result)
14{
15    uint8_t raw[8] = { 0 };
16    size_t olen;
17    if (mbedtls_test_unhexify(raw, sizeof(raw), hex_string, &olen) != 0) {
18        return 0;
19    }
20
21    *result = 0;
22    for (size_t i = 0; i < olen; i++) {
23        *result |= ((uint64_t) raw[i]) << ((olen - i - 1) * 8);
24    }
25    return 1;
26}
27
28/* END_HEADER */
29
30/* BEGIN_CASE */
31void mbedtls_unaligned_access(int size, int offset)
32{
33    /* Define 64-bit aligned raw byte array */
34    uint64_t raw[2];
35
36    /* Populate with known data */
37    uint8_t *x = (uint8_t *) raw;
38    for (size_t i = 0; i < sizeof(raw); i++) {
39        x[i] = (uint8_t) i;
40    }
41
42    TEST_ASSERT(size == 16 || size == 32 || size == 64);
43
44    uint64_t r = 0;
45    switch (size) {
46        case 16:
47            r = mbedtls_get_unaligned_uint16(x + offset);
48            break;
49        case 32:
50            r = mbedtls_get_unaligned_uint32(x + offset);
51            break;
52        case 64:
53            r = mbedtls_get_unaligned_uint64(x + offset);
54            break;
55    }
56
57    /* Define expected result by manually aligning the raw bytes, and
58     * reading back with a normal pointer access. */
59    uint64_t raw_aligned_64;
60    uint16_t *raw_aligned_16 = (uint16_t *) &raw_aligned_64;
61    uint32_t *raw_aligned_32 = (uint32_t *) &raw_aligned_64;
62    memcpy(&raw_aligned_64, ((uint8_t *) &raw) + offset, size / 8);
63    /* Make a 16/32/64 byte read from the aligned location, and copy to expected */
64    uint64_t expected = 0;
65    switch (size) {
66        case 16:
67            expected = *raw_aligned_16;
68            break;
69        case 32:
70            expected = *raw_aligned_32;
71            break;
72        case 64:
73            expected = raw_aligned_64;
74            break;
75    }
76
77    TEST_EQUAL(r, expected);
78
79    /* Write sentinel to the part of the array we will test writing to */
80    for (size_t i = 0; i < (size_t) (size / 8); i++) {
81        x[i + offset] = 0xff;
82    }
83    /*
84     * Write back to the array with mbedtls_put_unaligned_uint16 and validate
85     * that the array is unchanged as a result.
86     */
87    switch (size) {
88        case 16:
89            mbedtls_put_unaligned_uint16(x + offset, r);
90            break;
91        case 32:
92            mbedtls_put_unaligned_uint32(x + offset, r);
93            break;
94        case 64:
95            mbedtls_put_unaligned_uint64(x + offset, r);
96            break;
97    }
98    for (size_t i = 0; i < sizeof(x); i++) {
99        TEST_EQUAL(x[i], (uint8_t) i);
100    }
101}
102/* END_CASE */
103
104/* BEGIN_CASE */
105void mbedtls_byteswap(char *input_str, int size, char *expected_str)
106{
107    uint64_t input = 0, expected = 0;
108    TEST_ASSERT(parse_hex_string(input_str, &input));
109    TEST_ASSERT(parse_hex_string(expected_str, &expected));
110
111    /* Check against expected result */
112    uint64_t r = 0;
113    switch (size) {
114        case 16:
115            r = MBEDTLS_BSWAP16(input);
116            break;
117        case 32:
118            r = MBEDTLS_BSWAP32(input);
119            break;
120        case 64:
121            r = MBEDTLS_BSWAP64(input);
122            break;
123        default:
124            TEST_FAIL("size must be 16, 32 or 64");
125    }
126    TEST_EQUAL(r, expected);
127
128    /*
129     * Check byte by byte by extracting bytes from opposite ends of
130     * input and r.
131     */
132    for (size_t i = 0; i < (size_t) (size / 8); i++) {
133        size_t s1 = i * 8;
134        size_t s2 = ((size / 8 - 1) - i) * 8;
135        uint64_t a = (input & ((uint64_t) 0xff << s1)) >> s1;
136        uint64_t b = (r & ((uint64_t) 0xff << s2)) >> s2;
137        TEST_EQUAL(a, b);
138    }
139
140    /* Check BSWAP(BSWAP(x)) == x */
141    switch (size) {
142        case 16:
143            r = MBEDTLS_BSWAP16(r);
144            TEST_EQUAL(r, input & 0xffff);
145            break;
146        case 32:
147            r = MBEDTLS_BSWAP32(r);
148            TEST_EQUAL(r, input & 0xffffffff);
149            break;
150        case 64:
151            r = MBEDTLS_BSWAP64(r);
152            TEST_EQUAL(r, input);
153            break;
154    }
155}
156/* END_CASE */
157
158/* BEGIN_CASE */
159void get_byte()
160{
161    uint8_t data[16];
162
163    for (size_t i = 0; i < sizeof(data); i++) {
164        data[i] = (uint8_t) i;
165    }
166
167    uint64_t u64 = 0x0706050403020100;
168    for (size_t b = 0; b < 8; b++) {
169        uint8_t expected = b;
170        uint8_t actual = b + 1;
171        switch (b) {
172            case 0:
173                actual = MBEDTLS_BYTE_0(u64);
174                break;
175            case 1:
176                actual = MBEDTLS_BYTE_1(u64);
177                break;
178            case 2:
179                actual = MBEDTLS_BYTE_2(u64);
180                break;
181            case 3:
182                actual = MBEDTLS_BYTE_3(u64);
183                break;
184            case 4:
185                actual = MBEDTLS_BYTE_4(u64);
186                break;
187            case 5:
188                actual = MBEDTLS_BYTE_5(u64);
189                break;
190            case 6:
191                actual = MBEDTLS_BYTE_6(u64);
192                break;
193            case 7:
194                actual = MBEDTLS_BYTE_7(u64);
195                break;
196        }
197        TEST_EQUAL(actual, expected);
198    }
199
200    uint32_t u32 = 0x03020100;
201    for (size_t b = 0; b < 4; b++) {
202        uint8_t expected = b;
203        uint8_t actual = b + 1;
204        switch (b) {
205            case 0:
206                actual = MBEDTLS_BYTE_0(u32);
207                break;
208            case 1:
209                actual = MBEDTLS_BYTE_1(u32);
210                break;
211            case 2:
212                actual = MBEDTLS_BYTE_2(u32);
213                break;
214            case 3:
215                actual = MBEDTLS_BYTE_3(u32);
216                break;
217        }
218        TEST_EQUAL(actual, expected);
219    }
220
221    uint16_t u16 = 0x0100;
222    for (size_t b = 0; b < 2; b++) {
223        uint8_t expected = b;
224        uint8_t actual = b + 1;
225        switch (b) {
226            case 0:
227                actual = MBEDTLS_BYTE_0(u16);
228                break;
229            case 1:
230                actual = MBEDTLS_BYTE_1(u16);
231                break;
232        }
233        TEST_EQUAL(actual, expected);
234    }
235
236    uint8_t u8 = 0x01;
237    uint8_t actual = MBEDTLS_BYTE_0(u8);
238    TEST_EQUAL(actual, u8);
239}
240/* END_CASE */
241
242/* BEGIN_CASE */
243void unaligned_access_endian_aware(int size, int offset, int big_endian)
244{
245    TEST_ASSERT(size == 16 || size == 24 || size == 32 || size == 64);
246    TEST_ASSERT(offset >= 0 && offset < 8);
247
248    /* Define 64-bit aligned raw byte array */
249    uint64_t raw[2];
250    /* Populate with known data: x == { 0, 1, 2, ... } */
251    uint8_t *x = (uint8_t *) raw;
252    for (size_t i = 0; i < sizeof(raw); i++) {
253        x[i] = (uint8_t) i;
254    }
255
256    uint64_t read = 0;
257    if (big_endian) {
258        switch (size) {
259            case 16:
260                read = MBEDTLS_GET_UINT16_BE(x, offset);
261                break;
262            case 24:
263                read = MBEDTLS_GET_UINT24_BE(x, offset);
264                break;
265            case 32:
266                read = MBEDTLS_GET_UINT32_BE(x, offset);
267                break;
268            case 64:
269                read = MBEDTLS_GET_UINT64_BE(x, offset);
270                break;
271        }
272    } else {
273        switch (size) {
274            case 16:
275                read = MBEDTLS_GET_UINT16_LE(x, offset);
276                break;
277            case 24:
278                read = MBEDTLS_GET_UINT24_LE(x, offset);
279                break;
280            case 32:
281                read = MBEDTLS_GET_UINT32_LE(x, offset);
282                break;
283            case 64:
284                read = MBEDTLS_GET_UINT64_LE(x, offset);
285                break;
286        }
287    }
288
289    /* Build up expected value byte by byte, in either big or little endian format */
290    uint64_t expected = 0;
291    for (size_t i = 0; i < (size_t) (size / 8); i++) {
292        uint64_t b = x[i + offset];
293        uint8_t shift = (big_endian) ? (8 * ((size / 8 - 1) - i)) : (8 * i);
294        expected |= b << shift;
295    }
296
297    /* Verify read */
298    TEST_EQUAL(read, expected);
299
300    /* Test writing back to memory. First write sentinel */
301    for (size_t i = 0; i < (size_t) (size / 8); i++) {
302        x[i + offset] = 0xff;
303    }
304    /* Overwrite sentinel with endian-aware write macro */
305    if (big_endian) {
306        switch (size) {
307            case 16:
308                MBEDTLS_PUT_UINT16_BE(read, x, offset);
309                break;
310            case 24:
311                MBEDTLS_PUT_UINT24_BE(read, x, offset);
312                break;
313            case 32:
314                MBEDTLS_PUT_UINT32_BE(read, x, offset);
315                break;
316            case 64:
317                MBEDTLS_PUT_UINT64_BE(read, x, offset);
318                break;
319        }
320    } else {
321        switch (size) {
322            case 16:
323                MBEDTLS_PUT_UINT16_LE(read, x, offset);
324                break;
325            case 24:
326                MBEDTLS_PUT_UINT24_LE(read, x, offset);
327                break;
328            case 32:
329                MBEDTLS_PUT_UINT32_LE(read, x, offset);
330                break;
331            case 64:
332                MBEDTLS_PUT_UINT64_LE(read, x, offset);
333                break;
334        }
335    }
336
337    /* Verify write - check memory is correct */
338    for (size_t i = 0; i < sizeof(raw); i++) {
339        TEST_EQUAL(x[i], (uint8_t) i);
340    }
341}
342/* END_CASE */
343
344/* BEGIN_CASE */
345void mbedtls_is_big_endian()
346{
347    uint16_t check = 0x1234;
348    uint8_t *p = (uint8_t *) &check;
349
350    if (MBEDTLS_IS_BIG_ENDIAN) {
351        /* Big-endian: data stored MSB first, i.e. p == { 0x12, 0x34 } */
352        TEST_EQUAL(p[0], 0x12);
353        TEST_EQUAL(p[1], 0x34);
354    } else {
355        /* Little-endian: data stored LSB first, i.e. p == { 0x34, 0x12 } */
356        TEST_EQUAL(p[0], 0x34);
357        TEST_EQUAL(p[1], 0x12);
358    }
359}
360/* END_CASE */
361