Skip to content

Always gather MBEDTLS_ENTROPY_BLOCK_SIZE bytes of entropy #293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions library/entropy.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,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];

Expand Down Expand Up @@ -363,12 +364,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 );

Expand Down
43 changes: 32 additions & 11 deletions tests/suites/test_suite_entropy.data
Original file line number Diff line number Diff line change
@@ -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:

Expand Down
135 changes: 109 additions & 26 deletions tests/suites/test_suite_entropy.function
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,48 @@
#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
*
* 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
Expand All @@ -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
*/
Expand Down Expand Up @@ -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 );

Expand All @@ -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 );

Expand Down Expand Up @@ -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 );

Expand All @@ -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( 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( entropy_dummy_calls == (size_t) result );
TEST_ASSERT( dummy1.calls == (size_t) result );
}
else
{
Expand Down