From e7723ec284f3c23d6113cc37a77adfe7555455f9 Mon Sep 17 00:00:00 2001 From: Andres AG Date: Thu, 25 Aug 2016 10:18:50 +0100 Subject: [PATCH] Make entropy bias self test poll multiple times Instead of polling the hardware entropy source a single time and comparing the output with itself, the source is polled at least twice and make sure that the separate outputs are different. --- include/mbedtls/entropy.h | 6 +- library/entropy.c | 123 +++++++++++++---------- programs/test/selftest.c | 6 -- tests/suites/test_suite_entropy.function | 3 - 4 files changed, 72 insertions(+), 66 deletions(-) diff --git a/include/mbedtls/entropy.h b/include/mbedtls/entropy.h index fb7f2f4ab..19e8e7294 100644 --- a/include/mbedtls/entropy.h +++ b/include/mbedtls/entropy.h @@ -259,14 +259,14 @@ int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char * */ int mbedtls_entropy_self_test( int verbose ); -#if !defined(MBEDTLS_TEST_NULL_ENTROPY) && defined(MBEDTLS_ENTROPY_HARDWARE_ALT) +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) /** * \brief Checkup routine * * \return 0 if successful, or 1 if a test failed */ -int mbedtls_entropy_self_test_bias( int verbose ); -#endif /* !MBEDTLS_TEST_NULL_ENTROPY && MBEDTLS_ENTROPY_HARDWARE_ALT */ +int mbedtls_entropy_source_self_test( int verbose ); +#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ #endif /* MBEDTLS_SELF_TEST */ #ifdef __cplusplus diff --git a/library/entropy.c b/library/entropy.c index e09c24c79..42ace5533 100644 --- a/library/entropy.c +++ b/library/entropy.c @@ -470,80 +470,89 @@ static int entropy_dummy_source( void *data, unsigned char *output, return( 0 ); } -#if !defined(MBEDTLS_TEST_NULL_ENTROPY) && defined(MBEDTLS_ENTROPY_HARDWARE_ALT) +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) -#define MBEDTLS_SELF_TEST_BIAS_PATTERN( buf_len, type ) \ - { \ - size_t i; \ - int has_pat = 1; \ - for( i = 0; i < buf_len; i += sizeof( type ) ) \ - { \ - has_pat &= memcmp( buf, buf + i, sizeof( type ) ) == 0; \ - } \ - if( ( ret = has_pat ) != 0 ) \ - goto cleanup; \ - } while( 0 ) \ +static int mbedtls_entropy_source_self_test_gather( unsigned char *buf, size_t buf_len ) +{ + int ret = 0; + size_t entropy_len = 0; + size_t olen = 0; + size_t attempts = buf_len; + + while( attempts > 0 && entropy_len < buf_len ) + { + if( ( ret = mbedtls_hardware_poll( NULL, buf + entropy_len, + buf_len - entropy_len, &olen ) ) != 0 ) + return( ret ); + + entropy_len += olen; + attempts--; + } + + if( entropy_len < buf_len ) + { + ret = 1; + } + + return( ret ); +} + + +static int mbedtls_entropy_source_self_test_check_bits( const unsigned char *buf, + size_t buf_len ) +{ + unsigned char set= 0xFF; + unsigned char unset = 0x00; + size_t i; + + for( i = 0; i < buf_len; i++ ) + { + set &= buf[i]; + unset |= buf[i]; + } + + return( set == 0xFF || unset == 0x00 ); +} /* - * A quick test to ensure hat the entropy sources are functioning correctly - * and there is no obvious bias. The test performs the following checks: + * A test to ensure hat the entropy sources are functioning correctly + * and there is no obvious failure. The test performs the following checks: * - The entropy source is not providing only 0s (all bits unset) or 1s (all * bits set). * - The entropy source is not providing values in a pattern. Because the - * hardware could be providing data in an arbitrary length, this check is - * only perform for bytes, words and long words. + * hardware could be providing data in an arbitrary length, this check polls + * the hardware entropy source twice and compares the result to ensure they + * are not equal. * - The error code returned by the entropy source is not an error. */ -int mbedtls_entropy_self_test_bias( int verbose ) +int mbedtls_entropy_source_self_test( int verbose ) { int ret = 0; - unsigned char buf[2 * sizeof( unsigned long long int )]; - mbedtls_entropy_context ctx; - size_t entropy_len; - size_t olen; - size_t gather_tries; + unsigned char buf0[2 * sizeof( unsigned long long int )]; + unsigned char buf1[2 * sizeof( unsigned long long int )]; if( verbose != 0 ) mbedtls_printf( " ENTROPY_BIAS test: " ); - memset( buf, 0x00, sizeof( buf ) ); + memset( buf0, 0x00, sizeof( buf0 ) ); + memset( buf1, 0x00, sizeof( buf1 ) ); - mbedtls_entropy_init( &ctx ); - - /* The hardware entropy source could return less than the amount of - * bytes we requested, so we poll the source as many times as there are - * bytes */ - gather_tries = sizeof( buf ); - entropy_len = 0; - while( gather_tries > 0 && entropy_len < sizeof( buf ) ) - { - if( ( ret = mbedtls_hardware_poll( &ctx, buf + entropy_len, - sizeof( buf ) - entropy_len, &olen ) ) != 0 ) - goto cleanup; - - entropy_len += olen; - gather_tries--; - } - - if( entropy_len < sizeof( buf ) ) - { - /* We still do not have enough entropy: fail */ - ret = 1; + if( ( ret = mbedtls_entropy_source_self_test_gather( buf0, sizeof( buf0 ) ) ) != 0 ) + goto cleanup; + if( ( ret = mbedtls_entropy_source_self_test_gather( buf1, sizeof( buf1 ) ) ) != 0 ) + goto cleanup; + + /* Make sure that the returned values are not all 0 or 1 */ + if( ( ret = mbedtls_entropy_source_self_test_check_bits( buf0, sizeof( buf0 ) ) ) != 0 ) + goto cleanup; + if( ( ret = mbedtls_entropy_source_self_test_check_bits( buf1, sizeof( buf1 ) ) ) != 0 ) goto cleanup; - } /* Make sure that the entropy source is not returning values in a * pattern */ - /* Byte */ - MBEDTLS_SELF_TEST_BIAS_PATTERN( 2 * sizeof( unsigned long long int ), unsigned char ); - /* Word */ - MBEDTLS_SELF_TEST_BIAS_PATTERN( 2 * sizeof( unsigned long long int ), unsigned long ); - /* Long word */ - MBEDTLS_SELF_TEST_BIAS_PATTERN( 2 * sizeof( unsigned long long int ), unsigned long long int ); + ret = memcmp( buf0, buf1, sizeof( buf0 ) ) == 0; cleanup: - mbedtls_entropy_free( &ctx ); - if( verbose != 0 ) { if( ret != 0 ) @@ -556,7 +565,8 @@ cleanup: return( ret != 0 ); } -#endif /* !MBEDTLS_TEST_NULL_ENTROPY && MBEDTLS_ENTROPY_HARDWARE_ALT */ + +#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ /* * The actual entropy quality is hard to test, but we can at least @@ -614,6 +624,11 @@ int mbedtls_entropy_self_test( int verbose ) } } +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + if( ( ret = mbedtls_entropy_source_self_test( 0 ) ) != 0 ) + goto cleanup; +#endif + cleanup: mbedtls_entropy_free( &ctx ); diff --git a/programs/test/selftest.c b/programs/test/selftest.c index 62fa5fb95..89c66169e 100644 --- a/programs/test/selftest.c +++ b/programs/test/selftest.c @@ -375,12 +375,6 @@ int main( int argc, char *argv[] ) { suites_failed++; } -#if !defined(MBEDTLS_TEST_NULL_ENTROPY) && defined(MBEDTLS_ENTROPY_HARDWARE_ALT) - if( mbedtls_entropy_self_test_bias( v ) != 0) - { - suites_failed++; - } -#endif suites_tested++; #endif diff --git a/tests/suites/test_suite_entropy.function b/tests/suites/test_suite_entropy.function index c81f279cb..d1ef94b6e 100644 --- a/tests/suites/test_suite_entropy.function +++ b/tests/suites/test_suite_entropy.function @@ -381,8 +381,5 @@ void entropy_nv_seed( char *read_seed_str ) void entropy_selftest( ) { TEST_ASSERT( mbedtls_entropy_self_test( 0 ) == 0 ); -#if !defined(MBEDTLS_TEST_NULL_ENTROPY) && defined(MBEDTLS_ENTROPY_HARDWARE_ALT) - TEST_ASSERT( mbedtls_entropy_self_test_bias( 0 ) == 0 ); -#endif } /* END_CASE */