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