1/* BEGIN_HEADER */ 2#include "mbedtls/entropy.h" 3#include "mbedtls/entropy_poll.h" 4#include "mbedtls/md.h" 5#include "string.h" 6 7typedef enum 8{ 9 DUMMY_CONSTANT_LENGTH, /* Output context->length bytes */ 10 DUMMY_REQUESTED_LENGTH, /* Output whatever length was requested */ 11 DUMMY_FAIL, /* Return an error code */ 12} entropy_dummy_instruction; 13 14typedef struct 15{ 16 entropy_dummy_instruction instruction; 17 size_t length; /* Length to return for DUMMY_CONSTANT_LENGTH */ 18 size_t calls; /* Incremented at each call */ 19} entropy_dummy_context; 20 21/* 22 * Dummy entropy source 23 * 24 * If data is NULL, write exactly the requested length. 25 * Otherwise, write the length indicated by data or error if negative 26 */ 27static int entropy_dummy_source( void *arg, unsigned char *output, 28 size_t len, size_t *olen ) 29{ 30 entropy_dummy_context *context = arg; 31 ++context->calls; 32 33 switch( context->instruction ) 34 { 35 case DUMMY_CONSTANT_LENGTH: 36 *olen = context->length; 37 break; 38 case DUMMY_REQUESTED_LENGTH: 39 *olen = len; 40 break; 41 case DUMMY_FAIL: 42 return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); 43 } 44 45 memset( output, 0x2a, *olen ); 46 return( 0 ); 47} 48 49/* 50 * Ability to clear entropy sources to allow testing with just predefined 51 * entropy sources. This function or tests depending on it might break if there 52 * are internal changes to how entropy sources are registered. 53 * 54 * To be called immediately after mbedtls_entropy_init(). 55 * 56 * Just resetting the counter. New sources will overwrite existing ones. 57 * This might break memory checks in the future if sources need 'free-ing' then 58 * as well. 59 */ 60static void entropy_clear_sources( mbedtls_entropy_context *ctx ) 61{ 62 ctx->source_count = 0; 63} 64 65#if defined(MBEDTLS_ENTROPY_NV_SEED) 66/* 67 * NV seed read/write functions that use a buffer instead of a file 68 */ 69static unsigned char buffer_seed[MBEDTLS_ENTROPY_BLOCK_SIZE]; 70 71int buffer_nv_seed_read( unsigned char *buf, size_t buf_len ) 72{ 73 if( buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE ) 74 return( -1 ); 75 76 memcpy( buf, buffer_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ); 77 return( 0 ); 78} 79 80int buffer_nv_seed_write( unsigned char *buf, size_t buf_len ) 81{ 82 if( buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE ) 83 return( -1 ); 84 85 memcpy( buffer_seed, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); 86 return( 0 ); 87} 88 89/* 90 * NV seed read/write helpers that fill the base seedfile 91 */ 92static int write_nv_seed( unsigned char *buf, size_t buf_len ) 93{ 94 FILE *f; 95 96 if( buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE ) 97 return( -1 ); 98 99 if( ( f = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "w" ) ) == NULL ) 100 return( -1 ); 101 102 if( fwrite( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) != 103 MBEDTLS_ENTROPY_BLOCK_SIZE ) 104 return( -1 ); 105 106 fclose( f ); 107 108 return( 0 ); 109} 110 111int read_nv_seed( unsigned char *buf, size_t buf_len ) 112{ 113 FILE *f; 114 115 if( buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE ) 116 return( -1 ); 117 118 if( ( f = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "rb" ) ) == NULL ) 119 return( -1 ); 120 121 if( fread( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) != 122 MBEDTLS_ENTROPY_BLOCK_SIZE ) 123 return( -1 ); 124 125 fclose( f ); 126 127 return( 0 ); 128} 129#endif /* MBEDTLS_ENTROPY_NV_SEED */ 130/* END_HEADER */ 131 132/* BEGIN_DEPENDENCIES 133 * depends_on:MBEDTLS_ENTROPY_C 134 * END_DEPENDENCIES 135 */ 136 137/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */ 138void entropy_seed_file( char * path, int ret ) 139{ 140 mbedtls_entropy_context ctx; 141 142 mbedtls_entropy_init( &ctx ); 143 144 TEST_ASSERT( mbedtls_entropy_write_seed_file( &ctx, path ) == ret ); 145 TEST_ASSERT( mbedtls_entropy_update_seed_file( &ctx, path ) == ret ); 146 147exit: 148 mbedtls_entropy_free( &ctx ); 149} 150/* END_CASE */ 151 152/* BEGIN_CASE */ 153void entropy_no_sources( ) 154{ 155 mbedtls_entropy_context ctx; 156 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; 157 158 mbedtls_entropy_init( &ctx ); 159 entropy_clear_sources( &ctx ); 160 TEST_EQUAL( mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ), 161 MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED ); 162 163exit: 164 mbedtls_entropy_free( &ctx ); 165} 166/* END_CASE */ 167 168/* BEGIN_CASE */ 169void entropy_too_many_sources( ) 170{ 171 mbedtls_entropy_context ctx; 172 size_t i; 173 entropy_dummy_context dummy = {DUMMY_REQUESTED_LENGTH, 0, 0}; 174 175 mbedtls_entropy_init( &ctx ); 176 177 /* 178 * It's hard to tell precisely when the error will occur, 179 * since we don't know how many sources were automatically added. 180 */ 181 for( i = 0; i < MBEDTLS_ENTROPY_MAX_SOURCES; i++ ) 182 (void) mbedtls_entropy_add_source( &ctx, entropy_dummy_source, &dummy, 183 16, MBEDTLS_ENTROPY_SOURCE_WEAK ); 184 185 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, &dummy, 186 16, MBEDTLS_ENTROPY_SOURCE_WEAK ) 187 == MBEDTLS_ERR_ENTROPY_MAX_SOURCES ); 188 189exit: 190 mbedtls_entropy_free( &ctx ); 191} 192/* END_CASE */ 193 194/* BEGIN_CASE depends_on:ENTROPY_HAVE_STRONG */ 195void entropy_func_len( int len, int ret ) 196{ 197 mbedtls_entropy_context ctx; 198 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE + 10] = { 0 }; 199 unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE + 10] = { 0 }; 200 size_t i, j; 201 202 mbedtls_entropy_init( &ctx ); 203 204 /* 205 * See comments in mbedtls_entropy_self_test() 206 */ 207 for( i = 0; i < 8; i++ ) 208 { 209 TEST_ASSERT( mbedtls_entropy_func( &ctx, buf, len ) == ret ); 210 for( j = 0; j < sizeof( buf ); j++ ) 211 acc[j] |= buf[j]; 212 } 213 214 if( ret == 0 ) 215 for( j = 0; j < (size_t) len; j++ ) 216 TEST_ASSERT( acc[j] != 0 ); 217 218 for( j = len; j < sizeof( buf ); j++ ) 219 TEST_ASSERT( acc[j] == 0 ); 220} 221/* END_CASE */ 222 223/* BEGIN_CASE */ 224void entropy_source_fail( char * path ) 225{ 226 mbedtls_entropy_context ctx; 227 unsigned char buf[16]; 228 entropy_dummy_context dummy = {DUMMY_FAIL, 0, 0}; 229 230 mbedtls_entropy_init( &ctx ); 231 232 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, 233 &dummy, 16, 234 MBEDTLS_ENTROPY_SOURCE_WEAK ) 235 == 0 ); 236 237 TEST_ASSERT( mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ) 238 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); 239 TEST_ASSERT( mbedtls_entropy_gather( &ctx ) 240 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); 241#if defined(MBEDTLS_FS_IO) && defined(MBEDTLS_ENTROPY_NV_SEED) 242 TEST_ASSERT( mbedtls_entropy_write_seed_file( &ctx, path ) 243 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); 244 TEST_ASSERT( mbedtls_entropy_update_seed_file( &ctx, path ) 245 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); 246#else 247 ((void) path); 248#endif 249 250exit: 251 mbedtls_entropy_free( &ctx ); 252} 253/* END_CASE */ 254 255/* BEGIN_CASE */ 256void entropy_threshold( int threshold, int chunk_size, int result ) 257{ 258 mbedtls_entropy_context ctx; 259 entropy_dummy_context strong = 260 {DUMMY_CONSTANT_LENGTH, MBEDTLS_ENTROPY_BLOCK_SIZE, 0}; 261 entropy_dummy_context weak = {DUMMY_CONSTANT_LENGTH, chunk_size, 0}; 262 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; 263 int ret; 264 265 mbedtls_entropy_init( &ctx ); 266 entropy_clear_sources( &ctx ); 267 268 /* Set strong source that reaches its threshold immediately and 269 * a weak source whose threshold is a test parameter. */ 270 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, 271 &strong, 1, 272 MBEDTLS_ENTROPY_SOURCE_STRONG ) == 0 ); 273 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, 274 &weak, threshold, 275 MBEDTLS_ENTROPY_SOURCE_WEAK ) == 0 ); 276 277 ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ); 278 279 if( result >= 0 ) 280 { 281 TEST_ASSERT( ret == 0 ); 282#if defined(MBEDTLS_ENTROPY_NV_SEED) 283 /* If the NV seed functionality is enabled, there are two entropy 284 * updates: before and after updating the NV seed. */ 285 result *= 2; 286#endif 287 TEST_ASSERT( weak.calls == (size_t) result ); 288 } 289 else 290 { 291 TEST_ASSERT( ret == result ); 292 } 293 294exit: 295 mbedtls_entropy_free( &ctx ); 296} 297/* END_CASE */ 298 299/* BEGIN_CASE */ 300void entropy_calls( int strength1, int strength2, 301 int threshold, int chunk_size, 302 int result ) 303{ 304 /* 305 * if result >= 0: result = expected number of calls to source 1 306 * if result < 0: result = expected return code from mbedtls_entropy_func() 307 */ 308 309 mbedtls_entropy_context ctx; 310 entropy_dummy_context dummy1 = {DUMMY_CONSTANT_LENGTH, chunk_size, 0}; 311 entropy_dummy_context dummy2 = {DUMMY_CONSTANT_LENGTH, chunk_size, 0}; 312 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; 313 int ret; 314 315 mbedtls_entropy_init( &ctx ); 316 entropy_clear_sources( &ctx ); 317 318 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, 319 &dummy1, threshold, 320 strength1 ) == 0 ); 321 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, 322 &dummy2, threshold, 323 strength2 ) == 0 ); 324 325 ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ); 326 327 if( result >= 0 ) 328 { 329 TEST_ASSERT( ret == 0 ); 330#if defined(MBEDTLS_ENTROPY_NV_SEED) 331 /* If the NV seed functionality is enabled, there are two entropy 332 * updates: before and after updating the NV seed. */ 333 result *= 2; 334#endif 335 TEST_ASSERT( dummy1.calls == (size_t) result ); 336 } 337 else 338 { 339 TEST_ASSERT( ret == result ); 340 } 341 342exit: 343 mbedtls_entropy_free( &ctx ); 344} 345/* END_CASE */ 346 347/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */ 348void nv_seed_file_create( ) 349{ 350 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; 351 352 memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); 353 354 TEST_ASSERT( write_nv_seed( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 355} 356/* END_CASE */ 357 358/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO:MBEDTLS_PLATFORM_NV_SEED_ALT */ 359void entropy_nv_seed_std_io( ) 360{ 361 unsigned char io_seed[MBEDTLS_ENTROPY_BLOCK_SIZE]; 362 unsigned char check_seed[MBEDTLS_ENTROPY_BLOCK_SIZE]; 363 364 memset( io_seed, 1, MBEDTLS_ENTROPY_BLOCK_SIZE ); 365 memset( check_seed, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); 366 367 mbedtls_platform_set_nv_seed( mbedtls_platform_std_nv_seed_read, 368 mbedtls_platform_std_nv_seed_write ); 369 370 /* Check if platform NV read and write manipulate the same data */ 371 TEST_ASSERT( write_nv_seed( io_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 372 TEST_ASSERT( mbedtls_nv_seed_read( check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 373 MBEDTLS_ENTROPY_BLOCK_SIZE ); 374 375 TEST_ASSERT( memcmp( io_seed, check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 376 377 memset( check_seed, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); 378 379 /* Check if platform NV write and raw read manipulate the same data */ 380 TEST_ASSERT( mbedtls_nv_seed_write( io_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 381 MBEDTLS_ENTROPY_BLOCK_SIZE ); 382 TEST_ASSERT( read_nv_seed( check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 383 384 TEST_ASSERT( memcmp( io_seed, check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 385} 386/* END_CASE */ 387 388/* BEGIN_CASE depends_on:MBEDTLS_MD_C:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_PLATFORM_NV_SEED_ALT */ 389void entropy_nv_seed( data_t * read_seed ) 390{ 391#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) 392 const mbedtls_md_info_t *md_info = 393 mbedtls_md_info_from_type( MBEDTLS_MD_SHA512 ); 394#elif defined(MBEDTLS_ENTROPY_SHA256_ACCUMULATOR) 395 const mbedtls_md_info_t *md_info = 396 mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ); 397#else 398#error "Unsupported entropy accumulator" 399#endif 400 mbedtls_md_context_t accumulator; 401 mbedtls_entropy_context ctx; 402 int (*original_mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len ) = 403 mbedtls_nv_seed_read; 404 int (*original_mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len ) = 405 mbedtls_nv_seed_write; 406 407 unsigned char header[2]; 408 unsigned char entropy[MBEDTLS_ENTROPY_BLOCK_SIZE]; 409 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; 410 unsigned char empty[MBEDTLS_ENTROPY_BLOCK_SIZE]; 411 unsigned char check_seed[MBEDTLS_ENTROPY_BLOCK_SIZE]; 412 unsigned char check_entropy[MBEDTLS_ENTROPY_BLOCK_SIZE]; 413 414 memset( entropy, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); 415 memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); 416 memset( empty, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); 417 memset( check_seed, 2, MBEDTLS_ENTROPY_BLOCK_SIZE ); 418 memset( check_entropy, 3, MBEDTLS_ENTROPY_BLOCK_SIZE ); 419 420 // Make sure we read/write NV seed from our buffers 421 mbedtls_platform_set_nv_seed( buffer_nv_seed_read, buffer_nv_seed_write ); 422 423 mbedtls_md_init( &accumulator ); 424 mbedtls_entropy_init( &ctx ); 425 entropy_clear_sources( &ctx ); 426 427 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, mbedtls_nv_seed_poll, NULL, 428 MBEDTLS_ENTROPY_BLOCK_SIZE, 429 MBEDTLS_ENTROPY_SOURCE_STRONG ) == 0 ); 430 431 // Set the initial NV seed to read 432 TEST_ASSERT( read_seed->len >= MBEDTLS_ENTROPY_BLOCK_SIZE ); 433 memcpy( buffer_seed, read_seed->x, MBEDTLS_ENTROPY_BLOCK_SIZE ); 434 435 // Do an entropy run 436 TEST_ASSERT( mbedtls_entropy_func( &ctx, entropy, sizeof( entropy ) ) == 0 ); 437 // Determine what should have happened with manual entropy internal logic 438 439 // Init accumulator 440 header[1] = MBEDTLS_ENTROPY_BLOCK_SIZE; 441 TEST_ASSERT( mbedtls_md_setup( &accumulator, md_info, 0 ) == 0 ); 442 443 // First run for updating write_seed 444 header[0] = 0; 445 TEST_ASSERT( mbedtls_md_starts( &accumulator ) == 0 ); 446 TEST_ASSERT( mbedtls_md_update( &accumulator, header, 2 ) == 0 ); 447 TEST_ASSERT( mbedtls_md_update( &accumulator, 448 read_seed->x, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 449 TEST_ASSERT( mbedtls_md_finish( &accumulator, buf ) == 0 ); 450 451 TEST_ASSERT( mbedtls_md_starts( &accumulator ) == 0 ); 452 TEST_ASSERT( mbedtls_md_update( &accumulator, 453 buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 454 455 TEST_ASSERT( mbedtls_md( md_info, buf, MBEDTLS_ENTROPY_BLOCK_SIZE, 456 check_seed ) == 0 ); 457 458 // Second run for actual entropy (triggers mbedtls_entropy_update_nv_seed) 459 header[0] = MBEDTLS_ENTROPY_SOURCE_MANUAL; 460 TEST_ASSERT( mbedtls_md_update( &accumulator, header, 2 ) == 0 ); 461 TEST_ASSERT( mbedtls_md_update( &accumulator, 462 empty, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 463 464 header[0] = 0; 465 TEST_ASSERT( mbedtls_md_update( &accumulator, header, 2 ) == 0 ); 466 TEST_ASSERT( mbedtls_md_update( &accumulator, 467 check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 468 TEST_ASSERT( mbedtls_md_finish( &accumulator, buf ) == 0 ); 469 470 TEST_ASSERT( mbedtls_md( md_info, buf, MBEDTLS_ENTROPY_BLOCK_SIZE, 471 check_entropy ) == 0 ); 472 473 // Check result of both NV file and entropy received with the manual calculations 474 TEST_ASSERT( memcmp( check_seed, buffer_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 475 TEST_ASSERT( memcmp( check_entropy, entropy, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 476 477exit: 478 mbedtls_md_free( &accumulator ); 479 mbedtls_entropy_free( &ctx ); 480 mbedtls_nv_seed_read = original_mbedtls_nv_seed_read; 481 mbedtls_nv_seed_write = original_mbedtls_nv_seed_write; 482} 483/* END_CASE */ 484 485/* BEGIN_CASE depends_on:ENTROPY_HAVE_STRONG:MBEDTLS_SELF_TEST */ 486void entropy_selftest( int result ) 487{ 488 TEST_ASSERT( mbedtls_entropy_self_test( 1 ) == result ); 489} 490/* END_CASE */ 491