diff --git a/library/entropy.c b/library/entropy.c index d7091cbf7..a40ce80cd 100644 --- a/library/entropy.c +++ b/library/entropy.c @@ -327,7 +327,8 @@ int mbedtls_entropy_gather( mbedtls_entropy_context *ctx ) int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ) { - int ret, count = 0, i, done; + int ret, count = 0, i, thresholds_reached; + size_t strong_size; mbedtls_entropy_context *ctx = (mbedtls_entropy_context *) data; unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; @@ -365,12 +366,17 @@ int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ) if( ( ret = entropy_gather_internal( ctx ) ) != 0 ) goto exit; - done = 1; + thresholds_reached = 1; + strong_size = 0; for( i = 0; i < ctx->source_count; i++ ) + { if( ctx->source[i].size < ctx->source[i].threshold ) - done = 0; + thresholds_reached = 0; + if( ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG ) + strong_size += ctx->source[i].size; + } } - while( ! done ); + while( ! thresholds_reached || strong_size < MBEDTLS_ENTROPY_BLOCK_SIZE ); memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); diff --git a/tests/suites/test_suite_entropy.data b/tests/suites/test_suite_entropy.data index 11ced64b3..b2d20b472 100644 --- a/tests/suites/test_suite_entropy.data +++ b/tests/suites/test_suite_entropy.data @@ -1,45 +1,66 @@ Create NV seed_file nv_seed_file_create: -Entropy write/update seed file [#1] +Entropy write/update seed file: good entropy_seed_file:"data_files/entropy_seed":0 -Entropy write/update seed file [#2] +Entropy write/update seed file: nonexistent entropy_seed_file:"no_such_dir/file":MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR +Entropy no sources +entropy_no_sources: + Entropy too many sources entropy_too_many_sources: -Entropy output length #1 +Entropy output length: 0 entropy_func_len:0:0 -Entropy output length #2 +Entropy output length: 1 entropy_func_len:1:0 -Entropy output length #3 +Entropy output length: 2 entropy_func_len:2:0 -Entropy output length #4 +Entropy output length: 31 entropy_func_len:31:0 -Entropy output length #5 +Entropy output length: 65 > BLOCK_SIZE entropy_func_len:65:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED Entropy failing source entropy_source_fail:"data_files/entropy_seed" -Entropy threshold #1 +Entropy threshold: 16=2*8 entropy_threshold:16:2:8 -Entropy threshold #2 +Entropy threshold: 32=1*32 entropy_threshold:32:1:32 -Entropy threshold #3 +Entropy threshold: 0* never reaches the threshold entropy_threshold:16:0:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED -Entropy threshold #4 +Entropy threshold: 1024 never reached entropy_threshold:1024:1:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED +Entropy calls: no strong +entropy_calls:MBEDTLS_ENTROPY_SOURCE_WEAK:MBEDTLS_ENTROPY_SOURCE_WEAK:1:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE + +Entropy calls: 1 strong, 1*BLOCK_SIZE +entropy_calls:MBEDTLS_ENTROPY_SOURCE_STRONG:MBEDTLS_ENTROPY_SOURCE_WEAK:1:MBEDTLS_ENTROPY_BLOCK_SIZE:1 + +Entropy calls: 1 strong, 2*(BLOCK_SIZE/2) +entropy_calls:MBEDTLS_ENTROPY_SOURCE_STRONG:MBEDTLS_ENTROPY_SOURCE_WEAK:1:(MBEDTLS_ENTROPY_BLOCK_SIZE+1)/2:2 + +Entropy calls: 1 strong, BLOCK_SIZE*1 +entropy_calls:MBEDTLS_ENTROPY_SOURCE_STRONG:MBEDTLS_ENTROPY_SOURCE_WEAK:1:1:MBEDTLS_ENTROPY_BLOCK_SIZE + +Entropy calls: 1 strong, 2*BLOCK_SIZE to reach threshold +entropy_calls:MBEDTLS_ENTROPY_SOURCE_STRONG:MBEDTLS_ENTROPY_SOURCE_WEAK:MBEDTLS_ENTROPY_BLOCK_SIZE+1:MBEDTLS_ENTROPY_BLOCK_SIZE:2 + +Entropy calls: 2 strong, BLOCK_SIZE/2 each +entropy_calls:MBEDTLS_ENTROPY_SOURCE_STRONG:MBEDTLS_ENTROPY_SOURCE_WEAK:(MBEDTLS_ENTROPY_BLOCK_SIZE+1)/2:(MBEDTLS_ENTROPY_BLOCK_SIZE+1)/2:2 + Check NV seed standard IO entropy_nv_seed_std_io: diff --git a/tests/suites/test_suite_entropy.function b/tests/suites/test_suite_entropy.function index 0d86eadbe..9f10a9043 100644 --- a/tests/suites/test_suite_entropy.function +++ b/tests/suites/test_suite_entropy.function @@ -3,10 +3,19 @@ #include "mbedtls/entropy_poll.h" #include "string.h" -/* - * Number of calls made to entropy_dummy_source() - */ -static size_t entropy_dummy_calls; +typedef enum +{ + DUMMY_CONSTANT_LENGTH, /* Output context->length bytes */ + DUMMY_REQUESTED_LENGTH, /* Output whatever length was requested */ + DUMMY_FAIL, /* Return an error code */ +} entropy_dummy_instruction; + +typedef struct +{ + entropy_dummy_instruction instruction; + size_t length; /* Length to return for DUMMY_CONSTANT_LENGTH */ + size_t calls; /* Incremented at each call */ +} entropy_dummy_context; /* * Dummy entropy source @@ -14,29 +23,28 @@ static size_t entropy_dummy_calls; * If data is NULL, write exactly the requested length. * Otherwise, write the length indicated by data or error if negative */ -static int entropy_dummy_source( void *data, unsigned char *output, +static int entropy_dummy_source( void *arg, unsigned char *output, size_t len, size_t *olen ) { - entropy_dummy_calls++; + entropy_dummy_context *context = arg; + ++context->calls; - if( data == NULL ) - *olen = len; - else + switch( context->instruction ) { - int *d = (int *) data; - - if( *d < 0 ) + case DUMMY_CONSTANT_LENGTH: + *olen = context->length; + break; + case DUMMY_REQUESTED_LENGTH: + *olen = len; + break; + case DUMMY_FAIL: return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); - else - *olen = *d; } memset( output, 0x2a, *olen ); - return( 0 ); } -#if defined(MBEDTLS_ENTROPY_NV_SEED) /* * Ability to clear entropy sources to allow testing with just predefined * entropy sources. This function or tests depending on it might break if there @@ -48,11 +56,12 @@ static int entropy_dummy_source( void *data, unsigned char *output, * This might break memory checks in the future if sources need 'free-ing' then * as well. */ -void entropy_clear_sources( mbedtls_entropy_context *ctx ) +static void entropy_clear_sources( mbedtls_entropy_context *ctx ) { ctx->source_count = 0; } +#if defined(MBEDTLS_ENTROPY_NV_SEED) /* * NV seed read/write functions that use a buffer instead of a file */ @@ -139,11 +148,28 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void entropy_no_sources( ) +{ + mbedtls_entropy_context ctx; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + mbedtls_entropy_init( &ctx ); + entropy_clear_sources( &ctx ); + TEST_EQUAL( mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ), + MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED ); + +exit: + mbedtls_entropy_free( &ctx ); +} +/* END_CASE */ + /* BEGIN_CASE */ void entropy_too_many_sources( ) { mbedtls_entropy_context ctx; size_t i; + entropy_dummy_context dummy = {DUMMY_REQUESTED_LENGTH, 0, 0}; mbedtls_entropy_init( &ctx ); @@ -152,10 +178,10 @@ void entropy_too_many_sources( ) * since we don't know how many sources were automatically added. */ for( i = 0; i < MBEDTLS_ENTROPY_MAX_SOURCES; i++ ) - (void) mbedtls_entropy_add_source( &ctx, entropy_dummy_source, NULL, + (void) mbedtls_entropy_add_source( &ctx, entropy_dummy_source, &dummy, 16, MBEDTLS_ENTROPY_SOURCE_WEAK ); - TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, NULL, + TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, &dummy, 16, MBEDTLS_ENTROPY_SOURCE_WEAK ) == MBEDTLS_ERR_ENTROPY_MAX_SOURCES ); @@ -197,13 +223,13 @@ void entropy_func_len( int len, int ret ) void entropy_source_fail( char * path ) { mbedtls_entropy_context ctx; - int fail = -1; unsigned char buf[16]; + entropy_dummy_context dummy = {DUMMY_FAIL, 0, 0}; mbedtls_entropy_init( &ctx ); TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, - &fail, 16, + &dummy, 16, MBEDTLS_ENTROPY_SOURCE_WEAK ) == 0 ); @@ -225,30 +251,87 @@ exit: } /* END_CASE */ -/* BEGIN_CASE depends_on:ENTROPY_HAVE_STRONG */ +/* BEGIN_CASE */ void entropy_threshold( int threshold, int chunk_size, int result ) { mbedtls_entropy_context ctx; + entropy_dummy_context strong = + {DUMMY_CONSTANT_LENGTH, MBEDTLS_ENTROPY_BLOCK_SIZE, 0}; + entropy_dummy_context weak = {DUMMY_CONSTANT_LENGTH, chunk_size, 0}; unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; int ret; mbedtls_entropy_init( &ctx ); + entropy_clear_sources( &ctx ); + /* Set strong source that reaches its threshold immediately and + * a weak source whose threshold is a test parameter. */ TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, - &chunk_size, threshold, + &strong, 1, + MBEDTLS_ENTROPY_SOURCE_STRONG ) == 0 ); + TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, + &weak, threshold, MBEDTLS_ENTROPY_SOURCE_WEAK ) == 0 ); - entropy_dummy_calls = 0; ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ); if( result >= 0 ) { TEST_ASSERT( ret == 0 ); #if defined(MBEDTLS_ENTROPY_NV_SEED) - // Two times as much calls due to the NV seed update + /* If the NV seed functionality is enabled, there are two entropy + * updates: before and after updating the NV seed. */ result *= 2; #endif - TEST_ASSERT( entropy_dummy_calls == (size_t) result ); + TEST_ASSERT( weak.calls == (size_t) result ); + } + else + { + TEST_ASSERT( ret == result ); + } + +exit: + mbedtls_entropy_free( &ctx ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void entropy_calls( int strength1, int strength2, + int threshold, int chunk_size, + int result ) +{ + /* + * if result >= 0: result = expected number of calls to source 1 + * if result < 0: result = expected return code from mbedtls_entropy_func() + */ + + mbedtls_entropy_context ctx; + entropy_dummy_context dummy1 = {DUMMY_CONSTANT_LENGTH, chunk_size, 0}; + entropy_dummy_context dummy2 = {DUMMY_CONSTANT_LENGTH, chunk_size, 0}; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; + int ret; + + mbedtls_entropy_init( &ctx ); + entropy_clear_sources( &ctx ); + + TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, + &dummy1, threshold, + strength1 ) == 0 ); + TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, + &dummy2, threshold, + strength2 ) == 0 ); + + ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ); + + if( result >= 0 ) + { + TEST_ASSERT( ret == 0 ); +#if defined(MBEDTLS_ENTROPY_NV_SEED) + /* If the NV seed functionality is enabled, there are two entropy + * updates: before and after updating the NV seed. */ + result *= 2; +#endif + TEST_ASSERT( dummy1.calls == (size_t) result ); } else {