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.
This commit is contained in:
Andres AG 2016-08-25 10:18:50 +01:00 committed by Simon Butcher
parent b34e42e69e
commit e7723ec284
4 changed files with 72 additions and 66 deletions

View File

@ -259,14 +259,14 @@ int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *
*/ */
int mbedtls_entropy_self_test( int verbose ); 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 * \brief Checkup routine
* *
* \return 0 if successful, or 1 if a test failed * \return 0 if successful, or 1 if a test failed
*/ */
int mbedtls_entropy_self_test_bias( int verbose ); int mbedtls_entropy_source_self_test( int verbose );
#endif /* !MBEDTLS_TEST_NULL_ENTROPY && MBEDTLS_ENTROPY_HARDWARE_ALT */ #endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */
#endif /* MBEDTLS_SELF_TEST */ #endif /* MBEDTLS_SELF_TEST */
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -470,80 +470,89 @@ static int entropy_dummy_source( void *data, unsigned char *output,
return( 0 ); 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 ) \ static int mbedtls_entropy_source_self_test_gather( unsigned char *buf, size_t buf_len )
{ \ {
size_t i; \ int ret = 0;
int has_pat = 1; \ size_t entropy_len = 0;
for( i = 0; i < buf_len; i += sizeof( type ) ) \ size_t olen = 0;
{ \ size_t attempts = buf_len;
has_pat &= memcmp( buf, buf + i, sizeof( type ) ) == 0; \
} \ while( attempts > 0 && entropy_len < buf_len )
if( ( ret = has_pat ) != 0 ) \ {
goto cleanup; \ if( ( ret = mbedtls_hardware_poll( NULL, buf + entropy_len,
} while( 0 ) \ 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 * A test to ensure hat the entropy sources are functioning correctly
* and there is no obvious bias. The test performs the following checks: * 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 * - The entropy source is not providing only 0s (all bits unset) or 1s (all
* bits set). * bits set).
* - The entropy source is not providing values in a pattern. Because the * - The entropy source is not providing values in a pattern. Because the
* hardware could be providing data in an arbitrary length, this check is * hardware could be providing data in an arbitrary length, this check polls
* only perform for bytes, words and long words. * 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. * - 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; int ret = 0;
unsigned char buf[2 * sizeof( unsigned long long int )]; unsigned char buf0[2 * sizeof( unsigned long long int )];
mbedtls_entropy_context ctx; unsigned char buf1[2 * sizeof( unsigned long long int )];
size_t entropy_len;
size_t olen;
size_t gather_tries;
if( verbose != 0 ) if( verbose != 0 )
mbedtls_printf( " ENTROPY_BIAS test: " ); mbedtls_printf( " ENTROPY_BIAS test: " );
memset( buf, 0x00, sizeof( buf ) ); memset( buf0, 0x00, sizeof( buf0 ) );
memset( buf1, 0x00, sizeof( buf1 ) );
mbedtls_entropy_init( &ctx ); if( ( ret = mbedtls_entropy_source_self_test_gather( buf0, sizeof( buf0 ) ) ) != 0 )
goto cleanup;
/* The hardware entropy source could return less than the amount of if( ( ret = mbedtls_entropy_source_self_test_gather( buf1, sizeof( buf1 ) ) ) != 0 )
* 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; goto cleanup;
entropy_len += olen; /* Make sure that the returned values are not all 0 or 1 */
gather_tries--; 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 )
if( entropy_len < sizeof( buf ) )
{
/* We still do not have enough entropy: fail */
ret = 1;
goto cleanup; goto cleanup;
}
/* Make sure that the entropy source is not returning values in a /* Make sure that the entropy source is not returning values in a
* pattern */ * pattern */
/* Byte */ ret = memcmp( buf0, buf1, sizeof( buf0 ) ) == 0;
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 );
cleanup: cleanup:
mbedtls_entropy_free( &ctx );
if( verbose != 0 ) if( verbose != 0 )
{ {
if( ret != 0 ) if( ret != 0 )
@ -556,7 +565,8 @@ cleanup:
return( ret != 0 ); 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 * 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: cleanup:
mbedtls_entropy_free( &ctx ); mbedtls_entropy_free( &ctx );

View File

@ -375,12 +375,6 @@ int main( int argc, char *argv[] )
{ {
suites_failed++; 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++; suites_tested++;
#endif #endif

View File

@ -381,8 +381,5 @@ void entropy_nv_seed( char *read_seed_str )
void entropy_selftest( ) void entropy_selftest( )
{ {
TEST_ASSERT( mbedtls_entropy_self_test( 0 ) == 0 ); 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 */ /* END_CASE */