From ffbfb4c24cc3007de9d53e9410b8265423541633 Mon Sep 17 00:00:00 2001 From: Paul Bakker Date: Wed, 1 Jun 2016 15:36:18 +0100 Subject: [PATCH] Add test cases for NV seed functionality A standard 'test' that writes a seed file is added so that regular tests still can succeed. This is in lieu of a 'SUITE_PRE_CODE' kind of arrangement where a suite can run code before (and after) all other code runs. A test is added that checks if we can read and write the standard NV seed file A test is added that actually checks if the entropy and seed file values that are the result of just using the NV seed are the same as the manual calculation. --- tests/suites/test_suite_entropy.data | 15 ++ tests/suites/test_suite_entropy.function | 203 +++++++++++++++++++++++ 2 files changed, 218 insertions(+) diff --git a/tests/suites/test_suite_entropy.data b/tests/suites/test_suite_entropy.data index 833eef565..5ca99f85c 100644 --- a/tests/suites/test_suite_entropy.data +++ b/tests/suites/test_suite_entropy.data @@ -1,3 +1,6 @@ +Create NV seed_file +nv_seed_file_create: + Entropy write/update seed file entropy_seed_file:"data_files/entropy_seed":0 @@ -37,5 +40,17 @@ entropy_threshold:16:0:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED Entropy thershold #4 entropy_threshold:1024:1:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED +Check NV seed standard IO +entropy_nv_seed_std_io: + +Check NV seed manually #1 +entropy_nv_seed:"00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF" + +Check NV seed manually #2 +entropy_nv_seed:"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + +Check NV seed manually #3 +entropy_nv_seed:"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + Entropy self test entropy_selftest: diff --git a/tests/suites/test_suite_entropy.function b/tests/suites/test_suite_entropy.function index 3b739cce9..999b5f667 100644 --- a/tests/suites/test_suite_entropy.function +++ b/tests/suites/test_suite_entropy.function @@ -1,5 +1,6 @@ /* BEGIN_HEADER */ #include "mbedtls/entropy.h" +#include "mbedtls/entropy_poll.h" /* * Number of calls made to entropy_dummy_source() @@ -33,6 +34,86 @@ static int entropy_dummy_source( void *data, unsigned char *output, return( 0 ); } + +/* + * Ability to clear entropy sources to allow testing with just predefined + * entropy sources. This function or tests depending on it might break if there + * are internal changes to how entropy sources are registered. + * + * To be called immediately after mbedtls_entropy_init(). + * + * Just resetting the counter. New sources will overwrite existing ones. + * This might break memory checks in the future if sources need 'free-ing' then + * as well. + */ +static void entropy_clear_sources( mbedtls_entropy_context *ctx ) +{ + ctx->source_count = 0; +} + +/* + * NV seed read/write functions that use a buffer instead of a file + */ +static unsigned char buffer_seed[MBEDTLS_ENTROPY_BLOCK_SIZE]; + +static int buffer_nv_seed_read( unsigned char *buf, size_t buf_len ) +{ + if( buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE ) + return( -1 ); + + memcpy( buf, buffer_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ); + return( 0 ); +} + +static int buffer_nv_seed_write( unsigned char *buf, size_t buf_len ) +{ + if( buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE ) + return( -1 ); + + memcpy( buffer_seed, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); + return( 0 ); +} + +/* + * NV seed read/write helpers that fill the base seedfile + */ +static int write_nv_seed( unsigned char *buf, size_t buf_len ) +{ + FILE *f; + + if( buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE ) + return( -1 ); + + if( ( f = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "w" ) ) == NULL ) + return( -1 ); + + if( fwrite( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) != + MBEDTLS_ENTROPY_BLOCK_SIZE ) + return( -1 ); + + fclose( f ); + + return( 0 ); +} + +static int read_nv_seed( unsigned char *buf, size_t buf_len ) +{ + FILE *f; + + if( buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE ) + return( -1 ); + + if( ( f = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "rb" ) ) == NULL ) + return( -1 ); + + if( fread( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) != + MBEDTLS_ENTROPY_BLOCK_SIZE ) + return( -1 ); + + fclose( f ); + + return( 0 ); +} /* END_HEADER */ /* BEGIN_DEPENDENCIES @@ -160,6 +241,10 @@ void entropy_threshold( int threshold, int chunk_size, int result ) if( result >= 0 ) { TEST_ASSERT( ret == 0 ); +#if defined(MBEDTLS_ENTROPY_NV_SEED) + // Two times as much calls due to the NV seed update + result *= 2; +#endif TEST_ASSERT( entropy_dummy_calls == (size_t) result ); } else @@ -172,6 +257,124 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */ +void nv_seed_file_create() +{ + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + TEST_ASSERT( write_nv_seed( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */ +void entropy_nv_seed_std_io() +{ + unsigned char io_seed[MBEDTLS_ENTROPY_BLOCK_SIZE]; + unsigned char check_seed[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + memset( io_seed, 1, MBEDTLS_ENTROPY_BLOCK_SIZE ); + memset( check_seed, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + mbedtls_platform_set_nv_seed( mbedtls_platform_std_nv_seed_read, + mbedtls_platform_std_nv_seed_write ); + + /* Check if platform NV read and write manipulate the same data */ + TEST_ASSERT( write_nv_seed( io_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); + TEST_ASSERT( mbedtls_nv_seed_read( check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == + MBEDTLS_ENTROPY_BLOCK_SIZE ); + + TEST_ASSERT( memcmp( io_seed, check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); + + memset( check_seed, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + /* Check if platform NV write and raw read manipulate the same data */ + TEST_ASSERT( mbedtls_nv_seed_write( io_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == + MBEDTLS_ENTROPY_BLOCK_SIZE ); + TEST_ASSERT( read_nv_seed( check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); + + TEST_ASSERT( memcmp( io_seed, check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_PLATFORM_NV_SEED_ALT:MBEDTLS_SHA512_C */ +void entropy_nv_seed( char *read_seed_str ) +{ + mbedtls_sha512_context accumulator; + mbedtls_entropy_context ctx; + + unsigned char header[2]; + unsigned char entropy[MBEDTLS_ENTROPY_BLOCK_SIZE]; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + unsigned char empty[MBEDTLS_ENTROPY_BLOCK_SIZE]; + unsigned char read_seed[MBEDTLS_ENTROPY_BLOCK_SIZE]; + unsigned char check_seed[MBEDTLS_ENTROPY_BLOCK_SIZE]; + unsigned char check_entropy[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + memset( entropy, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + memset( buffer_seed, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + memset( empty, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + memset( check_seed, 2, MBEDTLS_ENTROPY_BLOCK_SIZE ); + memset( check_entropy, 3, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + // Set the initial NV seed to read + unhexify( read_seed, read_seed_str ); + memcpy( buffer_seed, read_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + // Make sure we read/write NV seed from our buffers + mbedtls_platform_set_nv_seed( buffer_nv_seed_read, buffer_nv_seed_write ); + + mbedtls_entropy_init( &ctx ); + entropy_clear_sources( &ctx ); + + TEST_ASSERT( mbedtls_entropy_add_source( &ctx, mbedtls_nv_seed_poll, NULL, + MBEDTLS_ENTROPY_BLOCK_SIZE, + MBEDTLS_ENTROPY_SOURCE_STRONG ) == 0 ); + + // Do an entropy run + TEST_ASSERT( mbedtls_entropy_func( &ctx, entropy, sizeof( entropy ) ) == 0 ); + + // Determine what should have happened with manual entropy internal logic + // Only use the SHA-512 version to check + + // Init accumulator + header[1] = MBEDTLS_ENTROPY_BLOCK_SIZE; + mbedtls_sha512_starts( &accumulator, 0 ); + + // First run for updating write_seed + header[0] = 0; + mbedtls_sha512_update( &accumulator, header, 2 ); + mbedtls_sha512_update( &accumulator, read_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ); + mbedtls_sha512_finish( &accumulator, buf ); + + memset( &accumulator, 0, sizeof( mbedtls_sha512_context ) ); + mbedtls_sha512_starts( &accumulator, 0 ); + mbedtls_sha512_update( &accumulator, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + mbedtls_sha512( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, check_seed, 0 ); + + // Second run for actual entropy (triggers mbedtls_entropy_update_nv_seed) + header[0] = MBEDTLS_ENTROPY_SOURCE_MANUAL; + mbedtls_sha512_update( &accumulator, header, 2 ); + mbedtls_sha512_update( &accumulator, empty, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + header[0] = 0; + mbedtls_sha512_update( &accumulator, header, 2 ); + mbedtls_sha512_update( &accumulator, check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ); + mbedtls_sha512_finish( &accumulator, buf ); + + mbedtls_sha512( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, check_entropy, 0 ); + + // Check result of both NV file and entropy received with the manual calculations + TEST_ASSERT( memcmp( check_seed, buffer_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); + TEST_ASSERT( memcmp( check_entropy, entropy, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); + + mbedtls_entropy_free( &ctx ); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_SELF_TEST */ void entropy_selftest( ) {