1/* BEGIN_HEADER */
2#include "mbedtls/entropy.h"
3#include "mbedtls/ctr_drbg.h"
4#include "string.h"
5#include "ctr.h"
6
7#if defined(MBEDTLS_THREADING_PTHREAD)
8#include "mbedtls/threading.h"
9#endif
10
11/* Modes for ctr_drbg_validate */
12enum reseed_mode {
13    RESEED_NEVER, /* never reseed */
14    RESEED_FIRST, /* instantiate, reseed, generate, generate */
15    RESEED_SECOND, /* instantiate, generate, reseed, generate */
16    RESEED_ALWAYS /* prediction resistance, no explicit reseed */
17};
18
19static size_t test_offset_idx = 0;
20static size_t test_max_idx  = 0;
21static int mbedtls_test_entropy_func(void *data, unsigned char *buf, size_t len)
22{
23    const unsigned char *p = (unsigned char *) data;
24    if (test_offset_idx + len > test_max_idx) {
25        return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
26    }
27    memcpy(buf, p + test_offset_idx, len);
28    test_offset_idx += len;
29    return 0;
30}
31
32static void ctr_drbg_validate_internal(int reseed_mode, data_t *nonce,
33                                       int entropy_len_arg, data_t *entropy,
34                                       data_t *reseed,
35                                       data_t *add1, data_t *add2,
36                                       data_t *result)
37{
38    mbedtls_ctr_drbg_context ctx;
39    mbedtls_ctr_drbg_init(&ctx);
40    unsigned char buf[64];
41
42    size_t entropy_chunk_len = (size_t) entropy_len_arg;
43    TEST_ASSERT(entropy_chunk_len <= sizeof(buf));
44
45    test_offset_idx = 0;
46    test_max_idx = entropy->len;
47
48    /* CTR_DRBG_Instantiate(entropy[:entropy->len], nonce, perso, <ignored>)
49     * where nonce||perso = nonce[nonce->len] */
50    mbedtls_ctr_drbg_set_entropy_len(&ctx, entropy_chunk_len);
51    mbedtls_ctr_drbg_set_nonce_len(&ctx, 0);
52    TEST_ASSERT(mbedtls_ctr_drbg_seed(
53                    &ctx,
54                    mbedtls_test_entropy_func, entropy->x,
55                    nonce->x, nonce->len) == 0);
56    if (reseed_mode == RESEED_ALWAYS) {
57        mbedtls_ctr_drbg_set_prediction_resistance(
58            &ctx,
59            MBEDTLS_CTR_DRBG_PR_ON);
60    }
61
62    if (reseed_mode == RESEED_FIRST) {
63        /* CTR_DRBG_Reseed(entropy[idx:idx+entropy->len],
64         *                 reseed[:reseed->len]) */
65        TEST_ASSERT(mbedtls_ctr_drbg_reseed(
66                        &ctx,
67                        reseed->x, reseed->len) == 0);
68    }
69
70    /* CTR_DRBG_Generate(result->len * 8 bits, add1[:add1->len]) -> buf */
71    /* Then reseed if prediction resistance is enabled. */
72    TEST_ASSERT(mbedtls_ctr_drbg_random_with_add(
73                    &ctx,
74                    buf, result->len,
75                    add1->x, add1->len) == 0);
76
77
78    if (reseed_mode == RESEED_SECOND) {
79        /* CTR_DRBG_Reseed(entropy[idx:idx+entropy->len],
80         *                 reseed[:reseed->len]) */
81        TEST_ASSERT(mbedtls_ctr_drbg_reseed(
82                        &ctx,
83                        reseed->x, reseed->len) == 0);
84    }
85
86    /* CTR_DRBG_Generate(result->len * 8 bits, add2->x[:add2->len]) -> buf */
87    /* Then reseed if prediction resistance is enabled. */
88    TEST_ASSERT(mbedtls_ctr_drbg_random_with_add(
89                    &ctx,
90                    buf, result->len,
91                    add2->x, add2->len) == 0);
92    TEST_ASSERT(memcmp(buf, result->x, result->len) == 0);
93
94exit:
95    mbedtls_ctr_drbg_free(&ctx);
96}
97
98static const int thread_random_reps = 10;
99void *thread_random_function(void *ctx)
100{
101    unsigned char out[16];
102    memset(out, 0, sizeof(out));
103
104    for (int i = 0; i < thread_random_reps; i++) {
105        TEST_EQUAL(mbedtls_ctr_drbg_random((mbedtls_ctr_drbg_context *) ctx, out, sizeof(out)), 0);
106    }
107
108exit:
109    return NULL;
110}
111/* END_HEADER */
112
113/* BEGIN_DEPENDENCIES
114 * depends_on:MBEDTLS_CTR_DRBG_C
115 * END_DEPENDENCIES
116 */
117
118/* BEGIN_CASE */
119void ctr_drbg_special_behaviours()
120{
121    mbedtls_ctr_drbg_context ctx;
122    unsigned char output[512];
123    unsigned char additional[512];
124
125    mbedtls_ctr_drbg_init(&ctx);
126    memset(output, 0, sizeof(output));
127    memset(additional, 0, sizeof(additional));
128
129    TEST_ASSERT(mbedtls_ctr_drbg_random_with_add(&ctx,
130                                                 output, MBEDTLS_CTR_DRBG_MAX_REQUEST + 1,
131                                                 additional, 16) ==
132                MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG);
133    TEST_ASSERT(mbedtls_ctr_drbg_random_with_add(&ctx,
134                                                 output, 16,
135                                                 additional, MBEDTLS_CTR_DRBG_MAX_INPUT + 1) ==
136                MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG);
137
138    TEST_ASSERT(mbedtls_ctr_drbg_reseed(&ctx, additional,
139                                        MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + 1) ==
140                MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG);
141
142    mbedtls_ctr_drbg_set_entropy_len(&ctx, ~0);
143    TEST_ASSERT(mbedtls_ctr_drbg_reseed(&ctx, additional,
144                                        MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) ==
145                MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG);
146exit:
147    mbedtls_ctr_drbg_free(&ctx);
148}
149/* END_CASE */
150
151
152/* BEGIN_CASE */
153void ctr_drbg_validate_no_reseed(data_t *add_init, data_t *entropy,
154                                 data_t *add1, data_t *add2,
155                                 data_t *result_string)
156{
157    data_t empty = { 0, 0 };
158    AES_PSA_INIT();
159    ctr_drbg_validate_internal(RESEED_NEVER, add_init,
160                               entropy->len, entropy,
161                               &empty, add1, add2,
162                               result_string);
163    AES_PSA_DONE();
164    goto exit; // goto is needed to avoid warning ( no test assertions in func)
165}
166/* END_CASE */
167
168/* BEGIN_CASE */
169void ctr_drbg_validate_pr(data_t *add_init, data_t *entropy,
170                          data_t *add1, data_t *add2,
171                          data_t *result_string)
172{
173    data_t empty = { 0, 0 };
174    AES_PSA_INIT();
175    ctr_drbg_validate_internal(RESEED_ALWAYS, add_init,
176                               entropy->len / 3, entropy,
177                               &empty, add1, add2,
178                               result_string);
179    AES_PSA_DONE();
180    goto exit; // goto is needed to avoid warning ( no test assertions in func)
181}
182/* END_CASE */
183
184/* BEGIN_CASE */
185void ctr_drbg_validate_reseed_between(data_t *add_init, data_t *entropy,
186                                      data_t *add1, data_t *add_reseed,
187                                      data_t *add2, data_t *result_string)
188{
189    AES_PSA_INIT();
190    ctr_drbg_validate_internal(RESEED_SECOND, add_init,
191                               entropy->len / 2, entropy,
192                               add_reseed, add1, add2,
193                               result_string);
194    AES_PSA_DONE();
195    goto exit; // goto is needed to avoid warning ( no test assertions in func)
196}
197/* END_CASE */
198
199/* BEGIN_CASE */
200void ctr_drbg_validate_reseed_first(data_t *add_init, data_t *entropy,
201                                    data_t *add1, data_t *add_reseed,
202                                    data_t *add2, data_t *result_string)
203{
204    AES_PSA_INIT();
205    ctr_drbg_validate_internal(RESEED_FIRST, add_init,
206                               entropy->len / 2, entropy,
207                               add_reseed, add1, add2,
208                               result_string);
209    AES_PSA_DONE();
210    goto exit; // goto is needed to avoid warning ( no test assertions in func)
211}
212/* END_CASE */
213
214/* BEGIN_CASE */
215void ctr_drbg_entropy_strength(int expected_bit_strength)
216{
217    unsigned char entropy[/*initial entropy*/ MBEDTLS_CTR_DRBG_ENTROPY_LEN +
218                          /*nonce*/ MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN +
219                          /*reseed*/ MBEDTLS_CTR_DRBG_ENTROPY_LEN];
220    mbedtls_ctr_drbg_context ctx;
221    size_t last_idx;
222    size_t byte_strength = expected_bit_strength / 8;
223
224    mbedtls_ctr_drbg_init(&ctx);
225
226    AES_PSA_INIT();
227    test_offset_idx = 0;
228    test_max_idx = sizeof(entropy);
229    memset(entropy, 0, sizeof(entropy));
230
231    /* The initial seeding must grab at least byte_strength bytes of entropy
232     * for the entropy input and byte_strength/2 bytes for a nonce. */
233    TEST_ASSERT(mbedtls_ctr_drbg_seed(&ctx,
234                                      mbedtls_test_entropy_func, entropy,
235                                      NULL, 0) == 0);
236    TEST_ASSERT(test_offset_idx >= (byte_strength * 3 + 1) / 2);
237    last_idx = test_offset_idx;
238
239    /* A reseed must grab at least byte_strength bytes of entropy. */
240    TEST_ASSERT(mbedtls_ctr_drbg_reseed(&ctx, NULL, 0) == 0);
241    TEST_ASSERT(test_offset_idx - last_idx >= byte_strength);
242
243exit:
244    mbedtls_ctr_drbg_free(&ctx);
245    AES_PSA_DONE();
246}
247/* END_CASE */
248
249/* BEGIN_CASE */
250void ctr_drbg_entropy_usage(int entropy_nonce_len)
251{
252    unsigned char out[16];
253    unsigned char add[16];
254    unsigned char entropy[1024];
255    mbedtls_ctr_drbg_context ctx;
256    size_t i, reps = 10;
257    size_t expected_idx = 0;
258
259    mbedtls_ctr_drbg_init(&ctx);
260
261    AES_PSA_INIT();
262
263    test_offset_idx = 0;
264    test_max_idx = sizeof(entropy);
265    memset(entropy, 0, sizeof(entropy));
266    memset(out, 0, sizeof(out));
267    memset(add, 0, sizeof(add));
268
269    if (entropy_nonce_len >= 0) {
270        TEST_ASSERT(mbedtls_ctr_drbg_set_nonce_len(&ctx, entropy_nonce_len) == 0);
271    }
272
273    /* Set reseed interval before seed */
274    mbedtls_ctr_drbg_set_reseed_interval(&ctx, 2 * reps);
275
276    /* Init must use entropy */
277    TEST_ASSERT(mbedtls_ctr_drbg_seed(&ctx, mbedtls_test_entropy_func, entropy, NULL, 0) == 0);
278    expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_LEN;
279    if (entropy_nonce_len >= 0) {
280        expected_idx += entropy_nonce_len;
281    } else {
282        expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN;
283    }
284    TEST_EQUAL(test_offset_idx, expected_idx);
285
286    /* By default, PR is off, and reseed interval was set to
287     * 2 * reps so the next few calls should not use entropy */
288    for (i = 0; i < reps; i++) {
289        TEST_ASSERT(mbedtls_ctr_drbg_random(&ctx, out, sizeof(out) - 4) == 0);
290        TEST_ASSERT(mbedtls_ctr_drbg_random_with_add(&ctx, out, sizeof(out) - 4,
291                                                     add, sizeof(add)) == 0);
292    }
293    TEST_EQUAL(test_offset_idx, expected_idx);
294
295    /* While at it, make sure we didn't write past the requested length */
296    TEST_ASSERT(out[sizeof(out) - 4] == 0);
297    TEST_ASSERT(out[sizeof(out) - 3] == 0);
298    TEST_ASSERT(out[sizeof(out) - 2] == 0);
299    TEST_ASSERT(out[sizeof(out) - 1] == 0);
300
301    /* There have been 2 * reps calls to random. The next call should reseed */
302    TEST_ASSERT(mbedtls_ctr_drbg_random(&ctx, out, sizeof(out)) == 0);
303    expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_LEN;
304    TEST_EQUAL(test_offset_idx, expected_idx);
305
306    /* Set reseed interval after seed */
307    mbedtls_ctr_drbg_set_reseed_interval(&ctx, 4 * reps + 1);
308
309    /* The next few calls should not reseed */
310    for (i = 0; i < (2 * reps); i++) {
311        TEST_ASSERT(mbedtls_ctr_drbg_random(&ctx, out, sizeof(out)) == 0);
312        TEST_ASSERT(mbedtls_ctr_drbg_random_with_add(&ctx, out, sizeof(out),
313                                                     add, sizeof(add)) == 0);
314    }
315    TEST_EQUAL(test_offset_idx, expected_idx);
316
317    /* Call update with too much data (sizeof(entropy) > MAX(_SEED)_INPUT).
318     * Make sure it's detected as an error and doesn't cause memory
319     * corruption. */
320    TEST_ASSERT(mbedtls_ctr_drbg_update(
321                    &ctx, entropy, sizeof(entropy)) != 0);
322
323    /* Now enable PR, so the next few calls should all reseed */
324    mbedtls_ctr_drbg_set_prediction_resistance(&ctx, MBEDTLS_CTR_DRBG_PR_ON);
325    TEST_ASSERT(mbedtls_ctr_drbg_random(&ctx, out, sizeof(out)) == 0);
326    expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_LEN;
327    TEST_EQUAL(test_offset_idx, expected_idx);
328
329    /* Finally, check setting entropy_len */
330    mbedtls_ctr_drbg_set_entropy_len(&ctx, 42);
331    TEST_ASSERT(mbedtls_ctr_drbg_random(&ctx, out, sizeof(out)) == 0);
332    expected_idx += 42;
333    TEST_EQUAL(test_offset_idx, expected_idx);
334
335    mbedtls_ctr_drbg_set_entropy_len(&ctx, 13);
336    TEST_ASSERT(mbedtls_ctr_drbg_random(&ctx, out, sizeof(out)) == 0);
337    expected_idx += 13;
338    TEST_EQUAL(test_offset_idx, expected_idx);
339
340exit:
341    mbedtls_ctr_drbg_free(&ctx);
342    AES_PSA_DONE();
343}
344/* END_CASE */
345
346/* BEGIN_CASE depends_on:MBEDTLS_THREADING_PTHREAD:!MBEDTLS_CTR_DRBG_USE_128_BIT_KEY:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */
347void ctr_drbg_threads(data_t *expected_result, int reseed, int arg_thread_count)
348{
349    size_t thread_count = (size_t) arg_thread_count;
350    mbedtls_test_thread_t *threads = NULL;
351
352    unsigned char out[16];
353    unsigned char *entropy = NULL;
354
355    const size_t n_random_calls = thread_count * thread_random_reps + 1;
356
357    /* This is a known-answer test, and although tests use a mock entropy
358     * function the input entropy length will still affect the output.
359     * We therefore need to pick a fixed entropy length, rather than using the
360     * default entropy length (MBEDTLS_CTR_DRBG_ENTROPY_LEN). We've chosen to
361     * use the default value of MBEDTLS_CTR_DRBG_ENTROPY_LEN for SHA-512,
362     * as this was the value used when the expected answers were calculated. */
363    const size_t entropy_len = 48;
364
365    AES_PSA_INIT();
366
367    TEST_CALLOC(threads, sizeof(mbedtls_test_thread_t) * thread_count);
368    memset(out, 0, sizeof(out));
369
370    mbedtls_ctr_drbg_context ctx;
371    mbedtls_ctr_drbg_init(&ctx);
372
373    test_offset_idx = 0;
374
375    /* Need to set a non-default fixed entropy len, to ensure same output across
376     * all configs - see above for details. */
377    mbedtls_ctr_drbg_set_entropy_len(&ctx, entropy_len);
378
379    if (reseed == 0) {
380        mbedtls_ctr_drbg_set_prediction_resistance(&ctx, MBEDTLS_CTR_DRBG_PR_OFF);
381        mbedtls_ctr_drbg_set_reseed_interval(&ctx, n_random_calls + 1);
382
383        TEST_CALLOC(entropy, entropy_len + MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN);
384        test_max_idx = entropy_len + MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN;
385    } else {
386        const size_t entropy_size = ((n_random_calls + 1) * entropy_len)
387                                    + MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN;
388
389        mbedtls_ctr_drbg_set_prediction_resistance(&ctx, MBEDTLS_CTR_DRBG_PR_ON);
390
391        TEST_CALLOC(entropy, entropy_size);
392        test_max_idx = entropy_size;
393    }
394
395    TEST_EQUAL(
396        mbedtls_ctr_drbg_seed(&ctx, mbedtls_test_entropy_func, entropy, NULL, 0),
397        0);
398
399    for (size_t i = 0; i < thread_count; i++) {
400        TEST_EQUAL(
401            mbedtls_test_thread_create(&threads[i],
402                                       thread_random_function, (void *) &ctx),
403            0);
404    }
405
406    for (size_t i = 0; i < thread_count; i++) {
407        TEST_EQUAL(mbedtls_test_thread_join(&threads[i]), 0);
408    }
409
410    /* Take a last output for comparing and thus verifying the DRBG state */
411    TEST_EQUAL(mbedtls_ctr_drbg_random(&ctx, out, sizeof(out)), 0);
412
413    TEST_MEMORY_COMPARE(out, sizeof(out), expected_result->x, expected_result->len);
414
415exit:
416    mbedtls_ctr_drbg_free(&ctx);
417    mbedtls_free(entropy);
418    mbedtls_free(threads);
419
420    AES_PSA_DONE();
421}
422/* END_CASE */
423
424/* BEGIN_CASE depends_on:MBEDTLS_FS_IO */
425void ctr_drbg_seed_file(char *path, int ret)
426{
427    mbedtls_ctr_drbg_context ctx;
428
429    mbedtls_ctr_drbg_init(&ctx);
430
431    AES_PSA_INIT();
432
433    TEST_ASSERT(mbedtls_ctr_drbg_seed(&ctx, mbedtls_test_rnd_std_rand,
434                                      NULL, NULL, 0) == 0);
435    TEST_ASSERT(mbedtls_ctr_drbg_write_seed_file(&ctx, path) == ret);
436    TEST_ASSERT(mbedtls_ctr_drbg_update_seed_file(&ctx, path) == ret);
437
438exit:
439    mbedtls_ctr_drbg_free(&ctx);
440    AES_PSA_DONE();
441}
442/* END_CASE */
443
444/* BEGIN_CASE depends_on:MBEDTLS_SELF_TEST */
445void ctr_drbg_selftest()
446{
447    AES_PSA_INIT();
448    TEST_ASSERT(mbedtls_ctr_drbg_self_test(1) == 0);
449    AES_PSA_DONE();
450}
451/* END_CASE */
452
453/* BEGIN_CASE */
454void ctr_increment_rollover()
455{
456    uint8_t c[16];
457    uint8_t r[16];
458
459    // test all increments from 2^n - 1 to 2^n (i.e. where we roll over into the next bit)
460    for (int n = 0; n <= 128; n++) {
461        memset(c, 0, 16);
462        memset(r, 0, 16);
463
464        // set least significant (highest address) n bits to 1, i.e. generate (2^n - 1)
465        for (int i = 0; i < n; i++) {
466            int bit = i % 8;
467            int byte = (i / 8);
468            c[15 - byte] |= 1 << bit;
469        }
470        // increment to get 2^n
471        mbedtls_ctr_increment_counter(c);
472
473        // now generate a reference result equal to 2^n - i.e. set only bit (n + 1)
474        // if n == 127, this will not set any bits (i.e. wraps to 0).
475        int bit = n % 8;
476        int byte = n / 8;
477        if (byte < 16) {
478            r[15 - byte] = 1 << bit;
479        }
480
481        TEST_MEMORY_COMPARE(c, 16, r, 16);
482    }
483
484    uint64_t lsb = 10, msb = 20;
485    MBEDTLS_PUT_UINT64_BE(msb, c, 0);
486    MBEDTLS_PUT_UINT64_BE(lsb, c, 8);
487    memcpy(r, c, 16);
488    mbedtls_ctr_increment_counter(c);
489    for (int i = 15; i >= 0; i--) {
490        r[i] += 1;
491        if (r[i] != 0) {
492            break;
493        }
494    }
495    TEST_MEMORY_COMPARE(c, 16, r, 16);
496}
497/* END_CASE */
498
499/* BEGIN_CASE */
500void ctr_increment(data_t *x)
501{
502    uint8_t c[16];
503    uint8_t r[16];
504
505    // initialise c and r from test argument
506    memset(c, 0, 16);
507    memcpy(c, x->x, x->len);
508    memcpy(r, c, 16);
509
510    // increment c
511    mbedtls_ctr_increment_counter(c);
512    // increment reference
513    for (int i = 15; i >= 0; i--) {
514        r[i] += 1;
515        if (r[i] != 0) {
516            break;
517        }
518    }
519
520    // test that mbedtls_ctr_increment_counter behaviour matches reference
521    TEST_MEMORY_COMPARE(c, 16, r, 16);
522}
523/* END_CASE */
524