blob: 5ac65fcf5e53ba1da2f14e387fa6c1fc30d24be1 [file] [log] [blame]
Tom Rini0344c602024-10-08 13:56:50 -06001/* 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 */