1/* BEGIN_HEADER */
2#include "mbedtls/entropy.h"
3#include "entropy_poll.h"
4#include "mbedtls/md.h"
5#include "string.h"
6
7typedef enum {
8    DUMMY_CONSTANT_LENGTH, /* Output context->length bytes */
9    DUMMY_REQUESTED_LENGTH, /* Output whatever length was requested */
10    DUMMY_FAIL, /* Return an error code */
11} entropy_dummy_instruction;
12
13typedef struct {
14    entropy_dummy_instruction instruction;
15    size_t length; /* Length to return for DUMMY_CONSTANT_LENGTH */
16    size_t calls; /* Incremented at each call */
17} entropy_dummy_context;
18
19/*
20 * Dummy entropy source
21 *
22 * If data is NULL, write exactly the requested length.
23 * Otherwise, write the length indicated by data or error if negative
24 */
25static int entropy_dummy_source(void *arg, unsigned char *output,
26                                size_t len, size_t *olen)
27{
28    entropy_dummy_context *context = arg;
29    ++context->calls;
30
31    switch (context->instruction) {
32        case DUMMY_CONSTANT_LENGTH:
33            *olen = context->length;
34            break;
35        case DUMMY_REQUESTED_LENGTH:
36            *olen = len;
37            break;
38        case DUMMY_FAIL:
39            return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
40    }
41
42    memset(output, 0x2a, *olen);
43    return 0;
44}
45
46/*
47 * Ability to clear entropy sources to allow testing with just predefined
48 * entropy sources. This function or tests depending on it might break if there
49 * are internal changes to how entropy sources are registered.
50 *
51 * To be called immediately after mbedtls_entropy_init().
52 *
53 * Just resetting the counter. New sources will overwrite existing ones.
54 * This might break memory checks in the future if sources need 'free-ing' then
55 * as well.
56 */
57static void entropy_clear_sources(mbedtls_entropy_context *ctx)
58{
59    ctx->source_count = 0;
60}
61
62#if defined(MBEDTLS_ENTROPY_NV_SEED)
63/*
64 * NV seed read/write functions that use a buffer instead of a file
65 */
66static unsigned char buffer_seed[MBEDTLS_ENTROPY_BLOCK_SIZE];
67
68int buffer_nv_seed_read(unsigned char *buf, size_t buf_len)
69{
70    if (buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE) {
71        return -1;
72    }
73
74    memcpy(buf, buffer_seed, MBEDTLS_ENTROPY_BLOCK_SIZE);
75    return 0;
76}
77
78int buffer_nv_seed_write(unsigned char *buf, size_t buf_len)
79{
80    if (buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE) {
81        return -1;
82    }
83
84    memcpy(buffer_seed, buf, MBEDTLS_ENTROPY_BLOCK_SIZE);
85    return 0;
86}
87
88/*
89 * NV seed read/write helpers that fill the base seedfile
90 */
91static int write_nv_seed(unsigned char *buf, size_t buf_len)
92{
93    FILE *f;
94
95    if (buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE) {
96        return -1;
97    }
98
99    if ((f = fopen(MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "w")) == NULL) {
100        return -1;
101    }
102
103    if (fwrite(buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f) !=
104        MBEDTLS_ENTROPY_BLOCK_SIZE) {
105        fclose(f);
106        return -1;
107    }
108
109    fclose(f);
110
111    return 0;
112}
113
114int read_nv_seed(unsigned char *buf, size_t buf_len)
115{
116    FILE *f;
117
118    if (buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE) {
119        return -1;
120    }
121
122    if ((f = fopen(MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "rb")) == NULL) {
123        return -1;
124    }
125
126    if (fread(buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f) !=
127        MBEDTLS_ENTROPY_BLOCK_SIZE) {
128        fclose(f);
129        return -1;
130    }
131
132    fclose(f);
133
134    return 0;
135}
136#endif /* MBEDTLS_ENTROPY_NV_SEED */
137/* END_HEADER */
138
139/* BEGIN_DEPENDENCIES
140 * depends_on:MBEDTLS_ENTROPY_C:!MBEDTLS_PSA_INJECT_ENTROPY
141 * END_DEPENDENCIES
142 */
143
144/* BEGIN_CASE */
145void entropy_init_free(int reinit)
146{
147    mbedtls_entropy_context ctx;
148
149    /* Double free is not explicitly documented to work, but it is convenient
150     * to call mbedtls_entropy_free() unconditionally on an error path without
151     * checking whether it has already been called in the success path. */
152
153    mbedtls_entropy_init(&ctx);
154    mbedtls_entropy_free(&ctx);
155
156    if (reinit) {
157        mbedtls_entropy_init(&ctx);
158    }
159    mbedtls_entropy_free(&ctx);
160
161    /* This test case always succeeds, functionally speaking. A plausible
162     * bug might trigger an invalid pointer dereference or a memory leak. */
163    goto exit;
164}
165/* END_CASE */
166
167/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
168void entropy_seed_file(char *path, int ret)
169{
170    mbedtls_entropy_context ctx;
171    mbedtls_entropy_init(&ctx);
172
173    MD_PSA_INIT();
174
175    TEST_ASSERT(mbedtls_entropy_write_seed_file(&ctx, path) == ret);
176    TEST_ASSERT(mbedtls_entropy_update_seed_file(&ctx, path) == ret);
177
178exit:
179    mbedtls_entropy_free(&ctx);
180    MD_PSA_DONE();
181}
182/* END_CASE */
183
184/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
185void entropy_write_base_seed_file(int ret)
186{
187    mbedtls_entropy_context ctx;
188    mbedtls_entropy_init(&ctx);
189
190    MD_PSA_INIT();
191
192    TEST_ASSERT(mbedtls_entropy_write_seed_file(&ctx, MBEDTLS_PLATFORM_STD_NV_SEED_FILE) == ret);
193    TEST_ASSERT(mbedtls_entropy_update_seed_file(&ctx, MBEDTLS_PLATFORM_STD_NV_SEED_FILE) == ret);
194
195exit:
196    mbedtls_entropy_free(&ctx);
197    MD_PSA_DONE();
198}
199/* END_CASE */
200
201/* BEGIN_CASE */
202void entropy_no_sources()
203{
204    mbedtls_entropy_context ctx;
205    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
206
207    mbedtls_entropy_init(&ctx);
208    entropy_clear_sources(&ctx);
209    TEST_EQUAL(mbedtls_entropy_func(&ctx, buf, sizeof(buf)),
210               MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED);
211
212exit:
213    mbedtls_entropy_free(&ctx);
214}
215/* END_CASE */
216
217/* BEGIN_CASE */
218void entropy_too_many_sources()
219{
220    mbedtls_entropy_context ctx;
221    size_t i;
222    entropy_dummy_context dummy = { DUMMY_REQUESTED_LENGTH, 0, 0 };
223
224    mbedtls_entropy_init(&ctx);
225
226    /*
227     * It's hard to tell precisely when the error will occur,
228     * since we don't know how many sources were automatically added.
229     */
230    for (i = 0; i < MBEDTLS_ENTROPY_MAX_SOURCES; i++) {
231        (void) mbedtls_entropy_add_source(&ctx, entropy_dummy_source, &dummy,
232                                          16, MBEDTLS_ENTROPY_SOURCE_WEAK);
233    }
234
235    TEST_ASSERT(mbedtls_entropy_add_source(&ctx, entropy_dummy_source, &dummy,
236                                           16, MBEDTLS_ENTROPY_SOURCE_WEAK)
237                == MBEDTLS_ERR_ENTROPY_MAX_SOURCES);
238
239exit:
240    mbedtls_entropy_free(&ctx);
241}
242/* END_CASE */
243
244/* BEGIN_CASE depends_on:ENTROPY_HAVE_STRONG */
245void entropy_func_len(int len, int ret)
246{
247    mbedtls_entropy_context ctx;
248    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE + 10] = { 0 };
249    unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE + 10] = { 0 };
250    size_t i, j;
251
252    mbedtls_entropy_init(&ctx);
253
254    MD_PSA_INIT();
255
256    /*
257     * See comments in mbedtls_entropy_self_test()
258     */
259    for (i = 0; i < 8; i++) {
260        TEST_ASSERT(mbedtls_entropy_func(&ctx, buf, len) == ret);
261        for (j = 0; j < sizeof(buf); j++) {
262            acc[j] |= buf[j];
263        }
264    }
265
266    if (ret == 0) {
267        for (j = 0; j < (size_t) len; j++) {
268            TEST_ASSERT(acc[j] != 0);
269        }
270    }
271
272    for (j = len; j < sizeof(buf); j++) {
273        TEST_ASSERT(acc[j] == 0);
274    }
275
276exit:
277    mbedtls_entropy_free(&ctx);
278    MD_PSA_DONE();
279}
280/* END_CASE */
281
282/* BEGIN_CASE */
283void entropy_source_fail(char *path)
284{
285    mbedtls_entropy_context ctx;
286    unsigned char buf[16];
287    entropy_dummy_context dummy = { DUMMY_FAIL, 0, 0 };
288
289    mbedtls_entropy_init(&ctx);
290
291    MD_PSA_INIT();
292
293    TEST_ASSERT(mbedtls_entropy_add_source(&ctx, entropy_dummy_source,
294                                           &dummy, 16,
295                                           MBEDTLS_ENTROPY_SOURCE_WEAK)
296                == 0);
297
298    TEST_ASSERT(mbedtls_entropy_func(&ctx, buf, sizeof(buf))
299                == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED);
300    TEST_ASSERT(mbedtls_entropy_gather(&ctx)
301                == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED);
302#if defined(MBEDTLS_FS_IO) && defined(MBEDTLS_ENTROPY_NV_SEED)
303    TEST_ASSERT(mbedtls_entropy_write_seed_file(&ctx, path)
304                == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED);
305    TEST_ASSERT(mbedtls_entropy_update_seed_file(&ctx, path)
306                == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED);
307#else
308    ((void) path);
309#endif
310
311exit:
312    mbedtls_entropy_free(&ctx);
313    MD_PSA_DONE();
314}
315/* END_CASE */
316
317/* BEGIN_CASE */
318void entropy_threshold(int threshold, int chunk_size, int result)
319{
320    mbedtls_entropy_context ctx;
321    entropy_dummy_context strong =
322    { DUMMY_CONSTANT_LENGTH, MBEDTLS_ENTROPY_BLOCK_SIZE, 0 };
323    entropy_dummy_context weak = { DUMMY_CONSTANT_LENGTH, chunk_size, 0 };
324    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 };
325    int ret;
326
327    mbedtls_entropy_init(&ctx);
328    entropy_clear_sources(&ctx);
329
330    MD_PSA_INIT();
331
332    /* Set strong source that reaches its threshold immediately and
333     * a weak source whose threshold is a test parameter. */
334    TEST_ASSERT(mbedtls_entropy_add_source(&ctx, entropy_dummy_source,
335                                           &strong, 1,
336                                           MBEDTLS_ENTROPY_SOURCE_STRONG) == 0);
337    TEST_ASSERT(mbedtls_entropy_add_source(&ctx, entropy_dummy_source,
338                                           &weak, threshold,
339                                           MBEDTLS_ENTROPY_SOURCE_WEAK) == 0);
340
341    ret = mbedtls_entropy_func(&ctx, buf, sizeof(buf));
342
343    if (result >= 0) {
344        TEST_ASSERT(ret == 0);
345#if defined(MBEDTLS_ENTROPY_NV_SEED)
346        /* If the NV seed functionality is enabled, there are two entropy
347         * updates: before and after updating the NV seed. */
348        result *= 2;
349#endif
350        TEST_ASSERT(weak.calls == (size_t) result);
351    } else {
352        TEST_ASSERT(ret == result);
353    }
354
355exit:
356    mbedtls_entropy_free(&ctx);
357    MD_PSA_DONE();
358}
359/* END_CASE */
360
361/* BEGIN_CASE */
362void entropy_calls(int strength1, int strength2,
363                   int threshold, int chunk_size,
364                   int result)
365{
366    /*
367     * if result >= 0: result = expected number of calls to source 1
368     * if result < 0: result = expected return code from mbedtls_entropy_func()
369     */
370
371    mbedtls_entropy_context ctx;
372    entropy_dummy_context dummy1 = { DUMMY_CONSTANT_LENGTH, chunk_size, 0 };
373    entropy_dummy_context dummy2 = { DUMMY_CONSTANT_LENGTH, chunk_size, 0 };
374    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 };
375    int ret;
376
377    mbedtls_entropy_init(&ctx);
378    entropy_clear_sources(&ctx);
379
380    MD_PSA_INIT();
381
382    TEST_ASSERT(mbedtls_entropy_add_source(&ctx, entropy_dummy_source,
383                                           &dummy1, threshold,
384                                           strength1) == 0);
385    TEST_ASSERT(mbedtls_entropy_add_source(&ctx, entropy_dummy_source,
386                                           &dummy2, threshold,
387                                           strength2) == 0);
388
389    ret = mbedtls_entropy_func(&ctx, buf, sizeof(buf));
390
391    if (result >= 0) {
392        TEST_ASSERT(ret == 0);
393#if defined(MBEDTLS_ENTROPY_NV_SEED)
394        /* If the NV seed functionality is enabled, there are two entropy
395         * updates: before and after updating the NV seed. */
396        result *= 2;
397#endif
398        TEST_ASSERT(dummy1.calls == (size_t) result);
399    } else {
400        TEST_ASSERT(ret == result);
401    }
402
403exit:
404    mbedtls_entropy_free(&ctx);
405    MD_PSA_DONE();
406}
407/* END_CASE */
408
409/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
410void nv_seed_file_create()
411{
412    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
413
414    memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);
415
416    TEST_ASSERT(write_nv_seed(buf, MBEDTLS_ENTROPY_BLOCK_SIZE) == 0);
417}
418/* END_CASE */
419
420/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO:MBEDTLS_PLATFORM_NV_SEED_ALT */
421void entropy_nv_seed_std_io()
422{
423    unsigned char io_seed[MBEDTLS_ENTROPY_BLOCK_SIZE];
424    unsigned char check_seed[MBEDTLS_ENTROPY_BLOCK_SIZE];
425
426    memset(io_seed, 1, MBEDTLS_ENTROPY_BLOCK_SIZE);
427    memset(check_seed, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);
428
429    mbedtls_platform_set_nv_seed(mbedtls_platform_std_nv_seed_read,
430                                 mbedtls_platform_std_nv_seed_write);
431
432    /* Check if platform NV read and write manipulate the same data */
433    TEST_ASSERT(write_nv_seed(io_seed, MBEDTLS_ENTROPY_BLOCK_SIZE) == 0);
434    TEST_ASSERT(mbedtls_nv_seed_read(check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE) ==
435                MBEDTLS_ENTROPY_BLOCK_SIZE);
436
437    TEST_ASSERT(memcmp(io_seed, check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE) == 0);
438
439    memset(check_seed, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);
440
441    /* Check if platform NV write and raw read manipulate the same data */
442    TEST_ASSERT(mbedtls_nv_seed_write(io_seed, MBEDTLS_ENTROPY_BLOCK_SIZE) ==
443                MBEDTLS_ENTROPY_BLOCK_SIZE);
444    TEST_ASSERT(read_nv_seed(check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE) == 0);
445
446    TEST_ASSERT(memcmp(io_seed, check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE) == 0);
447}
448/* END_CASE */
449
450/* BEGIN_CASE depends_on:MBEDTLS_MD_LIGHT:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_PLATFORM_NV_SEED_ALT */
451void entropy_nv_seed(data_t *read_seed)
452{
453#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
454    const mbedtls_md_info_t *md_info =
455        mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
456#elif defined(MBEDTLS_ENTROPY_SHA256_ACCUMULATOR)
457    const mbedtls_md_info_t *md_info =
458        mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
459#else
460#error "Unsupported entropy accumulator"
461#endif
462    mbedtls_md_context_t accumulator;
463    mbedtls_entropy_context ctx;
464    int (*original_mbedtls_nv_seed_read)(unsigned char *buf, size_t buf_len) =
465        mbedtls_nv_seed_read;
466    int (*original_mbedtls_nv_seed_write)(unsigned char *buf, size_t buf_len) =
467        mbedtls_nv_seed_write;
468
469    unsigned char header[2];
470    unsigned char entropy[MBEDTLS_ENTROPY_BLOCK_SIZE];
471    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
472    unsigned char empty[MBEDTLS_ENTROPY_BLOCK_SIZE];
473    unsigned char check_seed[MBEDTLS_ENTROPY_BLOCK_SIZE];
474    unsigned char check_entropy[MBEDTLS_ENTROPY_BLOCK_SIZE];
475
476    memset(entropy, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);
477    memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);
478    memset(empty, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);
479    memset(check_seed, 2, MBEDTLS_ENTROPY_BLOCK_SIZE);
480    memset(check_entropy, 3, MBEDTLS_ENTROPY_BLOCK_SIZE);
481
482    // Make sure we read/write NV seed from our buffers
483    mbedtls_platform_set_nv_seed(buffer_nv_seed_read, buffer_nv_seed_write);
484
485    mbedtls_md_init(&accumulator);
486    mbedtls_entropy_init(&ctx);
487    entropy_clear_sources(&ctx);
488
489    MD_PSA_INIT();
490
491    TEST_ASSERT(mbedtls_entropy_add_source(&ctx, mbedtls_nv_seed_poll, NULL,
492                                           MBEDTLS_ENTROPY_BLOCK_SIZE,
493                                           MBEDTLS_ENTROPY_SOURCE_STRONG) == 0);
494
495    // Set the initial NV seed to read
496    TEST_ASSERT(read_seed->len >= MBEDTLS_ENTROPY_BLOCK_SIZE);
497    memcpy(buffer_seed, read_seed->x, MBEDTLS_ENTROPY_BLOCK_SIZE);
498
499    // Do an entropy run
500    TEST_ASSERT(mbedtls_entropy_func(&ctx, entropy, sizeof(entropy)) == 0);
501    // Determine what should have happened with manual entropy internal logic
502
503    // Init accumulator
504    header[1] = MBEDTLS_ENTROPY_BLOCK_SIZE;
505    TEST_ASSERT(mbedtls_md_setup(&accumulator, md_info, 0) == 0);
506
507    // First run for updating write_seed
508    header[0] = 0;
509    TEST_ASSERT(mbedtls_md_starts(&accumulator) == 0);
510    TEST_ASSERT(mbedtls_md_update(&accumulator, header, 2) == 0);
511    TEST_ASSERT(mbedtls_md_update(&accumulator,
512                                  read_seed->x, MBEDTLS_ENTROPY_BLOCK_SIZE) == 0);
513    TEST_ASSERT(mbedtls_md_finish(&accumulator, buf) == 0);
514
515    TEST_ASSERT(mbedtls_md_starts(&accumulator) == 0);
516    TEST_ASSERT(mbedtls_md_update(&accumulator,
517                                  buf, MBEDTLS_ENTROPY_BLOCK_SIZE) == 0);
518
519    TEST_ASSERT(mbedtls_md(md_info, buf, MBEDTLS_ENTROPY_BLOCK_SIZE,
520                           check_seed) == 0);
521
522    // Second run for actual entropy (triggers mbedtls_entropy_update_nv_seed)
523    header[0] = MBEDTLS_ENTROPY_SOURCE_MANUAL;
524    TEST_ASSERT(mbedtls_md_update(&accumulator, header, 2) == 0);
525    TEST_ASSERT(mbedtls_md_update(&accumulator,
526                                  empty, MBEDTLS_ENTROPY_BLOCK_SIZE) == 0);
527
528    header[0] = 0;
529    TEST_ASSERT(mbedtls_md_update(&accumulator, header, 2) == 0);
530    TEST_ASSERT(mbedtls_md_update(&accumulator,
531                                  check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE) == 0);
532    TEST_ASSERT(mbedtls_md_finish(&accumulator, buf) == 0);
533
534    TEST_ASSERT(mbedtls_md(md_info, buf, MBEDTLS_ENTROPY_BLOCK_SIZE,
535                           check_entropy) == 0);
536
537    // Check result of both NV file and entropy received with the manual calculations
538    TEST_ASSERT(memcmp(check_seed, buffer_seed, MBEDTLS_ENTROPY_BLOCK_SIZE) == 0);
539    TEST_ASSERT(memcmp(check_entropy, entropy, MBEDTLS_ENTROPY_BLOCK_SIZE) == 0);
540
541exit:
542    mbedtls_md_free(&accumulator);
543    mbedtls_entropy_free(&ctx);
544    mbedtls_nv_seed_read = original_mbedtls_nv_seed_read;
545    mbedtls_nv_seed_write = original_mbedtls_nv_seed_write;
546    MD_PSA_DONE();
547}
548/* END_CASE */
549
550/* BEGIN_CASE depends_on:ENTROPY_HAVE_STRONG:MBEDTLS_SELF_TEST */
551void entropy_selftest(int result)
552{
553    MD_PSA_INIT();
554
555    TEST_ASSERT(mbedtls_entropy_self_test(1) == result);
556
557exit:
558    MD_PSA_DONE();
559}
560/* END_CASE */
561