Path: blob/master/thirdparty/mbedtls/library/entropy.c
9898 views
/*1* Entropy accumulator implementation2*3* Copyright The Mbed TLS Contributors4* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later5*/67#include "common.h"89#if defined(MBEDTLS_ENTROPY_C)1011#include "mbedtls/entropy.h"12#include "entropy_poll.h"13#include "mbedtls/platform_util.h"14#include "mbedtls/error.h"1516#include <string.h>1718#if defined(MBEDTLS_FS_IO)19#include <stdio.h>20#endif2122#include "mbedtls/platform.h"2324#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */2526void mbedtls_entropy_init(mbedtls_entropy_context *ctx)27{28ctx->source_count = 0;29memset(ctx->source, 0, sizeof(ctx->source));3031#if defined(MBEDTLS_THREADING_C)32mbedtls_mutex_init(&ctx->mutex);33#endif3435ctx->accumulator_started = 0;36mbedtls_md_init(&ctx->accumulator);3738/* Reminder: Update ENTROPY_HAVE_STRONG in the test files39* when adding more strong entropy sources here. */4041#if !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES)42#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)43mbedtls_entropy_add_source(ctx, mbedtls_platform_entropy_poll, NULL,44MBEDTLS_ENTROPY_MIN_PLATFORM,45MBEDTLS_ENTROPY_SOURCE_STRONG);46#endif47#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)48mbedtls_entropy_add_source(ctx, mbedtls_hardware_poll, NULL,49MBEDTLS_ENTROPY_MIN_HARDWARE,50MBEDTLS_ENTROPY_SOURCE_STRONG);51#endif52#if defined(MBEDTLS_ENTROPY_NV_SEED)53mbedtls_entropy_add_source(ctx, mbedtls_nv_seed_poll, NULL,54MBEDTLS_ENTROPY_BLOCK_SIZE,55MBEDTLS_ENTROPY_SOURCE_STRONG);56ctx->initial_entropy_run = 0;57#endif58#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */59}6061void mbedtls_entropy_free(mbedtls_entropy_context *ctx)62{63if (ctx == NULL) {64return;65}6667/* If the context was already free, don't call free() again.68* This is important for mutexes which don't allow double-free. */69if (ctx->accumulator_started == -1) {70return;71}7273#if defined(MBEDTLS_THREADING_C)74mbedtls_mutex_free(&ctx->mutex);75#endif76mbedtls_md_free(&ctx->accumulator);77#if defined(MBEDTLS_ENTROPY_NV_SEED)78ctx->initial_entropy_run = 0;79#endif80ctx->source_count = 0;81mbedtls_platform_zeroize(ctx->source, sizeof(ctx->source));82ctx->accumulator_started = -1;83}8485int mbedtls_entropy_add_source(mbedtls_entropy_context *ctx,86mbedtls_entropy_f_source_ptr f_source, void *p_source,87size_t threshold, int strong)88{89int idx, ret = 0;9091#if defined(MBEDTLS_THREADING_C)92if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {93return ret;94}95#endif9697idx = ctx->source_count;98if (idx >= MBEDTLS_ENTROPY_MAX_SOURCES) {99ret = MBEDTLS_ERR_ENTROPY_MAX_SOURCES;100goto exit;101}102103ctx->source[idx].f_source = f_source;104ctx->source[idx].p_source = p_source;105ctx->source[idx].threshold = threshold;106ctx->source[idx].strong = strong;107108ctx->source_count++;109110exit:111#if defined(MBEDTLS_THREADING_C)112if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {113return MBEDTLS_ERR_THREADING_MUTEX_ERROR;114}115#endif116117return ret;118}119120/*121* Entropy accumulator update122*/123static int entropy_update(mbedtls_entropy_context *ctx, unsigned char source_id,124const unsigned char *data, size_t len)125{126unsigned char header[2];127unsigned char tmp[MBEDTLS_ENTROPY_BLOCK_SIZE];128size_t use_len = len;129const unsigned char *p = data;130int ret = 0;131132if (use_len > MBEDTLS_ENTROPY_BLOCK_SIZE) {133if ((ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD),134data, len, tmp)) != 0) {135goto cleanup;136}137p = tmp;138use_len = MBEDTLS_ENTROPY_BLOCK_SIZE;139}140141header[0] = source_id;142header[1] = use_len & 0xFF;143144/*145* Start the accumulator if this has not already happened. Note that146* it is sufficient to start the accumulator here only because all calls to147* gather entropy eventually execute this code.148*/149if (ctx->accumulator_started == 0) {150ret = mbedtls_md_setup(&ctx->accumulator,151mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), 0);152if (ret != 0) {153goto cleanup;154}155ret = mbedtls_md_starts(&ctx->accumulator);156if (ret != 0) {157goto cleanup;158}159ctx->accumulator_started = 1;160}161if ((ret = mbedtls_md_update(&ctx->accumulator, header, 2)) != 0) {162goto cleanup;163}164ret = mbedtls_md_update(&ctx->accumulator, p, use_len);165166cleanup:167mbedtls_platform_zeroize(tmp, sizeof(tmp));168169return ret;170}171172int mbedtls_entropy_update_manual(mbedtls_entropy_context *ctx,173const unsigned char *data, size_t len)174{175int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;176177#if defined(MBEDTLS_THREADING_C)178if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {179return ret;180}181#endif182183ret = entropy_update(ctx, MBEDTLS_ENTROPY_SOURCE_MANUAL, data, len);184185#if defined(MBEDTLS_THREADING_C)186if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {187return MBEDTLS_ERR_THREADING_MUTEX_ERROR;188}189#endif190191return ret;192}193194/*195* Run through the different sources to add entropy to our accumulator196*/197static int entropy_gather_internal(mbedtls_entropy_context *ctx)198{199int ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;200int i;201int have_one_strong = 0;202unsigned char buf[MBEDTLS_ENTROPY_MAX_GATHER];203size_t olen;204205if (ctx->source_count == 0) {206return MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED;207}208209/*210* Run through our entropy sources211*/212for (i = 0; i < ctx->source_count; i++) {213if (ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG) {214have_one_strong = 1;215}216217olen = 0;218if ((ret = ctx->source[i].f_source(ctx->source[i].p_source,219buf, MBEDTLS_ENTROPY_MAX_GATHER, &olen)) != 0) {220goto cleanup;221}222223/*224* Add if we actually gathered something225*/226if (olen > 0) {227if ((ret = entropy_update(ctx, (unsigned char) i,228buf, olen)) != 0) {229return ret;230}231ctx->source[i].size += olen;232}233}234235if (have_one_strong == 0) {236ret = MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE;237}238239cleanup:240mbedtls_platform_zeroize(buf, sizeof(buf));241242return ret;243}244245/*246* Thread-safe wrapper for entropy_gather_internal()247*/248int mbedtls_entropy_gather(mbedtls_entropy_context *ctx)249{250int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;251252#if defined(MBEDTLS_THREADING_C)253if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {254return ret;255}256#endif257258ret = entropy_gather_internal(ctx);259260#if defined(MBEDTLS_THREADING_C)261if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {262return MBEDTLS_ERR_THREADING_MUTEX_ERROR;263}264#endif265266return ret;267}268269int mbedtls_entropy_func(void *data, unsigned char *output, size_t len)270{271int ret, count = 0, i, thresholds_reached;272size_t strong_size;273mbedtls_entropy_context *ctx = (mbedtls_entropy_context *) data;274unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];275276if (len > MBEDTLS_ENTROPY_BLOCK_SIZE) {277return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;278}279280#if defined(MBEDTLS_ENTROPY_NV_SEED)281/* Update the NV entropy seed before generating any entropy for outside282* use.283*/284if (ctx->initial_entropy_run == 0) {285ctx->initial_entropy_run = 1;286if ((ret = mbedtls_entropy_update_nv_seed(ctx)) != 0) {287return ret;288}289}290#endif291292#if defined(MBEDTLS_THREADING_C)293if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {294return ret;295}296#endif297298/*299* Always gather extra entropy before a call300*/301do {302if (count++ > ENTROPY_MAX_LOOP) {303ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;304goto exit;305}306307if ((ret = entropy_gather_internal(ctx)) != 0) {308goto exit;309}310311thresholds_reached = 1;312strong_size = 0;313for (i = 0; i < ctx->source_count; i++) {314if (ctx->source[i].size < ctx->source[i].threshold) {315thresholds_reached = 0;316}317if (ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG) {318strong_size += ctx->source[i].size;319}320}321} while (!thresholds_reached || strong_size < MBEDTLS_ENTROPY_BLOCK_SIZE);322323memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);324325/*326* Note that at this stage it is assumed that the accumulator was started327* in a previous call to entropy_update(). If this is not guaranteed, the328* code below will fail.329*/330if ((ret = mbedtls_md_finish(&ctx->accumulator, buf)) != 0) {331goto exit;332}333334/*335* Reset accumulator and counters and recycle existing entropy336*/337mbedtls_md_free(&ctx->accumulator);338mbedtls_md_init(&ctx->accumulator);339ret = mbedtls_md_setup(&ctx->accumulator,340mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), 0);341if (ret != 0) {342goto exit;343}344ret = mbedtls_md_starts(&ctx->accumulator);345if (ret != 0) {346goto exit;347}348if ((ret = mbedtls_md_update(&ctx->accumulator, buf,349MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) {350goto exit;351}352353/*354* Perform second hashing on entropy355*/356if ((ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD),357buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf)) != 0) {358goto exit;359}360361for (i = 0; i < ctx->source_count; i++) {362ctx->source[i].size = 0;363}364365memcpy(output, buf, len);366367ret = 0;368369exit:370mbedtls_platform_zeroize(buf, sizeof(buf));371372#if defined(MBEDTLS_THREADING_C)373if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {374return MBEDTLS_ERR_THREADING_MUTEX_ERROR;375}376#endif377378return ret;379}380381#if defined(MBEDTLS_ENTROPY_NV_SEED)382int mbedtls_entropy_update_nv_seed(mbedtls_entropy_context *ctx)383{384int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;385unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];386387/* Read new seed and write it to NV */388if ((ret = mbedtls_entropy_func(ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) {389return ret;390}391392if (mbedtls_nv_seed_write(buf, MBEDTLS_ENTROPY_BLOCK_SIZE) < 0) {393return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;394}395396/* Manually update the remaining stream with a separator value to diverge */397memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);398ret = mbedtls_entropy_update_manual(ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE);399400return ret;401}402#endif /* MBEDTLS_ENTROPY_NV_SEED */403404#if defined(MBEDTLS_FS_IO)405int mbedtls_entropy_write_seed_file(mbedtls_entropy_context *ctx, const char *path)406{407int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;408FILE *f = NULL;409unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];410411if ((ret = mbedtls_entropy_func(ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) {412ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;413goto exit;414}415416if ((f = fopen(path, "wb")) == NULL) {417ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;418goto exit;419}420421/* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */422mbedtls_setbuf(f, NULL);423424if (fwrite(buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f) != MBEDTLS_ENTROPY_BLOCK_SIZE) {425ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;426goto exit;427}428429ret = 0;430431exit:432mbedtls_platform_zeroize(buf, sizeof(buf));433434if (f != NULL) {435fclose(f);436}437438return ret;439}440441int mbedtls_entropy_update_seed_file(mbedtls_entropy_context *ctx, const char *path)442{443int ret = 0;444FILE *f;445size_t n;446unsigned char buf[MBEDTLS_ENTROPY_MAX_SEED_SIZE];447448if ((f = fopen(path, "rb")) == NULL) {449return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;450}451452/* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */453mbedtls_setbuf(f, NULL);454455fseek(f, 0, SEEK_END);456n = (size_t) ftell(f);457fseek(f, 0, SEEK_SET);458459if (n > MBEDTLS_ENTROPY_MAX_SEED_SIZE) {460n = MBEDTLS_ENTROPY_MAX_SEED_SIZE;461}462463if (fread(buf, 1, n, f) != n) {464ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;465} else {466ret = mbedtls_entropy_update_manual(ctx, buf, n);467}468469fclose(f);470471mbedtls_platform_zeroize(buf, sizeof(buf));472473if (ret != 0) {474return ret;475}476477return mbedtls_entropy_write_seed_file(ctx, path);478}479#endif /* MBEDTLS_FS_IO */480481#if defined(MBEDTLS_SELF_TEST)482/*483* Dummy source function484*/485static int entropy_dummy_source(void *data, unsigned char *output,486size_t len, size_t *olen)487{488((void) data);489490memset(output, 0x2a, len);491*olen = len;492493return 0;494}495496#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)497498static int mbedtls_entropy_source_self_test_gather(unsigned char *buf, size_t buf_len)499{500int ret = 0;501size_t entropy_len = 0;502size_t olen = 0;503size_t attempts = buf_len;504505while (attempts > 0 && entropy_len < buf_len) {506if ((ret = mbedtls_hardware_poll(NULL, buf + entropy_len,507buf_len - entropy_len, &olen)) != 0) {508return ret;509}510511entropy_len += olen;512attempts--;513}514515if (entropy_len < buf_len) {516ret = 1;517}518519return ret;520}521522523static int mbedtls_entropy_source_self_test_check_bits(const unsigned char *buf,524size_t buf_len)525{526unsigned char set = 0xFF;527unsigned char unset = 0x00;528size_t i;529530for (i = 0; i < buf_len; i++) {531set &= buf[i];532unset |= buf[i];533}534535return set == 0xFF || unset == 0x00;536}537538/*539* A test to ensure that the entropy sources are functioning correctly540* and there is no obvious failure. The test performs the following checks:541* - The entropy source is not providing only 0s (all bits unset) or 1s (all542* bits set).543* - The entropy source is not providing values in a pattern. Because the544* hardware could be providing data in an arbitrary length, this check polls545* the hardware entropy source twice and compares the result to ensure they546* are not equal.547* - The error code returned by the entropy source is not an error.548*/549int mbedtls_entropy_source_self_test(int verbose)550{551int ret = 0;552unsigned char buf0[2 * sizeof(unsigned long long int)];553unsigned char buf1[2 * sizeof(unsigned long long int)];554555if (verbose != 0) {556mbedtls_printf(" ENTROPY_BIAS test: ");557}558559memset(buf0, 0x00, sizeof(buf0));560memset(buf1, 0x00, sizeof(buf1));561562if ((ret = mbedtls_entropy_source_self_test_gather(buf0, sizeof(buf0))) != 0) {563goto cleanup;564}565if ((ret = mbedtls_entropy_source_self_test_gather(buf1, sizeof(buf1))) != 0) {566goto cleanup;567}568569/* Make sure that the returned values are not all 0 or 1 */570if ((ret = mbedtls_entropy_source_self_test_check_bits(buf0, sizeof(buf0))) != 0) {571goto cleanup;572}573if ((ret = mbedtls_entropy_source_self_test_check_bits(buf1, sizeof(buf1))) != 0) {574goto cleanup;575}576577/* Make sure that the entropy source is not returning values in a578* pattern */579ret = memcmp(buf0, buf1, sizeof(buf0)) == 0;580581cleanup:582if (verbose != 0) {583if (ret != 0) {584mbedtls_printf("failed\n");585} else {586mbedtls_printf("passed\n");587}588589mbedtls_printf("\n");590}591592return ret != 0;593}594595#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */596597/*598* The actual entropy quality is hard to test, but we can at least599* test that the functions don't cause errors and write the correct600* amount of data to buffers.601*/602int mbedtls_entropy_self_test(int verbose)603{604int ret = 1;605mbedtls_entropy_context ctx;606unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 };607unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 };608size_t i, j;609610if (verbose != 0) {611mbedtls_printf(" ENTROPY test: ");612}613614mbedtls_entropy_init(&ctx);615616/* First do a gather to make sure we have default sources */617if ((ret = mbedtls_entropy_gather(&ctx)) != 0) {618goto cleanup;619}620621ret = mbedtls_entropy_add_source(&ctx, entropy_dummy_source, NULL, 16,622MBEDTLS_ENTROPY_SOURCE_WEAK);623if (ret != 0) {624goto cleanup;625}626627if ((ret = mbedtls_entropy_update_manual(&ctx, buf, sizeof(buf))) != 0) {628goto cleanup;629}630631/*632* To test that mbedtls_entropy_func writes correct number of bytes:633* - use the whole buffer and rely on ASan to detect overruns634* - collect entropy 8 times and OR the result in an accumulator:635* any byte should then be 0 with probably 2^(-64), so requiring636* each of the 32 or 64 bytes to be non-zero has a false failure rate637* of at most 2^(-58) which is acceptable.638*/639for (i = 0; i < 8; i++) {640if ((ret = mbedtls_entropy_func(&ctx, buf, sizeof(buf))) != 0) {641goto cleanup;642}643644for (j = 0; j < sizeof(buf); j++) {645acc[j] |= buf[j];646}647}648649for (j = 0; j < sizeof(buf); j++) {650if (acc[j] == 0) {651ret = 1;652goto cleanup;653}654}655656#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)657if ((ret = mbedtls_entropy_source_self_test(0)) != 0) {658goto cleanup;659}660#endif661662cleanup:663mbedtls_entropy_free(&ctx);664665if (verbose != 0) {666if (ret != 0) {667mbedtls_printf("failed\n");668} else {669mbedtls_printf("passed\n");670}671672mbedtls_printf("\n");673}674675return ret != 0;676}677#endif /* MBEDTLS_SELF_TEST */678679#endif /* MBEDTLS_ENTROPY_C */680681682