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 TEST_ASSERT( mbedtls_ctr_drbg_seed( 49 &ctx, 50 mbedtls_test_entropy_func, entropy->x, 51 nonce->x, nonce->len ) == 0 ); 52 if( reseed_mode == RESEED_ALWAYS ) 53 mbedtls_ctr_drbg_set_prediction_resistance( 54 &ctx, 55 MBEDTLS_CTR_DRBG_PR_ON ); 56 57 if( reseed_mode == RESEED_FIRST ) 58 { 59 /* CTR_DRBG_Reseed(entropy[idx:idx+entropy->len], 60 * reseed[:reseed->len]) */ 61 TEST_ASSERT( mbedtls_ctr_drbg_reseed( 62 &ctx, 63 reseed->x, reseed->len ) == 0 ); 64 } 65 66 /* CTR_DRBG_Generate(result->len * 8 bits, add1[:add1->len]) -> buf */ 67 /* Then reseed if prediction resistance is enabled. */ 68 TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( 69 &ctx, 70 buf, result->len, 71 add1->x, add1->len ) == 0 ); 72 73 74 if( reseed_mode == RESEED_SECOND ) 75 { 76 /* CTR_DRBG_Reseed(entropy[idx:idx+entropy->len], 77 * reseed[:reseed->len]) */ 78 TEST_ASSERT( mbedtls_ctr_drbg_reseed( 79 &ctx, 80 reseed->x, reseed->len ) == 0 ); 81 } 82 83 /* CTR_DRBG_Generate(result->len * 8 bits, add2->x[:add2->len]) -> buf */ 84 /* Then reseed if prediction resistance is enabled. */ 85 TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( 86 &ctx, 87 buf, result->len, 88 add2->x, add2->len ) == 0 ); 89 TEST_ASSERT( memcmp( buf, result->x, result->len ) == 0 ); 90 91exit: 92 mbedtls_ctr_drbg_free( &ctx ); 93} 94 95/* END_HEADER */ 96 97/* BEGIN_DEPENDENCIES 98 * depends_on:MBEDTLS_CTR_DRBG_C 99 * END_DEPENDENCIES 100 */ 101 102/* BEGIN_CASE */ 103void ctr_drbg_special_behaviours( ) 104{ 105 mbedtls_ctr_drbg_context ctx; 106 unsigned char output[512]; 107 unsigned char additional[512]; 108 109 mbedtls_ctr_drbg_init( &ctx ); 110 memset( output, 0, sizeof( output ) ); 111 memset( additional, 0, sizeof( additional ) ); 112 113 TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( &ctx, 114 output, MBEDTLS_CTR_DRBG_MAX_REQUEST + 1, 115 additional, 16 ) == 116 MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG ); 117 TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( &ctx, 118 output, 16, 119 additional, MBEDTLS_CTR_DRBG_MAX_INPUT + 1 ) == 120 MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); 121 122 TEST_ASSERT( mbedtls_ctr_drbg_reseed( &ctx, additional, 123 MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + 1 ) == 124 MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); 125 126 mbedtls_ctr_drbg_set_entropy_len( &ctx, ~0 ); 127 TEST_ASSERT( mbedtls_ctr_drbg_reseed( &ctx, additional, 128 MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) == 129 MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); 130exit: 131 mbedtls_ctr_drbg_free( &ctx ); 132} 133/* END_CASE */ 134 135 136/* BEGIN_CASE */ 137void ctr_drbg_validate_no_reseed( data_t * add_init, data_t * entropy, 138 data_t * add1, data_t * add2, 139 data_t * result_string ) 140{ 141 data_t empty = { 0, 0 }; 142 ctr_drbg_validate_internal( RESEED_NEVER, add_init, 143 entropy->len, entropy, 144 &empty, add1, add2, 145 result_string ); 146 goto exit; // goto is needed to avoid warning ( no test assertions in func) 147} 148/* END_CASE */ 149 150/* BEGIN_CASE */ 151void ctr_drbg_validate_pr( data_t * add_init, data_t * entropy, 152 data_t * add1, data_t * add2, 153 data_t * result_string ) 154{ 155 data_t empty = { 0, 0 }; 156 ctr_drbg_validate_internal( RESEED_ALWAYS, add_init, 157 entropy->len / 3, entropy, 158 &empty, add1, add2, 159 result_string ); 160 goto exit; // goto is needed to avoid warning ( no test assertions in func) 161} 162/* END_CASE */ 163 164/* BEGIN_CASE */ 165void ctr_drbg_validate_reseed_between( data_t * add_init, data_t * entropy, 166 data_t * add1, data_t * add_reseed, 167 data_t * add2, data_t * result_string ) 168{ 169 ctr_drbg_validate_internal( RESEED_SECOND, add_init, 170 entropy->len / 2, entropy, 171 add_reseed, add1, add2, 172 result_string ); 173 goto exit; // goto is needed to avoid warning ( no test assertions in func) 174} 175/* END_CASE */ 176 177/* BEGIN_CASE */ 178void ctr_drbg_validate_reseed_first( data_t * add_init, data_t * entropy, 179 data_t * add1, data_t * add_reseed, 180 data_t * add2, data_t * result_string ) 181{ 182 ctr_drbg_validate_internal( RESEED_FIRST, add_init, 183 entropy->len / 2, entropy, 184 add_reseed, add1, add2, 185 result_string ); 186 goto exit; // goto is needed to avoid warning ( no test assertions in func) 187} 188/* END_CASE */ 189 190 191 192/* BEGIN_CASE */ 193void ctr_drbg_entropy_usage( ) 194{ 195 unsigned char out[16]; 196 unsigned char add[16]; 197 unsigned char entropy[1024]; 198 mbedtls_ctr_drbg_context ctx; 199 size_t i, reps = 10; 200 size_t last_idx; 201 202 mbedtls_ctr_drbg_init( &ctx ); 203 test_offset_idx = 0; 204 test_max_idx = sizeof( entropy ); 205 memset( entropy, 0, sizeof( entropy ) ); 206 memset( out, 0, sizeof( out ) ); 207 memset( add, 0, sizeof( add ) ); 208 209 /* Set reseed interval before seed */ 210 mbedtls_ctr_drbg_set_reseed_interval( &ctx, 2 * reps ); 211 212 /* Init must use entropy */ 213 last_idx = test_offset_idx; 214 TEST_ASSERT( mbedtls_ctr_drbg_seed( &ctx, mbedtls_test_entropy_func, entropy, NULL, 0 ) == 0 ); 215 TEST_ASSERT( last_idx < test_offset_idx ); 216 217 /* By default, PR is off, and reseed interval was set to 218 * 2 * reps so the next few calls should not use entropy */ 219 last_idx = test_offset_idx; 220 for( i = 0; i < reps; i++ ) 221 { 222 TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) - 4 ) == 0 ); 223 TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( &ctx, out, sizeof( out ) - 4, 224 add, sizeof( add ) ) == 0 ); 225 } 226 TEST_ASSERT( last_idx == test_offset_idx ); 227 228 /* While at it, make sure we didn't write past the requested length */ 229 TEST_ASSERT( out[sizeof( out ) - 4] == 0 ); 230 TEST_ASSERT( out[sizeof( out ) - 3] == 0 ); 231 TEST_ASSERT( out[sizeof( out ) - 2] == 0 ); 232 TEST_ASSERT( out[sizeof( out ) - 1] == 0 ); 233 234 /* There have been 2 * reps calls to random. The next call should reseed */ 235 TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 ); 236 TEST_ASSERT( last_idx < test_offset_idx ); 237 238 /* Set reseed interval after seed */ 239 mbedtls_ctr_drbg_set_reseed_interval( &ctx, 4 * reps + 1 ); 240 241 /* The next few calls should not reseed */ 242 last_idx = test_offset_idx; 243 for( i = 0; i < (2 * reps); i++ ) 244 { 245 TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 ); 246 TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( &ctx, out, sizeof( out ) , 247 add, sizeof( add ) ) == 0 ); 248 } 249 TEST_ASSERT( last_idx == test_offset_idx ); 250 251 /* Call update with too much data (sizeof entropy > MAX(_SEED)_INPUT). 252 * Make sure it's detected as an error and doesn't cause memory 253 * corruption. */ 254 TEST_ASSERT( mbedtls_ctr_drbg_update_ret( 255 &ctx, entropy, sizeof( entropy ) ) != 0 ); 256 257 /* Now enable PR, so the next few calls should all reseed */ 258 mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON ); 259 TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 ); 260 TEST_ASSERT( last_idx < test_offset_idx ); 261 262 /* Finally, check setting entropy_len */ 263 mbedtls_ctr_drbg_set_entropy_len( &ctx, 42 ); 264 last_idx = test_offset_idx; 265 TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 ); 266 TEST_ASSERT( test_offset_idx - last_idx == 42 ); 267 268 mbedtls_ctr_drbg_set_entropy_len( &ctx, 13 ); 269 last_idx = test_offset_idx; 270 TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 ); 271 TEST_ASSERT( test_offset_idx - last_idx == 13 ); 272 273exit: 274 mbedtls_ctr_drbg_free( &ctx ); 275} 276/* END_CASE */ 277 278/* BEGIN_CASE depends_on:MBEDTLS_FS_IO */ 279void ctr_drbg_seed_file( char * path, int ret ) 280{ 281 mbedtls_ctr_drbg_context ctx; 282 283 mbedtls_ctr_drbg_init( &ctx ); 284 285 TEST_ASSERT( mbedtls_ctr_drbg_seed( &ctx, rnd_std_rand, NULL, NULL, 0 ) == 0 ); 286 TEST_ASSERT( mbedtls_ctr_drbg_write_seed_file( &ctx, path ) == ret ); 287 TEST_ASSERT( mbedtls_ctr_drbg_update_seed_file( &ctx, path ) == ret ); 288 289exit: 290 mbedtls_ctr_drbg_free( &ctx ); 291} 292/* END_CASE */ 293 294/* BEGIN_CASE depends_on:MBEDTLS_SELF_TEST */ 295void ctr_drbg_selftest( ) 296{ 297 TEST_ASSERT( mbedtls_ctr_drbg_self_test( 1 ) == 0 ); 298} 299/* END_CASE */ 300