1/* BEGIN_HEADER */ 2#include "mbedtls/entropy.h" 3#include "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 */ 138void entropy_init_free( int reinit ) 139{ 140 mbedtls_entropy_context ctx; 141 142 /* Double free is not explicitly documented to work, but it is convenient 143 * to call mbedtls_entropy_free() unconditionally on an error path without 144 * checking whether it has already been called in the success path. */ 145 146 mbedtls_entropy_init( &ctx ); 147 mbedtls_entropy_free( &ctx ); 148 149 if( reinit ) 150 mbedtls_entropy_init( &ctx ); 151 mbedtls_entropy_free( &ctx ); 152 153 /* This test case always succeeds, functionally speaking. A plausible 154 * bug might trigger an invalid pointer dereference or a memory leak. */ 155 goto exit; 156} 157/* END_CASE */ 158 159/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */ 160void entropy_seed_file( char * path, int ret ) 161{ 162 mbedtls_entropy_context ctx; 163 164 mbedtls_entropy_init( &ctx ); 165 166 TEST_ASSERT( mbedtls_entropy_write_seed_file( &ctx, path ) == ret ); 167 TEST_ASSERT( mbedtls_entropy_update_seed_file( &ctx, path ) == ret ); 168 169exit: 170 mbedtls_entropy_free( &ctx ); 171} 172/* END_CASE */ 173 174/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */ 175void entropy_write_base_seed_file( int ret ) 176{ 177 mbedtls_entropy_context ctx; 178 179 mbedtls_entropy_init( &ctx ); 180 181 TEST_ASSERT( mbedtls_entropy_write_seed_file( &ctx, MBEDTLS_PLATFORM_STD_NV_SEED_FILE ) == ret ); 182 TEST_ASSERT( mbedtls_entropy_update_seed_file( &ctx, MBEDTLS_PLATFORM_STD_NV_SEED_FILE ) == ret ); 183 184exit: 185 mbedtls_entropy_free( &ctx ); 186} 187/* END_CASE */ 188 189/* BEGIN_CASE */ 190void entropy_no_sources( ) 191{ 192 mbedtls_entropy_context ctx; 193 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; 194 195 mbedtls_entropy_init( &ctx ); 196 entropy_clear_sources( &ctx ); 197 TEST_EQUAL( mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ), 198 MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED ); 199 200exit: 201 mbedtls_entropy_free( &ctx ); 202} 203/* END_CASE */ 204 205/* BEGIN_CASE */ 206void entropy_too_many_sources( ) 207{ 208 mbedtls_entropy_context ctx; 209 size_t i; 210 entropy_dummy_context dummy = {DUMMY_REQUESTED_LENGTH, 0, 0}; 211 212 mbedtls_entropy_init( &ctx ); 213 214 /* 215 * It's hard to tell precisely when the error will occur, 216 * since we don't know how many sources were automatically added. 217 */ 218 for( i = 0; i < MBEDTLS_ENTROPY_MAX_SOURCES; i++ ) 219 (void) mbedtls_entropy_add_source( &ctx, entropy_dummy_source, &dummy, 220 16, MBEDTLS_ENTROPY_SOURCE_WEAK ); 221 222 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, &dummy, 223 16, MBEDTLS_ENTROPY_SOURCE_WEAK ) 224 == MBEDTLS_ERR_ENTROPY_MAX_SOURCES ); 225 226exit: 227 mbedtls_entropy_free( &ctx ); 228} 229/* END_CASE */ 230 231/* BEGIN_CASE depends_on:ENTROPY_HAVE_STRONG */ 232void entropy_func_len( int len, int ret ) 233{ 234 mbedtls_entropy_context ctx; 235 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE + 10] = { 0 }; 236 unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE + 10] = { 0 }; 237 size_t i, j; 238 239 mbedtls_entropy_init( &ctx ); 240 241 /* 242 * See comments in mbedtls_entropy_self_test() 243 */ 244 for( i = 0; i < 8; i++ ) 245 { 246 TEST_ASSERT( mbedtls_entropy_func( &ctx, buf, len ) == ret ); 247 for( j = 0; j < sizeof( buf ); j++ ) 248 acc[j] |= buf[j]; 249 } 250 251 if( ret == 0 ) 252 for( j = 0; j < (size_t) len; j++ ) 253 TEST_ASSERT( acc[j] != 0 ); 254 255 for( j = len; j < sizeof( buf ); j++ ) 256 TEST_ASSERT( acc[j] == 0 ); 257 258exit: 259 mbedtls_entropy_free( &ctx ); 260} 261/* END_CASE */ 262 263/* BEGIN_CASE */ 264void entropy_source_fail( char * path ) 265{ 266 mbedtls_entropy_context ctx; 267 unsigned char buf[16]; 268 entropy_dummy_context dummy = {DUMMY_FAIL, 0, 0}; 269 270 mbedtls_entropy_init( &ctx ); 271 272 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, 273 &dummy, 16, 274 MBEDTLS_ENTROPY_SOURCE_WEAK ) 275 == 0 ); 276 277 TEST_ASSERT( mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ) 278 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); 279 TEST_ASSERT( mbedtls_entropy_gather( &ctx ) 280 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); 281#if defined(MBEDTLS_FS_IO) && defined(MBEDTLS_ENTROPY_NV_SEED) 282 TEST_ASSERT( mbedtls_entropy_write_seed_file( &ctx, path ) 283 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); 284 TEST_ASSERT( mbedtls_entropy_update_seed_file( &ctx, path ) 285 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); 286#else 287 ((void) path); 288#endif 289 290exit: 291 mbedtls_entropy_free( &ctx ); 292} 293/* END_CASE */ 294 295/* BEGIN_CASE */ 296void entropy_threshold( int threshold, int chunk_size, int result ) 297{ 298 mbedtls_entropy_context ctx; 299 entropy_dummy_context strong = 300 {DUMMY_CONSTANT_LENGTH, MBEDTLS_ENTROPY_BLOCK_SIZE, 0}; 301 entropy_dummy_context weak = {DUMMY_CONSTANT_LENGTH, chunk_size, 0}; 302 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; 303 int ret; 304 305 mbedtls_entropy_init( &ctx ); 306 entropy_clear_sources( &ctx ); 307 308 /* Set strong source that reaches its threshold immediately and 309 * a weak source whose threshold is a test parameter. */ 310 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, 311 &strong, 1, 312 MBEDTLS_ENTROPY_SOURCE_STRONG ) == 0 ); 313 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, 314 &weak, threshold, 315 MBEDTLS_ENTROPY_SOURCE_WEAK ) == 0 ); 316 317 ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ); 318 319 if( result >= 0 ) 320 { 321 TEST_ASSERT( ret == 0 ); 322#if defined(MBEDTLS_ENTROPY_NV_SEED) 323 /* If the NV seed functionality is enabled, there are two entropy 324 * updates: before and after updating the NV seed. */ 325 result *= 2; 326#endif 327 TEST_ASSERT( weak.calls == (size_t) result ); 328 } 329 else 330 { 331 TEST_ASSERT( ret == result ); 332 } 333 334exit: 335 mbedtls_entropy_free( &ctx ); 336} 337/* END_CASE */ 338 339/* BEGIN_CASE */ 340void entropy_calls( int strength1, int strength2, 341 int threshold, int chunk_size, 342 int result ) 343{ 344 /* 345 * if result >= 0: result = expected number of calls to source 1 346 * if result < 0: result = expected return code from mbedtls_entropy_func() 347 */ 348 349 mbedtls_entropy_context ctx; 350 entropy_dummy_context dummy1 = {DUMMY_CONSTANT_LENGTH, chunk_size, 0}; 351 entropy_dummy_context dummy2 = {DUMMY_CONSTANT_LENGTH, chunk_size, 0}; 352 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; 353 int ret; 354 355 mbedtls_entropy_init( &ctx ); 356 entropy_clear_sources( &ctx ); 357 358 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, 359 &dummy1, threshold, 360 strength1 ) == 0 ); 361 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, 362 &dummy2, threshold, 363 strength2 ) == 0 ); 364 365 ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ); 366 367 if( result >= 0 ) 368 { 369 TEST_ASSERT( ret == 0 ); 370#if defined(MBEDTLS_ENTROPY_NV_SEED) 371 /* If the NV seed functionality is enabled, there are two entropy 372 * updates: before and after updating the NV seed. */ 373 result *= 2; 374#endif 375 TEST_ASSERT( dummy1.calls == (size_t) result ); 376 } 377 else 378 { 379 TEST_ASSERT( ret == result ); 380 } 381 382exit: 383 mbedtls_entropy_free( &ctx ); 384} 385/* END_CASE */ 386 387/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */ 388void nv_seed_file_create( ) 389{ 390 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; 391 392 memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); 393 394 TEST_ASSERT( write_nv_seed( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 395} 396/* END_CASE */ 397 398/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO:MBEDTLS_PLATFORM_NV_SEED_ALT */ 399void entropy_nv_seed_std_io( ) 400{ 401 unsigned char io_seed[MBEDTLS_ENTROPY_BLOCK_SIZE]; 402 unsigned char check_seed[MBEDTLS_ENTROPY_BLOCK_SIZE]; 403 404 memset( io_seed, 1, MBEDTLS_ENTROPY_BLOCK_SIZE ); 405 memset( check_seed, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); 406 407 mbedtls_platform_set_nv_seed( mbedtls_platform_std_nv_seed_read, 408 mbedtls_platform_std_nv_seed_write ); 409 410 /* Check if platform NV read and write manipulate the same data */ 411 TEST_ASSERT( write_nv_seed( io_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 412 TEST_ASSERT( mbedtls_nv_seed_read( check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 413 MBEDTLS_ENTROPY_BLOCK_SIZE ); 414 415 TEST_ASSERT( memcmp( io_seed, check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 416 417 memset( check_seed, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); 418 419 /* Check if platform NV write and raw read manipulate the same data */ 420 TEST_ASSERT( mbedtls_nv_seed_write( io_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 421 MBEDTLS_ENTROPY_BLOCK_SIZE ); 422 TEST_ASSERT( read_nv_seed( check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 423 424 TEST_ASSERT( memcmp( io_seed, check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 425} 426/* END_CASE */ 427 428/* BEGIN_CASE depends_on:MBEDTLS_MD_C:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_PLATFORM_NV_SEED_ALT */ 429void entropy_nv_seed( data_t * read_seed ) 430{ 431#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) 432 const mbedtls_md_info_t *md_info = 433 mbedtls_md_info_from_type( MBEDTLS_MD_SHA512 ); 434#elif defined(MBEDTLS_ENTROPY_SHA256_ACCUMULATOR) 435 const mbedtls_md_info_t *md_info = 436 mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ); 437#else 438#error "Unsupported entropy accumulator" 439#endif 440 mbedtls_md_context_t accumulator; 441 mbedtls_entropy_context ctx; 442 int (*original_mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len ) = 443 mbedtls_nv_seed_read; 444 int (*original_mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len ) = 445 mbedtls_nv_seed_write; 446 447 unsigned char header[2]; 448 unsigned char entropy[MBEDTLS_ENTROPY_BLOCK_SIZE]; 449 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; 450 unsigned char empty[MBEDTLS_ENTROPY_BLOCK_SIZE]; 451 unsigned char check_seed[MBEDTLS_ENTROPY_BLOCK_SIZE]; 452 unsigned char check_entropy[MBEDTLS_ENTROPY_BLOCK_SIZE]; 453 454 memset( entropy, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); 455 memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); 456 memset( empty, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); 457 memset( check_seed, 2, MBEDTLS_ENTROPY_BLOCK_SIZE ); 458 memset( check_entropy, 3, MBEDTLS_ENTROPY_BLOCK_SIZE ); 459 460 // Make sure we read/write NV seed from our buffers 461 mbedtls_platform_set_nv_seed( buffer_nv_seed_read, buffer_nv_seed_write ); 462 463 mbedtls_md_init( &accumulator ); 464 mbedtls_entropy_init( &ctx ); 465 entropy_clear_sources( &ctx ); 466 467 TEST_ASSERT( mbedtls_entropy_add_source( &ctx, mbedtls_nv_seed_poll, NULL, 468 MBEDTLS_ENTROPY_BLOCK_SIZE, 469 MBEDTLS_ENTROPY_SOURCE_STRONG ) == 0 ); 470 471 // Set the initial NV seed to read 472 TEST_ASSERT( read_seed->len >= MBEDTLS_ENTROPY_BLOCK_SIZE ); 473 memcpy( buffer_seed, read_seed->x, MBEDTLS_ENTROPY_BLOCK_SIZE ); 474 475 // Do an entropy run 476 TEST_ASSERT( mbedtls_entropy_func( &ctx, entropy, sizeof( entropy ) ) == 0 ); 477 // Determine what should have happened with manual entropy internal logic 478 479 // Init accumulator 480 header[1] = MBEDTLS_ENTROPY_BLOCK_SIZE; 481 TEST_ASSERT( mbedtls_md_setup( &accumulator, md_info, 0 ) == 0 ); 482 483 // First run for updating write_seed 484 header[0] = 0; 485 TEST_ASSERT( mbedtls_md_starts( &accumulator ) == 0 ); 486 TEST_ASSERT( mbedtls_md_update( &accumulator, header, 2 ) == 0 ); 487 TEST_ASSERT( mbedtls_md_update( &accumulator, 488 read_seed->x, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 489 TEST_ASSERT( mbedtls_md_finish( &accumulator, buf ) == 0 ); 490 491 TEST_ASSERT( mbedtls_md_starts( &accumulator ) == 0 ); 492 TEST_ASSERT( mbedtls_md_update( &accumulator, 493 buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 494 495 TEST_ASSERT( mbedtls_md( md_info, buf, MBEDTLS_ENTROPY_BLOCK_SIZE, 496 check_seed ) == 0 ); 497 498 // Second run for actual entropy (triggers mbedtls_entropy_update_nv_seed) 499 header[0] = MBEDTLS_ENTROPY_SOURCE_MANUAL; 500 TEST_ASSERT( mbedtls_md_update( &accumulator, header, 2 ) == 0 ); 501 TEST_ASSERT( mbedtls_md_update( &accumulator, 502 empty, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 503 504 header[0] = 0; 505 TEST_ASSERT( mbedtls_md_update( &accumulator, header, 2 ) == 0 ); 506 TEST_ASSERT( mbedtls_md_update( &accumulator, 507 check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 508 TEST_ASSERT( mbedtls_md_finish( &accumulator, buf ) == 0 ); 509 510 TEST_ASSERT( mbedtls_md( md_info, buf, MBEDTLS_ENTROPY_BLOCK_SIZE, 511 check_entropy ) == 0 ); 512 513 // Check result of both NV file and entropy received with the manual calculations 514 TEST_ASSERT( memcmp( check_seed, buffer_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 515 TEST_ASSERT( memcmp( check_entropy, entropy, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 ); 516 517exit: 518 mbedtls_md_free( &accumulator ); 519 mbedtls_entropy_free( &ctx ); 520 mbedtls_nv_seed_read = original_mbedtls_nv_seed_read; 521 mbedtls_nv_seed_write = original_mbedtls_nv_seed_write; 522} 523/* END_CASE */ 524 525/* BEGIN_CASE depends_on:ENTROPY_HAVE_STRONG:MBEDTLS_SELF_TEST */ 526void entropy_selftest( int result ) 527{ 528 TEST_ASSERT( mbedtls_entropy_self_test( 1 ) == result ); 529} 530/* END_CASE */ 531