quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

entropy.c (18137B)


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