Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/mbedtls/library/entropy.c
9898 views
1
/*
2
* Entropy accumulator implementation
3
*
4
* Copyright The Mbed TLS Contributors
5
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6
*/
7
8
#include "common.h"
9
10
#if defined(MBEDTLS_ENTROPY_C)
11
12
#include "mbedtls/entropy.h"
13
#include "entropy_poll.h"
14
#include "mbedtls/platform_util.h"
15
#include "mbedtls/error.h"
16
17
#include <string.h>
18
19
#if defined(MBEDTLS_FS_IO)
20
#include <stdio.h>
21
#endif
22
23
#include "mbedtls/platform.h"
24
25
#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */
26
27
void mbedtls_entropy_init(mbedtls_entropy_context *ctx)
28
{
29
ctx->source_count = 0;
30
memset(ctx->source, 0, sizeof(ctx->source));
31
32
#if defined(MBEDTLS_THREADING_C)
33
mbedtls_mutex_init(&ctx->mutex);
34
#endif
35
36
ctx->accumulator_started = 0;
37
mbedtls_md_init(&ctx->accumulator);
38
39
/* Reminder: Update ENTROPY_HAVE_STRONG in the test files
40
* when adding more strong entropy sources here. */
41
42
#if !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES)
43
#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
44
mbedtls_entropy_add_source(ctx, mbedtls_platform_entropy_poll, NULL,
45
MBEDTLS_ENTROPY_MIN_PLATFORM,
46
MBEDTLS_ENTROPY_SOURCE_STRONG);
47
#endif
48
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
49
mbedtls_entropy_add_source(ctx, mbedtls_hardware_poll, NULL,
50
MBEDTLS_ENTROPY_MIN_HARDWARE,
51
MBEDTLS_ENTROPY_SOURCE_STRONG);
52
#endif
53
#if defined(MBEDTLS_ENTROPY_NV_SEED)
54
mbedtls_entropy_add_source(ctx, mbedtls_nv_seed_poll, NULL,
55
MBEDTLS_ENTROPY_BLOCK_SIZE,
56
MBEDTLS_ENTROPY_SOURCE_STRONG);
57
ctx->initial_entropy_run = 0;
58
#endif
59
#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */
60
}
61
62
void mbedtls_entropy_free(mbedtls_entropy_context *ctx)
63
{
64
if (ctx == NULL) {
65
return;
66
}
67
68
/* If the context was already free, don't call free() again.
69
* This is important for mutexes which don't allow double-free. */
70
if (ctx->accumulator_started == -1) {
71
return;
72
}
73
74
#if defined(MBEDTLS_THREADING_C)
75
mbedtls_mutex_free(&ctx->mutex);
76
#endif
77
mbedtls_md_free(&ctx->accumulator);
78
#if defined(MBEDTLS_ENTROPY_NV_SEED)
79
ctx->initial_entropy_run = 0;
80
#endif
81
ctx->source_count = 0;
82
mbedtls_platform_zeroize(ctx->source, sizeof(ctx->source));
83
ctx->accumulator_started = -1;
84
}
85
86
int mbedtls_entropy_add_source(mbedtls_entropy_context *ctx,
87
mbedtls_entropy_f_source_ptr f_source, void *p_source,
88
size_t threshold, int strong)
89
{
90
int idx, ret = 0;
91
92
#if defined(MBEDTLS_THREADING_C)
93
if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {
94
return ret;
95
}
96
#endif
97
98
idx = ctx->source_count;
99
if (idx >= MBEDTLS_ENTROPY_MAX_SOURCES) {
100
ret = MBEDTLS_ERR_ENTROPY_MAX_SOURCES;
101
goto exit;
102
}
103
104
ctx->source[idx].f_source = f_source;
105
ctx->source[idx].p_source = p_source;
106
ctx->source[idx].threshold = threshold;
107
ctx->source[idx].strong = strong;
108
109
ctx->source_count++;
110
111
exit:
112
#if defined(MBEDTLS_THREADING_C)
113
if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {
114
return MBEDTLS_ERR_THREADING_MUTEX_ERROR;
115
}
116
#endif
117
118
return ret;
119
}
120
121
/*
122
* Entropy accumulator update
123
*/
124
static int entropy_update(mbedtls_entropy_context *ctx, unsigned char source_id,
125
const unsigned char *data, size_t len)
126
{
127
unsigned char header[2];
128
unsigned char tmp[MBEDTLS_ENTROPY_BLOCK_SIZE];
129
size_t use_len = len;
130
const unsigned char *p = data;
131
int ret = 0;
132
133
if (use_len > MBEDTLS_ENTROPY_BLOCK_SIZE) {
134
if ((ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD),
135
data, len, tmp)) != 0) {
136
goto cleanup;
137
}
138
p = tmp;
139
use_len = MBEDTLS_ENTROPY_BLOCK_SIZE;
140
}
141
142
header[0] = source_id;
143
header[1] = use_len & 0xFF;
144
145
/*
146
* Start the accumulator if this has not already happened. Note that
147
* it is sufficient to start the accumulator here only because all calls to
148
* gather entropy eventually execute this code.
149
*/
150
if (ctx->accumulator_started == 0) {
151
ret = mbedtls_md_setup(&ctx->accumulator,
152
mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), 0);
153
if (ret != 0) {
154
goto cleanup;
155
}
156
ret = mbedtls_md_starts(&ctx->accumulator);
157
if (ret != 0) {
158
goto cleanup;
159
}
160
ctx->accumulator_started = 1;
161
}
162
if ((ret = mbedtls_md_update(&ctx->accumulator, header, 2)) != 0) {
163
goto cleanup;
164
}
165
ret = mbedtls_md_update(&ctx->accumulator, p, use_len);
166
167
cleanup:
168
mbedtls_platform_zeroize(tmp, sizeof(tmp));
169
170
return ret;
171
}
172
173
int mbedtls_entropy_update_manual(mbedtls_entropy_context *ctx,
174
const unsigned char *data, size_t len)
175
{
176
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
177
178
#if defined(MBEDTLS_THREADING_C)
179
if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {
180
return ret;
181
}
182
#endif
183
184
ret = entropy_update(ctx, MBEDTLS_ENTROPY_SOURCE_MANUAL, data, len);
185
186
#if defined(MBEDTLS_THREADING_C)
187
if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {
188
return MBEDTLS_ERR_THREADING_MUTEX_ERROR;
189
}
190
#endif
191
192
return ret;
193
}
194
195
/*
196
* Run through the different sources to add entropy to our accumulator
197
*/
198
static int entropy_gather_internal(mbedtls_entropy_context *ctx)
199
{
200
int ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
201
int i;
202
int have_one_strong = 0;
203
unsigned char buf[MBEDTLS_ENTROPY_MAX_GATHER];
204
size_t olen;
205
206
if (ctx->source_count == 0) {
207
return MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED;
208
}
209
210
/*
211
* Run through our entropy sources
212
*/
213
for (i = 0; i < ctx->source_count; i++) {
214
if (ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG) {
215
have_one_strong = 1;
216
}
217
218
olen = 0;
219
if ((ret = ctx->source[i].f_source(ctx->source[i].p_source,
220
buf, MBEDTLS_ENTROPY_MAX_GATHER, &olen)) != 0) {
221
goto cleanup;
222
}
223
224
/*
225
* Add if we actually gathered something
226
*/
227
if (olen > 0) {
228
if ((ret = entropy_update(ctx, (unsigned char) i,
229
buf, olen)) != 0) {
230
return ret;
231
}
232
ctx->source[i].size += olen;
233
}
234
}
235
236
if (have_one_strong == 0) {
237
ret = MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE;
238
}
239
240
cleanup:
241
mbedtls_platform_zeroize(buf, sizeof(buf));
242
243
return ret;
244
}
245
246
/*
247
* Thread-safe wrapper for entropy_gather_internal()
248
*/
249
int mbedtls_entropy_gather(mbedtls_entropy_context *ctx)
250
{
251
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
252
253
#if defined(MBEDTLS_THREADING_C)
254
if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {
255
return ret;
256
}
257
#endif
258
259
ret = entropy_gather_internal(ctx);
260
261
#if defined(MBEDTLS_THREADING_C)
262
if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {
263
return MBEDTLS_ERR_THREADING_MUTEX_ERROR;
264
}
265
#endif
266
267
return ret;
268
}
269
270
int mbedtls_entropy_func(void *data, unsigned char *output, size_t len)
271
{
272
int ret, count = 0, i, thresholds_reached;
273
size_t strong_size;
274
mbedtls_entropy_context *ctx = (mbedtls_entropy_context *) data;
275
unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
276
277
if (len > MBEDTLS_ENTROPY_BLOCK_SIZE) {
278
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
279
}
280
281
#if defined(MBEDTLS_ENTROPY_NV_SEED)
282
/* Update the NV entropy seed before generating any entropy for outside
283
* use.
284
*/
285
if (ctx->initial_entropy_run == 0) {
286
ctx->initial_entropy_run = 1;
287
if ((ret = mbedtls_entropy_update_nv_seed(ctx)) != 0) {
288
return ret;
289
}
290
}
291
#endif
292
293
#if defined(MBEDTLS_THREADING_C)
294
if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {
295
return ret;
296
}
297
#endif
298
299
/*
300
* Always gather extra entropy before a call
301
*/
302
do {
303
if (count++ > ENTROPY_MAX_LOOP) {
304
ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
305
goto exit;
306
}
307
308
if ((ret = entropy_gather_internal(ctx)) != 0) {
309
goto exit;
310
}
311
312
thresholds_reached = 1;
313
strong_size = 0;
314
for (i = 0; i < ctx->source_count; i++) {
315
if (ctx->source[i].size < ctx->source[i].threshold) {
316
thresholds_reached = 0;
317
}
318
if (ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG) {
319
strong_size += ctx->source[i].size;
320
}
321
}
322
} while (!thresholds_reached || strong_size < MBEDTLS_ENTROPY_BLOCK_SIZE);
323
324
memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);
325
326
/*
327
* Note that at this stage it is assumed that the accumulator was started
328
* in a previous call to entropy_update(). If this is not guaranteed, the
329
* code below will fail.
330
*/
331
if ((ret = mbedtls_md_finish(&ctx->accumulator, buf)) != 0) {
332
goto exit;
333
}
334
335
/*
336
* Reset accumulator and counters and recycle existing entropy
337
*/
338
mbedtls_md_free(&ctx->accumulator);
339
mbedtls_md_init(&ctx->accumulator);
340
ret = mbedtls_md_setup(&ctx->accumulator,
341
mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), 0);
342
if (ret != 0) {
343
goto exit;
344
}
345
ret = mbedtls_md_starts(&ctx->accumulator);
346
if (ret != 0) {
347
goto exit;
348
}
349
if ((ret = mbedtls_md_update(&ctx->accumulator, buf,
350
MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) {
351
goto exit;
352
}
353
354
/*
355
* Perform second hashing on entropy
356
*/
357
if ((ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD),
358
buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf)) != 0) {
359
goto exit;
360
}
361
362
for (i = 0; i < ctx->source_count; i++) {
363
ctx->source[i].size = 0;
364
}
365
366
memcpy(output, buf, len);
367
368
ret = 0;
369
370
exit:
371
mbedtls_platform_zeroize(buf, sizeof(buf));
372
373
#if defined(MBEDTLS_THREADING_C)
374
if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {
375
return MBEDTLS_ERR_THREADING_MUTEX_ERROR;
376
}
377
#endif
378
379
return ret;
380
}
381
382
#if defined(MBEDTLS_ENTROPY_NV_SEED)
383
int mbedtls_entropy_update_nv_seed(mbedtls_entropy_context *ctx)
384
{
385
int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
386
unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
387
388
/* Read new seed and write it to NV */
389
if ((ret = mbedtls_entropy_func(ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) {
390
return ret;
391
}
392
393
if (mbedtls_nv_seed_write(buf, MBEDTLS_ENTROPY_BLOCK_SIZE) < 0) {
394
return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
395
}
396
397
/* Manually update the remaining stream with a separator value to diverge */
398
memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);
399
ret = mbedtls_entropy_update_manual(ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE);
400
401
return ret;
402
}
403
#endif /* MBEDTLS_ENTROPY_NV_SEED */
404
405
#if defined(MBEDTLS_FS_IO)
406
int mbedtls_entropy_write_seed_file(mbedtls_entropy_context *ctx, const char *path)
407
{
408
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
409
FILE *f = NULL;
410
unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
411
412
if ((ret = mbedtls_entropy_func(ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) {
413
ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
414
goto exit;
415
}
416
417
if ((f = fopen(path, "wb")) == NULL) {
418
ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
419
goto exit;
420
}
421
422
/* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
423
mbedtls_setbuf(f, NULL);
424
425
if (fwrite(buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f) != MBEDTLS_ENTROPY_BLOCK_SIZE) {
426
ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
427
goto exit;
428
}
429
430
ret = 0;
431
432
exit:
433
mbedtls_platform_zeroize(buf, sizeof(buf));
434
435
if (f != NULL) {
436
fclose(f);
437
}
438
439
return ret;
440
}
441
442
int mbedtls_entropy_update_seed_file(mbedtls_entropy_context *ctx, const char *path)
443
{
444
int ret = 0;
445
FILE *f;
446
size_t n;
447
unsigned char buf[MBEDTLS_ENTROPY_MAX_SEED_SIZE];
448
449
if ((f = fopen(path, "rb")) == NULL) {
450
return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
451
}
452
453
/* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
454
mbedtls_setbuf(f, NULL);
455
456
fseek(f, 0, SEEK_END);
457
n = (size_t) ftell(f);
458
fseek(f, 0, SEEK_SET);
459
460
if (n > MBEDTLS_ENTROPY_MAX_SEED_SIZE) {
461
n = MBEDTLS_ENTROPY_MAX_SEED_SIZE;
462
}
463
464
if (fread(buf, 1, n, f) != n) {
465
ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
466
} else {
467
ret = mbedtls_entropy_update_manual(ctx, buf, n);
468
}
469
470
fclose(f);
471
472
mbedtls_platform_zeroize(buf, sizeof(buf));
473
474
if (ret != 0) {
475
return ret;
476
}
477
478
return mbedtls_entropy_write_seed_file(ctx, path);
479
}
480
#endif /* MBEDTLS_FS_IO */
481
482
#if defined(MBEDTLS_SELF_TEST)
483
/*
484
* Dummy source function
485
*/
486
static int entropy_dummy_source(void *data, unsigned char *output,
487
size_t len, size_t *olen)
488
{
489
((void) data);
490
491
memset(output, 0x2a, len);
492
*olen = len;
493
494
return 0;
495
}
496
497
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
498
499
static int mbedtls_entropy_source_self_test_gather(unsigned char *buf, size_t buf_len)
500
{
501
int ret = 0;
502
size_t entropy_len = 0;
503
size_t olen = 0;
504
size_t attempts = buf_len;
505
506
while (attempts > 0 && entropy_len < buf_len) {
507
if ((ret = mbedtls_hardware_poll(NULL, buf + entropy_len,
508
buf_len - entropy_len, &olen)) != 0) {
509
return ret;
510
}
511
512
entropy_len += olen;
513
attempts--;
514
}
515
516
if (entropy_len < buf_len) {
517
ret = 1;
518
}
519
520
return ret;
521
}
522
523
524
static int mbedtls_entropy_source_self_test_check_bits(const unsigned char *buf,
525
size_t buf_len)
526
{
527
unsigned char set = 0xFF;
528
unsigned char unset = 0x00;
529
size_t i;
530
531
for (i = 0; i < buf_len; i++) {
532
set &= buf[i];
533
unset |= buf[i];
534
}
535
536
return set == 0xFF || unset == 0x00;
537
}
538
539
/*
540
* A test to ensure that the entropy sources are functioning correctly
541
* and there is no obvious failure. The test performs the following checks:
542
* - The entropy source is not providing only 0s (all bits unset) or 1s (all
543
* bits set).
544
* - The entropy source is not providing values in a pattern. Because the
545
* hardware could be providing data in an arbitrary length, this check polls
546
* the hardware entropy source twice and compares the result to ensure they
547
* are not equal.
548
* - The error code returned by the entropy source is not an error.
549
*/
550
int mbedtls_entropy_source_self_test(int verbose)
551
{
552
int ret = 0;
553
unsigned char buf0[2 * sizeof(unsigned long long int)];
554
unsigned char buf1[2 * sizeof(unsigned long long int)];
555
556
if (verbose != 0) {
557
mbedtls_printf(" ENTROPY_BIAS test: ");
558
}
559
560
memset(buf0, 0x00, sizeof(buf0));
561
memset(buf1, 0x00, sizeof(buf1));
562
563
if ((ret = mbedtls_entropy_source_self_test_gather(buf0, sizeof(buf0))) != 0) {
564
goto cleanup;
565
}
566
if ((ret = mbedtls_entropy_source_self_test_gather(buf1, sizeof(buf1))) != 0) {
567
goto cleanup;
568
}
569
570
/* Make sure that the returned values are not all 0 or 1 */
571
if ((ret = mbedtls_entropy_source_self_test_check_bits(buf0, sizeof(buf0))) != 0) {
572
goto cleanup;
573
}
574
if ((ret = mbedtls_entropy_source_self_test_check_bits(buf1, sizeof(buf1))) != 0) {
575
goto cleanup;
576
}
577
578
/* Make sure that the entropy source is not returning values in a
579
* pattern */
580
ret = memcmp(buf0, buf1, sizeof(buf0)) == 0;
581
582
cleanup:
583
if (verbose != 0) {
584
if (ret != 0) {
585
mbedtls_printf("failed\n");
586
} else {
587
mbedtls_printf("passed\n");
588
}
589
590
mbedtls_printf("\n");
591
}
592
593
return ret != 0;
594
}
595
596
#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */
597
598
/*
599
* The actual entropy quality is hard to test, but we can at least
600
* test that the functions don't cause errors and write the correct
601
* amount of data to buffers.
602
*/
603
int mbedtls_entropy_self_test(int verbose)
604
{
605
int ret = 1;
606
mbedtls_entropy_context ctx;
607
unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 };
608
unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 };
609
size_t i, j;
610
611
if (verbose != 0) {
612
mbedtls_printf(" ENTROPY test: ");
613
}
614
615
mbedtls_entropy_init(&ctx);
616
617
/* First do a gather to make sure we have default sources */
618
if ((ret = mbedtls_entropy_gather(&ctx)) != 0) {
619
goto cleanup;
620
}
621
622
ret = mbedtls_entropy_add_source(&ctx, entropy_dummy_source, NULL, 16,
623
MBEDTLS_ENTROPY_SOURCE_WEAK);
624
if (ret != 0) {
625
goto cleanup;
626
}
627
628
if ((ret = mbedtls_entropy_update_manual(&ctx, buf, sizeof(buf))) != 0) {
629
goto cleanup;
630
}
631
632
/*
633
* To test that mbedtls_entropy_func writes correct number of bytes:
634
* - use the whole buffer and rely on ASan to detect overruns
635
* - collect entropy 8 times and OR the result in an accumulator:
636
* any byte should then be 0 with probably 2^(-64), so requiring
637
* each of the 32 or 64 bytes to be non-zero has a false failure rate
638
* of at most 2^(-58) which is acceptable.
639
*/
640
for (i = 0; i < 8; i++) {
641
if ((ret = mbedtls_entropy_func(&ctx, buf, sizeof(buf))) != 0) {
642
goto cleanup;
643
}
644
645
for (j = 0; j < sizeof(buf); j++) {
646
acc[j] |= buf[j];
647
}
648
}
649
650
for (j = 0; j < sizeof(buf); j++) {
651
if (acc[j] == 0) {
652
ret = 1;
653
goto cleanup;
654
}
655
}
656
657
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
658
if ((ret = mbedtls_entropy_source_self_test(0)) != 0) {
659
goto cleanup;
660
}
661
#endif
662
663
cleanup:
664
mbedtls_entropy_free(&ctx);
665
666
if (verbose != 0) {
667
if (ret != 0) {
668
mbedtls_printf("failed\n");
669
} else {
670
mbedtls_printf("passed\n");
671
}
672
673
mbedtls_printf("\n");
674
}
675
676
return ret != 0;
677
}
678
#endif /* MBEDTLS_SELF_TEST */
679
680
#endif /* MBEDTLS_ENTROPY_C */
681
682