1/* BEGIN_HEADER */ 2#include "mbedtls/entropy.h" 3#include "mbedtls/ctr_drbg.h" 4#include "string.h" 5 6/* Modes for ctr_drbg_validate */ 7enum reseed_mode 8{ 9 RESEED_NEVER, /* never reseed */ 10 RESEED_FIRST, /* instantiate, reseed, generate, generate */ 11 RESEED_SECOND, /* instantiate, generate, reseed, generate */ 12 RESEED_ALWAYS /* prediction resistance, no explicit reseed */ 13}; 14 15static size_t test_offset_idx = 0; 16static size_t test_max_idx = 0; 17static int mbedtls_test_entropy_func( void *data, unsigned char *buf, size_t len ) 18{ 19 const unsigned char *p = (unsigned char *) data; 20 if( test_offset_idx + len > test_max_idx ) 21 return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); 22 memcpy( buf, p + test_offset_idx, len ); 23 test_offset_idx += len; 24 return( 0 ); 25} 26 27static void ctr_drbg_validate_internal( int reseed_mode, data_t * nonce, 28 int entropy_len_arg, data_t * entropy, 29 data_t * reseed, 30 data_t * add1, data_t * add2, 31 data_t * result ) 32{ 33 mbedtls_ctr_drbg_context ctx; 34 unsigned char buf[64]; 35 36 size_t entropy_chunk_len = (size_t) entropy_len_arg; 37 38 TEST_ASSERT( entropy_chunk_len <= sizeof( buf ) ); 39 40 test_offset_idx = 0; 41 mbedtls_ctr_drbg_init( &ctx ); 42 43 test_max_idx = entropy->len; 44 45 /* CTR_DRBG_Instantiate(entropy[:entropy->len], nonce, perso, <ignored>) 46 * where nonce||perso = nonce[nonce->len] */ 47 mbedtls_ctr_drbg_set_entropy_len( &ctx, entropy_chunk_len ); 48 mbedtls_ctr_drbg_set_nonce_len( &ctx, 0 ); 49 TEST_ASSERT( mbedtls_ctr_drbg_seed( 50 &ctx, 51 mbedtls_test_entropy_func, entropy->x, 52 nonce->x, nonce->len ) == 0 ); 53 if( reseed_mode == RESEED_ALWAYS ) 54 mbedtls_ctr_drbg_set_prediction_resistance( 55 &ctx, 56 MBEDTLS_CTR_DRBG_PR_ON ); 57 58 if( reseed_mode == RESEED_FIRST ) 59 { 60 /* CTR_DRBG_Reseed(entropy[idx:idx+entropy->len], 61 * reseed[:reseed->len]) */ 62 TEST_ASSERT( mbedtls_ctr_drbg_reseed( 63 &ctx, 64 reseed->x, reseed->len ) == 0 ); 65 } 66 67 /* CTR_DRBG_Generate(result->len * 8 bits, add1[:add1->len]) -> buf */ 68 /* Then reseed if prediction resistance is enabled. */ 69 TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( 70 &ctx, 71 buf, result->len, 72 add1->x, add1->len ) == 0 ); 73 74 75 if( reseed_mode == RESEED_SECOND ) 76 { 77 /* CTR_DRBG_Reseed(entropy[idx:idx+entropy->len], 78 * reseed[:reseed->len]) */ 79 TEST_ASSERT( mbedtls_ctr_drbg_reseed( 80 &ctx, 81 reseed->x, reseed->len ) == 0 ); 82 } 83 84 /* CTR_DRBG_Generate(result->len * 8 bits, add2->x[:add2->len]) -> buf */ 85 /* Then reseed if prediction resistance is enabled. */ 86 TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( 87 &ctx, 88 buf, result->len, 89 add2->x, add2->len ) == 0 ); 90 TEST_ASSERT( memcmp( buf, result->x, result->len ) == 0 ); 91 92exit: 93 mbedtls_ctr_drbg_free( &ctx ); 94} 95 96/* END_HEADER */ 97 98/* BEGIN_DEPENDENCIES 99 * depends_on:MBEDTLS_CTR_DRBG_C 100 * END_DEPENDENCIES 101 */ 102 103/* BEGIN_CASE */ 104void ctr_drbg_special_behaviours( ) 105{ 106 mbedtls_ctr_drbg_context ctx; 107 unsigned char output[512]; 108 unsigned char additional[512]; 109 110 mbedtls_ctr_drbg_init( &ctx ); 111 memset( output, 0, sizeof( output ) ); 112 memset( additional, 0, sizeof( additional ) ); 113 114 TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( &ctx, 115 output, MBEDTLS_CTR_DRBG_MAX_REQUEST + 1, 116 additional, 16 ) == 117 MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG ); 118 TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( &ctx, 119 output, 16, 120 additional, MBEDTLS_CTR_DRBG_MAX_INPUT + 1 ) == 121 MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); 122 123 TEST_ASSERT( mbedtls_ctr_drbg_reseed( &ctx, additional, 124 MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + 1 ) == 125 MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); 126 127 mbedtls_ctr_drbg_set_entropy_len( &ctx, ~0 ); 128 TEST_ASSERT( mbedtls_ctr_drbg_reseed( &ctx, additional, 129 MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) == 130 MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); 131exit: 132 mbedtls_ctr_drbg_free( &ctx ); 133} 134/* END_CASE */ 135 136 137/* BEGIN_CASE */ 138void ctr_drbg_validate_no_reseed( data_t * add_init, data_t * entropy, 139 data_t * add1, data_t * add2, 140 data_t * result_string ) 141{ 142 data_t empty = { 0, 0 }; 143 ctr_drbg_validate_internal( RESEED_NEVER, add_init, 144 entropy->len, entropy, 145 &empty, add1, add2, 146 result_string ); 147 goto exit; // goto is needed to avoid warning ( no test assertions in func) 148} 149/* END_CASE */ 150 151/* BEGIN_CASE */ 152void ctr_drbg_validate_pr( data_t * add_init, data_t * entropy, 153 data_t * add1, data_t * add2, 154 data_t * result_string ) 155{ 156 data_t empty = { 0, 0 }; 157 ctr_drbg_validate_internal( RESEED_ALWAYS, add_init, 158 entropy->len / 3, entropy, 159 &empty, add1, add2, 160 result_string ); 161 goto exit; // goto is needed to avoid warning ( no test assertions in func) 162} 163/* END_CASE */ 164 165/* BEGIN_CASE */ 166void ctr_drbg_validate_reseed_between( data_t * add_init, data_t * entropy, 167 data_t * add1, data_t * add_reseed, 168 data_t * add2, data_t * result_string ) 169{ 170 ctr_drbg_validate_internal( RESEED_SECOND, add_init, 171 entropy->len / 2, entropy, 172 add_reseed, add1, add2, 173 result_string ); 174 goto exit; // goto is needed to avoid warning ( no test assertions in func) 175} 176/* END_CASE */ 177 178/* BEGIN_CASE */ 179void ctr_drbg_validate_reseed_first( data_t * add_init, data_t * entropy, 180 data_t * add1, data_t * add_reseed, 181 data_t * add2, data_t * result_string ) 182{ 183 ctr_drbg_validate_internal( RESEED_FIRST, add_init, 184 entropy->len / 2, entropy, 185 add_reseed, add1, add2, 186 result_string ); 187 goto exit; // goto is needed to avoid warning ( no test assertions in func) 188} 189/* END_CASE */ 190 191/* BEGIN_CASE */ 192void ctr_drbg_entropy_strength( int expected_bit_strength ) 193{ 194 unsigned char entropy[/*initial entropy*/ MBEDTLS_CTR_DRBG_ENTROPY_LEN + 195 /*nonce*/ MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN + 196 /*reseed*/ MBEDTLS_CTR_DRBG_ENTROPY_LEN]; 197 mbedtls_ctr_drbg_context ctx; 198 size_t last_idx; 199 size_t byte_strength = expected_bit_strength / 8; 200 201 mbedtls_ctr_drbg_init( &ctx ); 202 test_offset_idx = 0; 203 test_max_idx = sizeof( entropy ); 204 memset( entropy, 0, sizeof( entropy ) ); 205 206 /* The initial seeding must grab at least byte_strength bytes of entropy 207 * for the entropy input and byte_strength/2 bytes for a nonce. */ 208 TEST_ASSERT( mbedtls_ctr_drbg_seed( &ctx, 209 mbedtls_test_entropy_func, entropy, 210 NULL, 0 ) == 0 ); 211 TEST_ASSERT( test_offset_idx >= ( byte_strength * 3 + 1 ) / 2 ); 212 last_idx = test_offset_idx; 213 214 /* A reseed must grab at least byte_strength bytes of entropy. */ 215 TEST_ASSERT( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) == 0 ); 216 TEST_ASSERT( test_offset_idx - last_idx >= byte_strength ); 217 218exit: 219 mbedtls_ctr_drbg_free( &ctx ); 220} 221/* END_CASE */ 222 223/* BEGIN_CASE */ 224void ctr_drbg_entropy_usage( int entropy_nonce_len ) 225{ 226 unsigned char out[16]; 227 unsigned char add[16]; 228 unsigned char entropy[1024]; 229 mbedtls_ctr_drbg_context ctx; 230 size_t i, reps = 10; 231 size_t expected_idx = 0; 232 233 mbedtls_ctr_drbg_init( &ctx ); 234 test_offset_idx = 0; 235 test_max_idx = sizeof( entropy ); 236 memset( entropy, 0, sizeof( entropy ) ); 237 memset( out, 0, sizeof( out ) ); 238 memset( add, 0, sizeof( add ) ); 239 240 if( entropy_nonce_len >= 0 ) 241 TEST_ASSERT( mbedtls_ctr_drbg_set_nonce_len( &ctx, entropy_nonce_len ) == 0 ); 242 243 /* Set reseed interval before seed */ 244 mbedtls_ctr_drbg_set_reseed_interval( &ctx, 2 * reps ); 245 246 /* Init must use entropy */ 247 TEST_ASSERT( mbedtls_ctr_drbg_seed( &ctx, mbedtls_test_entropy_func, entropy, NULL, 0 ) == 0 ); 248 expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_LEN; 249 if( entropy_nonce_len >= 0 ) 250 expected_idx += entropy_nonce_len; 251 else 252 expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN; 253 TEST_EQUAL( test_offset_idx, expected_idx ); 254 255 /* By default, PR is off, and reseed interval was set to 256 * 2 * reps so the next few calls should not use entropy */ 257 for( i = 0; i < reps; i++ ) 258 { 259 TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) - 4 ) == 0 ); 260 TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( &ctx, out, sizeof( out ) - 4, 261 add, sizeof( add ) ) == 0 ); 262 } 263 TEST_EQUAL( test_offset_idx, expected_idx ); 264 265 /* While at it, make sure we didn't write past the requested length */ 266 TEST_ASSERT( out[sizeof( out ) - 4] == 0 ); 267 TEST_ASSERT( out[sizeof( out ) - 3] == 0 ); 268 TEST_ASSERT( out[sizeof( out ) - 2] == 0 ); 269 TEST_ASSERT( out[sizeof( out ) - 1] == 0 ); 270 271 /* There have been 2 * reps calls to random. The next call should reseed */ 272 TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 ); 273 expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_LEN; 274 TEST_EQUAL( test_offset_idx, expected_idx ); 275 276 /* Set reseed interval after seed */ 277 mbedtls_ctr_drbg_set_reseed_interval( &ctx, 4 * reps + 1 ); 278 279 /* The next few calls should not reseed */ 280 for( i = 0; i < (2 * reps); i++ ) 281 { 282 TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 ); 283 TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( &ctx, out, sizeof( out ) , 284 add, sizeof( add ) ) == 0 ); 285 } 286 TEST_EQUAL( test_offset_idx, expected_idx ); 287 288 /* Call update with too much data (sizeof entropy > MAX(_SEED)_INPUT). 289 * Make sure it's detected as an error and doesn't cause memory 290 * corruption. */ 291 TEST_ASSERT( mbedtls_ctr_drbg_update( 292 &ctx, entropy, sizeof( entropy ) ) != 0 ); 293 294 /* Now enable PR, so the next few calls should all reseed */ 295 mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON ); 296 TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 ); 297 expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_LEN; 298 TEST_EQUAL( test_offset_idx, expected_idx ); 299 300 /* Finally, check setting entropy_len */ 301 mbedtls_ctr_drbg_set_entropy_len( &ctx, 42 ); 302 TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 ); 303 expected_idx += 42; 304 TEST_EQUAL( test_offset_idx, expected_idx ); 305 306 mbedtls_ctr_drbg_set_entropy_len( &ctx, 13 ); 307 TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 ); 308 expected_idx += 13; 309 TEST_EQUAL( test_offset_idx, expected_idx ); 310 311exit: 312 mbedtls_ctr_drbg_free( &ctx ); 313} 314/* END_CASE */ 315 316/* BEGIN_CASE depends_on:MBEDTLS_FS_IO */ 317void ctr_drbg_seed_file( char * path, int ret ) 318{ 319 mbedtls_ctr_drbg_context ctx; 320 321 mbedtls_ctr_drbg_init( &ctx ); 322 323 TEST_ASSERT( mbedtls_ctr_drbg_seed( &ctx, mbedtls_test_rnd_std_rand, 324 NULL, NULL, 0 ) == 0 ); 325 TEST_ASSERT( mbedtls_ctr_drbg_write_seed_file( &ctx, path ) == ret ); 326 TEST_ASSERT( mbedtls_ctr_drbg_update_seed_file( &ctx, path ) == ret ); 327 328exit: 329 mbedtls_ctr_drbg_free( &ctx ); 330} 331/* END_CASE */ 332 333/* BEGIN_CASE depends_on:MBEDTLS_SELF_TEST */ 334void ctr_drbg_selftest( ) 335{ 336 TEST_ASSERT( mbedtls_ctr_drbg_self_test( 1 ) == 0 ); 337} 338/* END_CASE */ 339