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