1/* 2 * Entropy accumulator implementation 3 * 4 * Copyright The Mbed TLS Contributors 5 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6 */ 7 8#include "common.h" 9 10#if defined(MBEDTLS_ENTROPY_C) 11 12#include "mbedtls/entropy.h" 13#include "entropy_poll.h" 14#include "mbedtls/platform_util.h" 15#include "mbedtls/error.h" 16 17#include <string.h> 18 19#if defined(MBEDTLS_FS_IO) 20#include <stdio.h> 21#endif 22 23#include "mbedtls/platform.h" 24 25#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */ 26 27void mbedtls_entropy_init(mbedtls_entropy_context *ctx) 28{ 29 ctx->source_count = 0; 30 memset(ctx->source, 0, sizeof(ctx->source)); 31 32#if defined(MBEDTLS_THREADING_C) 33 mbedtls_mutex_init(&ctx->mutex); 34#endif 35 36 ctx->accumulator_started = 0; 37 mbedtls_md_init(&ctx->accumulator); 38 39 /* Reminder: Update ENTROPY_HAVE_STRONG in the test files 40 * when adding more strong entropy sources here. */ 41 42#if !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) 43#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) 44 mbedtls_entropy_add_source(ctx, mbedtls_platform_entropy_poll, NULL, 45 MBEDTLS_ENTROPY_MIN_PLATFORM, 46 MBEDTLS_ENTROPY_SOURCE_STRONG); 47#endif 48#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) 49 mbedtls_entropy_add_source(ctx, mbedtls_hardware_poll, NULL, 50 MBEDTLS_ENTROPY_MIN_HARDWARE, 51 MBEDTLS_ENTROPY_SOURCE_STRONG); 52#endif 53#if defined(MBEDTLS_ENTROPY_NV_SEED) 54 mbedtls_entropy_add_source(ctx, mbedtls_nv_seed_poll, NULL, 55 MBEDTLS_ENTROPY_BLOCK_SIZE, 56 MBEDTLS_ENTROPY_SOURCE_STRONG); 57 ctx->initial_entropy_run = 0; 58#endif 59#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */ 60} 61 62void mbedtls_entropy_free(mbedtls_entropy_context *ctx) 63{ 64 /* If the context was already free, don't call free() again. 65 * This is important for mutexes which don't allow double-free. */ 66 if (ctx->accumulator_started == -1) { 67 return; 68 } 69 70#if defined(MBEDTLS_THREADING_C) 71 mbedtls_mutex_free(&ctx->mutex); 72#endif 73 mbedtls_md_free(&ctx->accumulator); 74#if defined(MBEDTLS_ENTROPY_NV_SEED) 75 ctx->initial_entropy_run = 0; 76#endif 77 ctx->source_count = 0; 78 mbedtls_platform_zeroize(ctx->source, sizeof(ctx->source)); 79 ctx->accumulator_started = -1; 80} 81 82int mbedtls_entropy_add_source(mbedtls_entropy_context *ctx, 83 mbedtls_entropy_f_source_ptr f_source, void *p_source, 84 size_t threshold, int strong) 85{ 86 int idx, ret = 0; 87 88#if defined(MBEDTLS_THREADING_C) 89 if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { 90 return ret; 91 } 92#endif 93 94 idx = ctx->source_count; 95 if (idx >= MBEDTLS_ENTROPY_MAX_SOURCES) { 96 ret = MBEDTLS_ERR_ENTROPY_MAX_SOURCES; 97 goto exit; 98 } 99 100 ctx->source[idx].f_source = f_source; 101 ctx->source[idx].p_source = p_source; 102 ctx->source[idx].threshold = threshold; 103 ctx->source[idx].strong = strong; 104 105 ctx->source_count++; 106 107exit: 108#if defined(MBEDTLS_THREADING_C) 109 if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { 110 return MBEDTLS_ERR_THREADING_MUTEX_ERROR; 111 } 112#endif 113 114 return ret; 115} 116 117/* 118 * Entropy accumulator update 119 */ 120static int entropy_update(mbedtls_entropy_context *ctx, unsigned char source_id, 121 const unsigned char *data, size_t len) 122{ 123 unsigned char header[2]; 124 unsigned char tmp[MBEDTLS_ENTROPY_BLOCK_SIZE]; 125 size_t use_len = len; 126 const unsigned char *p = data; 127 int ret = 0; 128 129 if (use_len > MBEDTLS_ENTROPY_BLOCK_SIZE) { 130 if ((ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), 131 data, len, tmp)) != 0) { 132 goto cleanup; 133 } 134 p = tmp; 135 use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; 136 } 137 138 header[0] = source_id; 139 header[1] = use_len & 0xFF; 140 141 /* 142 * Start the accumulator if this has not already happened. Note that 143 * it is sufficient to start the accumulator here only because all calls to 144 * gather entropy eventually execute this code. 145 */ 146 if (ctx->accumulator_started == 0) { 147 ret = mbedtls_md_setup(&ctx->accumulator, 148 mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), 0); 149 if (ret != 0) { 150 goto cleanup; 151 } 152 ret = mbedtls_md_starts(&ctx->accumulator); 153 if (ret != 0) { 154 goto cleanup; 155 } 156 ctx->accumulator_started = 1; 157 } 158 if ((ret = mbedtls_md_update(&ctx->accumulator, header, 2)) != 0) { 159 goto cleanup; 160 } 161 ret = mbedtls_md_update(&ctx->accumulator, p, use_len); 162 163cleanup: 164 mbedtls_platform_zeroize(tmp, sizeof(tmp)); 165 166 return ret; 167} 168 169int mbedtls_entropy_update_manual(mbedtls_entropy_context *ctx, 170 const unsigned char *data, size_t len) 171{ 172 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 173 174#if defined(MBEDTLS_THREADING_C) 175 if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { 176 return ret; 177 } 178#endif 179 180 ret = entropy_update(ctx, MBEDTLS_ENTROPY_SOURCE_MANUAL, data, len); 181 182#if defined(MBEDTLS_THREADING_C) 183 if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { 184 return MBEDTLS_ERR_THREADING_MUTEX_ERROR; 185 } 186#endif 187 188 return ret; 189} 190 191/* 192 * Run through the different sources to add entropy to our accumulator 193 */ 194static int entropy_gather_internal(mbedtls_entropy_context *ctx) 195{ 196 int ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 197 int i; 198 int have_one_strong = 0; 199 unsigned char buf[MBEDTLS_ENTROPY_MAX_GATHER]; 200 size_t olen; 201 202 if (ctx->source_count == 0) { 203 return MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED; 204 } 205 206 /* 207 * Run through our entropy sources 208 */ 209 for (i = 0; i < ctx->source_count; i++) { 210 if (ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG) { 211 have_one_strong = 1; 212 } 213 214 olen = 0; 215 if ((ret = ctx->source[i].f_source(ctx->source[i].p_source, 216 buf, MBEDTLS_ENTROPY_MAX_GATHER, &olen)) != 0) { 217 goto cleanup; 218 } 219 220 /* 221 * Add if we actually gathered something 222 */ 223 if (olen > 0) { 224 if ((ret = entropy_update(ctx, (unsigned char) i, 225 buf, olen)) != 0) { 226 return ret; 227 } 228 ctx->source[i].size += olen; 229 } 230 } 231 232 if (have_one_strong == 0) { 233 ret = MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE; 234 } 235 236cleanup: 237 mbedtls_platform_zeroize(buf, sizeof(buf)); 238 239 return ret; 240} 241 242/* 243 * Thread-safe wrapper for entropy_gather_internal() 244 */ 245int mbedtls_entropy_gather(mbedtls_entropy_context *ctx) 246{ 247 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 248 249#if defined(MBEDTLS_THREADING_C) 250 if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { 251 return ret; 252 } 253#endif 254 255 ret = entropy_gather_internal(ctx); 256 257#if defined(MBEDTLS_THREADING_C) 258 if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { 259 return MBEDTLS_ERR_THREADING_MUTEX_ERROR; 260 } 261#endif 262 263 return ret; 264} 265 266int mbedtls_entropy_func(void *data, unsigned char *output, size_t len) 267{ 268 int ret, count = 0, i, thresholds_reached; 269 size_t strong_size; 270 mbedtls_entropy_context *ctx = (mbedtls_entropy_context *) data; 271 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; 272 273 if (len > MBEDTLS_ENTROPY_BLOCK_SIZE) { 274 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 275 } 276 277#if defined(MBEDTLS_ENTROPY_NV_SEED) 278 /* Update the NV entropy seed before generating any entropy for outside 279 * use. 280 */ 281 if (ctx->initial_entropy_run == 0) { 282 ctx->initial_entropy_run = 1; 283 if ((ret = mbedtls_entropy_update_nv_seed(ctx)) != 0) { 284 return ret; 285 } 286 } 287#endif 288 289#if defined(MBEDTLS_THREADING_C) 290 if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) { 291 return ret; 292 } 293#endif 294 295 /* 296 * Always gather extra entropy before a call 297 */ 298 do { 299 if (count++ > ENTROPY_MAX_LOOP) { 300 ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 301 goto exit; 302 } 303 304 if ((ret = entropy_gather_internal(ctx)) != 0) { 305 goto exit; 306 } 307 308 thresholds_reached = 1; 309 strong_size = 0; 310 for (i = 0; i < ctx->source_count; i++) { 311 if (ctx->source[i].size < ctx->source[i].threshold) { 312 thresholds_reached = 0; 313 } 314 if (ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG) { 315 strong_size += ctx->source[i].size; 316 } 317 } 318 } while (!thresholds_reached || strong_size < MBEDTLS_ENTROPY_BLOCK_SIZE); 319 320 memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE); 321 322 /* 323 * Note that at this stage it is assumed that the accumulator was started 324 * in a previous call to entropy_update(). If this is not guaranteed, the 325 * code below will fail. 326 */ 327 if ((ret = mbedtls_md_finish(&ctx->accumulator, buf)) != 0) { 328 goto exit; 329 } 330 331 /* 332 * Reset accumulator and counters and recycle existing entropy 333 */ 334 mbedtls_md_free(&ctx->accumulator); 335 mbedtls_md_init(&ctx->accumulator); 336 ret = mbedtls_md_setup(&ctx->accumulator, 337 mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), 0); 338 if (ret != 0) { 339 goto exit; 340 } 341 ret = mbedtls_md_starts(&ctx->accumulator); 342 if (ret != 0) { 343 goto exit; 344 } 345 if ((ret = mbedtls_md_update(&ctx->accumulator, buf, 346 MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) { 347 goto exit; 348 } 349 350 /* 351 * Perform second hashing on entropy 352 */ 353 if ((ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), 354 buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf)) != 0) { 355 goto exit; 356 } 357 358 for (i = 0; i < ctx->source_count; i++) { 359 ctx->source[i].size = 0; 360 } 361 362 memcpy(output, buf, len); 363 364 ret = 0; 365 366exit: 367 mbedtls_platform_zeroize(buf, sizeof(buf)); 368 369#if defined(MBEDTLS_THREADING_C) 370 if (mbedtls_mutex_unlock(&ctx->mutex) != 0) { 371 return MBEDTLS_ERR_THREADING_MUTEX_ERROR; 372 } 373#endif 374 375 return ret; 376} 377 378#if defined(MBEDTLS_ENTROPY_NV_SEED) 379int mbedtls_entropy_update_nv_seed(mbedtls_entropy_context *ctx) 380{ 381 int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; 382 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; 383 384 /* Read new seed and write it to NV */ 385 if ((ret = mbedtls_entropy_func(ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) { 386 return ret; 387 } 388 389 if (mbedtls_nv_seed_write(buf, MBEDTLS_ENTROPY_BLOCK_SIZE) < 0) { 390 return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; 391 } 392 393 /* Manually update the remaining stream with a separator value to diverge */ 394 memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE); 395 ret = mbedtls_entropy_update_manual(ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE); 396 397 return ret; 398} 399#endif /* MBEDTLS_ENTROPY_NV_SEED */ 400 401#if defined(MBEDTLS_FS_IO) 402int mbedtls_entropy_write_seed_file(mbedtls_entropy_context *ctx, const char *path) 403{ 404 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 405 FILE *f = NULL; 406 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; 407 408 if ((ret = mbedtls_entropy_func(ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) { 409 ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 410 goto exit; 411 } 412 413 if ((f = fopen(path, "wb")) == NULL) { 414 ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; 415 goto exit; 416 } 417 418 /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ 419 mbedtls_setbuf(f, NULL); 420 421 if (fwrite(buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f) != MBEDTLS_ENTROPY_BLOCK_SIZE) { 422 ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; 423 goto exit; 424 } 425 426 ret = 0; 427 428exit: 429 mbedtls_platform_zeroize(buf, sizeof(buf)); 430 431 if (f != NULL) { 432 fclose(f); 433 } 434 435 return ret; 436} 437 438int mbedtls_entropy_update_seed_file(mbedtls_entropy_context *ctx, const char *path) 439{ 440 int ret = 0; 441 FILE *f; 442 size_t n; 443 unsigned char buf[MBEDTLS_ENTROPY_MAX_SEED_SIZE]; 444 445 if ((f = fopen(path, "rb")) == NULL) { 446 return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; 447 } 448 449 /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ 450 mbedtls_setbuf(f, NULL); 451 452 fseek(f, 0, SEEK_END); 453 n = (size_t) ftell(f); 454 fseek(f, 0, SEEK_SET); 455 456 if (n > MBEDTLS_ENTROPY_MAX_SEED_SIZE) { 457 n = MBEDTLS_ENTROPY_MAX_SEED_SIZE; 458 } 459 460 if (fread(buf, 1, n, f) != n) { 461 ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; 462 } else { 463 ret = mbedtls_entropy_update_manual(ctx, buf, n); 464 } 465 466 fclose(f); 467 468 mbedtls_platform_zeroize(buf, sizeof(buf)); 469 470 if (ret != 0) { 471 return ret; 472 } 473 474 return mbedtls_entropy_write_seed_file(ctx, path); 475} 476#endif /* MBEDTLS_FS_IO */ 477 478#if defined(MBEDTLS_SELF_TEST) 479/* 480 * Dummy source function 481 */ 482static int entropy_dummy_source(void *data, unsigned char *output, 483 size_t len, size_t *olen) 484{ 485 ((void) data); 486 487 memset(output, 0x2a, len); 488 *olen = len; 489 490 return 0; 491} 492 493#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) 494 495static int mbedtls_entropy_source_self_test_gather(unsigned char *buf, size_t buf_len) 496{ 497 int ret = 0; 498 size_t entropy_len = 0; 499 size_t olen = 0; 500 size_t attempts = buf_len; 501 502 while (attempts > 0 && entropy_len < buf_len) { 503 if ((ret = mbedtls_hardware_poll(NULL, buf + entropy_len, 504 buf_len - entropy_len, &olen)) != 0) { 505 return ret; 506 } 507 508 entropy_len += olen; 509 attempts--; 510 } 511 512 if (entropy_len < buf_len) { 513 ret = 1; 514 } 515 516 return ret; 517} 518 519 520static int mbedtls_entropy_source_self_test_check_bits(const unsigned char *buf, 521 size_t buf_len) 522{ 523 unsigned char set = 0xFF; 524 unsigned char unset = 0x00; 525 size_t i; 526 527 for (i = 0; i < buf_len; i++) { 528 set &= buf[i]; 529 unset |= buf[i]; 530 } 531 532 return set == 0xFF || unset == 0x00; 533} 534 535/* 536 * A test to ensure that the entropy sources are functioning correctly 537 * and there is no obvious failure. The test performs the following checks: 538 * - The entropy source is not providing only 0s (all bits unset) or 1s (all 539 * bits set). 540 * - The entropy source is not providing values in a pattern. Because the 541 * hardware could be providing data in an arbitrary length, this check polls 542 * the hardware entropy source twice and compares the result to ensure they 543 * are not equal. 544 * - The error code returned by the entropy source is not an error. 545 */ 546int mbedtls_entropy_source_self_test(int verbose) 547{ 548 int ret = 0; 549 unsigned char buf0[2 * sizeof(unsigned long long int)]; 550 unsigned char buf1[2 * sizeof(unsigned long long int)]; 551 552 if (verbose != 0) { 553 mbedtls_printf(" ENTROPY_BIAS test: "); 554 } 555 556 memset(buf0, 0x00, sizeof(buf0)); 557 memset(buf1, 0x00, sizeof(buf1)); 558 559 if ((ret = mbedtls_entropy_source_self_test_gather(buf0, sizeof(buf0))) != 0) { 560 goto cleanup; 561 } 562 if ((ret = mbedtls_entropy_source_self_test_gather(buf1, sizeof(buf1))) != 0) { 563 goto cleanup; 564 } 565 566 /* Make sure that the returned values are not all 0 or 1 */ 567 if ((ret = mbedtls_entropy_source_self_test_check_bits(buf0, sizeof(buf0))) != 0) { 568 goto cleanup; 569 } 570 if ((ret = mbedtls_entropy_source_self_test_check_bits(buf1, sizeof(buf1))) != 0) { 571 goto cleanup; 572 } 573 574 /* Make sure that the entropy source is not returning values in a 575 * pattern */ 576 ret = memcmp(buf0, buf1, sizeof(buf0)) == 0; 577 578cleanup: 579 if (verbose != 0) { 580 if (ret != 0) { 581 mbedtls_printf("failed\n"); 582 } else { 583 mbedtls_printf("passed\n"); 584 } 585 586 mbedtls_printf("\n"); 587 } 588 589 return ret != 0; 590} 591 592#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ 593 594/* 595 * The actual entropy quality is hard to test, but we can at least 596 * test that the functions don't cause errors and write the correct 597 * amount of data to buffers. 598 */ 599int mbedtls_entropy_self_test(int verbose) 600{ 601 int ret = 1; 602 mbedtls_entropy_context ctx; 603 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; 604 unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; 605 size_t i, j; 606 607 if (verbose != 0) { 608 mbedtls_printf(" ENTROPY test: "); 609 } 610 611 mbedtls_entropy_init(&ctx); 612 613 /* First do a gather to make sure we have default sources */ 614 if ((ret = mbedtls_entropy_gather(&ctx)) != 0) { 615 goto cleanup; 616 } 617 618 ret = mbedtls_entropy_add_source(&ctx, entropy_dummy_source, NULL, 16, 619 MBEDTLS_ENTROPY_SOURCE_WEAK); 620 if (ret != 0) { 621 goto cleanup; 622 } 623 624 if ((ret = mbedtls_entropy_update_manual(&ctx, buf, sizeof(buf))) != 0) { 625 goto cleanup; 626 } 627 628 /* 629 * To test that mbedtls_entropy_func writes correct number of bytes: 630 * - use the whole buffer and rely on ASan to detect overruns 631 * - collect entropy 8 times and OR the result in an accumulator: 632 * any byte should then be 0 with probably 2^(-64), so requiring 633 * each of the 32 or 64 bytes to be non-zero has a false failure rate 634 * of at most 2^(-58) which is acceptable. 635 */ 636 for (i = 0; i < 8; i++) { 637 if ((ret = mbedtls_entropy_func(&ctx, buf, sizeof(buf))) != 0) { 638 goto cleanup; 639 } 640 641 for (j = 0; j < sizeof(buf); j++) { 642 acc[j] |= buf[j]; 643 } 644 } 645 646 for (j = 0; j < sizeof(buf); j++) { 647 if (acc[j] == 0) { 648 ret = 1; 649 goto cleanup; 650 } 651 } 652 653#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) 654 if ((ret = mbedtls_entropy_source_self_test(0)) != 0) { 655 goto cleanup; 656 } 657#endif 658 659cleanup: 660 mbedtls_entropy_free(&ctx); 661 662 if (verbose != 0) { 663 if (ret != 0) { 664 mbedtls_printf("failed\n"); 665 } else { 666 mbedtls_printf("passed\n"); 667 } 668 669 mbedtls_printf("\n"); 670 } 671 672 return ret != 0; 673} 674#endif /* MBEDTLS_SELF_TEST */ 675 676#endif /* MBEDTLS_ENTROPY_C */ 677