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 RESEED_NEVER, /* never reseed */ 9 RESEED_FIRST, /* instantiate, reseed, generate, generate */ 10 RESEED_SECOND, /* instantiate, generate, reseed, generate */ 11 RESEED_ALWAYS /* prediction resistance, no explicit reseed */ 12}; 13 14static size_t test_offset_idx = 0; 15static size_t test_max_idx = 0; 16static int mbedtls_test_entropy_func(void *data, unsigned char *buf, size_t len) 17{ 18 const unsigned char *p = (unsigned char *) data; 19 if (test_offset_idx + len > test_max_idx) { 20 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 21 } 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 59 if (reseed_mode == RESEED_FIRST) { 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 /* 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/* BEGIN_CASE */ 191void ctr_drbg_entropy_strength(int expected_bit_strength) 192{ 193 unsigned char entropy[/*initial entropy*/ MBEDTLS_CTR_DRBG_ENTROPY_LEN + 194 /*nonce*/ MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN + 195 /*reseed*/ MBEDTLS_CTR_DRBG_ENTROPY_LEN]; 196 mbedtls_ctr_drbg_context ctx; 197 size_t last_idx; 198 size_t byte_strength = expected_bit_strength / 8; 199 200 mbedtls_ctr_drbg_init(&ctx); 201 test_offset_idx = 0; 202 test_max_idx = sizeof(entropy); 203 memset(entropy, 0, sizeof(entropy)); 204 205 /* The initial seeding must grab at least byte_strength bytes of entropy 206 * for the entropy input and byte_strength/2 bytes for a nonce. */ 207 TEST_ASSERT(mbedtls_ctr_drbg_seed(&ctx, 208 mbedtls_test_entropy_func, entropy, 209 NULL, 0) == 0); 210 TEST_ASSERT(test_offset_idx >= (byte_strength * 3 + 1) / 2); 211 last_idx = test_offset_idx; 212 213 /* A reseed must grab at least byte_strength bytes of entropy. */ 214 TEST_ASSERT(mbedtls_ctr_drbg_reseed(&ctx, NULL, 0) == 0); 215 TEST_ASSERT(test_offset_idx - last_idx >= byte_strength); 216 217exit: 218 mbedtls_ctr_drbg_free(&ctx); 219} 220/* END_CASE */ 221 222/* BEGIN_CASE */ 223void ctr_drbg_entropy_usage(int entropy_nonce_len) 224{ 225 unsigned char out[16]; 226 unsigned char add[16]; 227 unsigned char entropy[1024]; 228 mbedtls_ctr_drbg_context ctx; 229 size_t i, reps = 10; 230 size_t expected_idx = 0; 231 232 mbedtls_ctr_drbg_init(&ctx); 233 test_offset_idx = 0; 234 test_max_idx = sizeof(entropy); 235 memset(entropy, 0, sizeof(entropy)); 236 memset(out, 0, sizeof(out)); 237 memset(add, 0, sizeof(add)); 238 239 if (entropy_nonce_len >= 0) { 240 TEST_ASSERT(mbedtls_ctr_drbg_set_nonce_len(&ctx, entropy_nonce_len) == 0); 241 } 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 } 254 TEST_EQUAL(test_offset_idx, expected_idx); 255 256 /* By default, PR is off, and reseed interval was set to 257 * 2 * reps so the next few calls should not use entropy */ 258 for (i = 0; i < reps; i++) { 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 TEST_ASSERT(mbedtls_ctr_drbg_random(&ctx, out, sizeof(out)) == 0); 282 TEST_ASSERT(mbedtls_ctr_drbg_random_with_add(&ctx, out, sizeof(out), 283 add, sizeof(add)) == 0); 284 } 285 TEST_EQUAL(test_offset_idx, expected_idx); 286 287 /* Call update with too much data (sizeof(entropy) > MAX(_SEED)_INPUT). 288 * Make sure it's detected as an error and doesn't cause memory 289 * corruption. */ 290 TEST_ASSERT(mbedtls_ctr_drbg_update( 291 &ctx, entropy, sizeof(entropy)) != 0); 292 293 /* Now enable PR, so the next few calls should all reseed */ 294 mbedtls_ctr_drbg_set_prediction_resistance(&ctx, MBEDTLS_CTR_DRBG_PR_ON); 295 TEST_ASSERT(mbedtls_ctr_drbg_random(&ctx, out, sizeof(out)) == 0); 296 expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_LEN; 297 TEST_EQUAL(test_offset_idx, expected_idx); 298 299 /* Finally, check setting entropy_len */ 300 mbedtls_ctr_drbg_set_entropy_len(&ctx, 42); 301 TEST_ASSERT(mbedtls_ctr_drbg_random(&ctx, out, sizeof(out)) == 0); 302 expected_idx += 42; 303 TEST_EQUAL(test_offset_idx, expected_idx); 304 305 mbedtls_ctr_drbg_set_entropy_len(&ctx, 13); 306 TEST_ASSERT(mbedtls_ctr_drbg_random(&ctx, out, sizeof(out)) == 0); 307 expected_idx += 13; 308 TEST_EQUAL(test_offset_idx, expected_idx); 309 310exit: 311 mbedtls_ctr_drbg_free(&ctx); 312} 313/* END_CASE */ 314 315/* BEGIN_CASE depends_on:MBEDTLS_FS_IO */ 316void ctr_drbg_seed_file(char *path, int ret) 317{ 318 mbedtls_ctr_drbg_context ctx; 319 320 mbedtls_ctr_drbg_init(&ctx); 321 322 TEST_ASSERT(mbedtls_ctr_drbg_seed(&ctx, mbedtls_test_rnd_std_rand, 323 NULL, NULL, 0) == 0); 324 TEST_ASSERT(mbedtls_ctr_drbg_write_seed_file(&ctx, path) == ret); 325 TEST_ASSERT(mbedtls_ctr_drbg_update_seed_file(&ctx, path) == ret); 326 327exit: 328 mbedtls_ctr_drbg_free(&ctx); 329} 330/* END_CASE */ 331 332/* BEGIN_CASE depends_on:MBEDTLS_SELF_TEST */ 333void ctr_drbg_selftest() 334{ 335 TEST_ASSERT(mbedtls_ctr_drbg_self_test(1) == 0); 336} 337/* END_CASE */ 338