/src/mbedtls/library/entropy.c
Line | Count | Source (jump to first uncovered line) |
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 | 10 | #define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */ |
26 | | |
27 | | void mbedtls_entropy_init(mbedtls_entropy_context *ctx) |
28 | 10 | { |
29 | 10 | ctx->source_count = 0; |
30 | 10 | memset(ctx->source, 0, sizeof(ctx->source)); |
31 | | |
32 | | #if defined(MBEDTLS_THREADING_C) |
33 | | mbedtls_mutex_init(&ctx->mutex); |
34 | | #endif |
35 | | |
36 | 10 | ctx->accumulator_started = 0; |
37 | 10 | 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 | 10 | #if !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) |
43 | 10 | #if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) |
44 | 10 | mbedtls_entropy_add_source(ctx, mbedtls_platform_entropy_poll, NULL, |
45 | 10 | MBEDTLS_ENTROPY_MIN_PLATFORM, |
46 | 10 | MBEDTLS_ENTROPY_SOURCE_STRONG); |
47 | 10 | #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 | 10 | #endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */ |
60 | 10 | } |
61 | | |
62 | | void mbedtls_entropy_free(mbedtls_entropy_context *ctx) |
63 | 0 | { |
64 | 0 | if (ctx == NULL) { |
65 | 0 | return; |
66 | 0 | } |
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 | 0 | if (ctx->accumulator_started == -1) { |
71 | 0 | return; |
72 | 0 | } |
73 | | |
74 | | #if defined(MBEDTLS_THREADING_C) |
75 | | mbedtls_mutex_free(&ctx->mutex); |
76 | | #endif |
77 | 0 | mbedtls_md_free(&ctx->accumulator); |
78 | | #if defined(MBEDTLS_ENTROPY_NV_SEED) |
79 | | ctx->initial_entropy_run = 0; |
80 | | #endif |
81 | 0 | ctx->source_count = 0; |
82 | 0 | mbedtls_platform_zeroize(ctx->source, sizeof(ctx->source)); |
83 | 0 | ctx->accumulator_started = -1; |
84 | 0 | } |
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 | 10 | { |
90 | 10 | 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 | 10 | idx = ctx->source_count; |
99 | 10 | if (idx >= MBEDTLS_ENTROPY_MAX_SOURCES) { |
100 | 0 | ret = MBEDTLS_ERR_ENTROPY_MAX_SOURCES; |
101 | 0 | goto exit; |
102 | 0 | } |
103 | | |
104 | 10 | ctx->source[idx].f_source = f_source; |
105 | 10 | ctx->source[idx].p_source = p_source; |
106 | 10 | ctx->source[idx].threshold = threshold; |
107 | 10 | ctx->source[idx].strong = strong; |
108 | | |
109 | 10 | ctx->source_count++; |
110 | | |
111 | 10 | 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 | 10 | return ret; |
119 | 10 | } |
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 | 10 | { |
127 | 10 | unsigned char header[2]; |
128 | 10 | unsigned char tmp[MBEDTLS_ENTROPY_BLOCK_SIZE]; |
129 | 10 | size_t use_len = len; |
130 | 10 | const unsigned char *p = data; |
131 | 10 | int ret = 0; |
132 | | |
133 | 10 | if (use_len > MBEDTLS_ENTROPY_BLOCK_SIZE) { |
134 | 10 | if ((ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), |
135 | 10 | data, len, tmp)) != 0) { |
136 | 0 | goto cleanup; |
137 | 0 | } |
138 | 10 | p = tmp; |
139 | 10 | use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; |
140 | 10 | } |
141 | | |
142 | 10 | header[0] = source_id; |
143 | 10 | 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 | 10 | if (ctx->accumulator_started == 0) { |
151 | 10 | ret = mbedtls_md_setup(&ctx->accumulator, |
152 | 10 | mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), 0); |
153 | 10 | if (ret != 0) { |
154 | 0 | goto cleanup; |
155 | 0 | } |
156 | 10 | ret = mbedtls_md_starts(&ctx->accumulator); |
157 | 10 | if (ret != 0) { |
158 | 0 | goto cleanup; |
159 | 0 | } |
160 | 10 | ctx->accumulator_started = 1; |
161 | 10 | } |
162 | 10 | if ((ret = mbedtls_md_update(&ctx->accumulator, header, 2)) != 0) { |
163 | 0 | goto cleanup; |
164 | 0 | } |
165 | 10 | ret = mbedtls_md_update(&ctx->accumulator, p, use_len); |
166 | | |
167 | 10 | cleanup: |
168 | 10 | mbedtls_platform_zeroize(tmp, sizeof(tmp)); |
169 | | |
170 | 10 | return ret; |
171 | 10 | } |
172 | | |
173 | | int mbedtls_entropy_update_manual(mbedtls_entropy_context *ctx, |
174 | | const unsigned char *data, size_t len) |
175 | 0 | { |
176 | 0 | 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 | 0 | 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 | 0 | return ret; |
193 | 0 | } |
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 | 10 | { |
200 | 10 | int ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; |
201 | 10 | int i; |
202 | 10 | int have_one_strong = 0; |
203 | 10 | unsigned char buf[MBEDTLS_ENTROPY_MAX_GATHER]; |
204 | 10 | size_t olen; |
205 | | |
206 | 10 | if (ctx->source_count == 0) { |
207 | 0 | return MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED; |
208 | 0 | } |
209 | | |
210 | | /* |
211 | | * Run through our entropy sources |
212 | | */ |
213 | 20 | for (i = 0; i < ctx->source_count; i++) { |
214 | 10 | if (ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG) { |
215 | 10 | have_one_strong = 1; |
216 | 10 | } |
217 | | |
218 | 10 | olen = 0; |
219 | 10 | if ((ret = ctx->source[i].f_source(ctx->source[i].p_source, |
220 | 10 | buf, MBEDTLS_ENTROPY_MAX_GATHER, &olen)) != 0) { |
221 | 0 | goto cleanup; |
222 | 0 | } |
223 | | |
224 | | /* |
225 | | * Add if we actually gathered something |
226 | | */ |
227 | 10 | if (olen > 0) { |
228 | 10 | if ((ret = entropy_update(ctx, (unsigned char) i, |
229 | 10 | buf, olen)) != 0) { |
230 | 0 | return ret; |
231 | 0 | } |
232 | 10 | ctx->source[i].size += olen; |
233 | 10 | } |
234 | 10 | } |
235 | | |
236 | 10 | if (have_one_strong == 0) { |
237 | 0 | ret = MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE; |
238 | 0 | } |
239 | | |
240 | 10 | cleanup: |
241 | 10 | mbedtls_platform_zeroize(buf, sizeof(buf)); |
242 | | |
243 | 10 | return ret; |
244 | 10 | } |
245 | | |
246 | | /* |
247 | | * Thread-safe wrapper for entropy_gather_internal() |
248 | | */ |
249 | | int mbedtls_entropy_gather(mbedtls_entropy_context *ctx) |
250 | 0 | { |
251 | 0 | 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 | 0 | 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 | 0 | return ret; |
268 | 0 | } |
269 | | |
270 | | int mbedtls_entropy_func(void *data, unsigned char *output, size_t len) |
271 | 10 | { |
272 | 10 | int ret, count = 0, i, thresholds_reached; |
273 | 10 | size_t strong_size; |
274 | 10 | mbedtls_entropy_context *ctx = (mbedtls_entropy_context *) data; |
275 | 10 | unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; |
276 | | |
277 | 10 | if (len > MBEDTLS_ENTROPY_BLOCK_SIZE) { |
278 | 0 | return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; |
279 | 0 | } |
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 | 10 | do { |
303 | 10 | if (count++ > ENTROPY_MAX_LOOP) { |
304 | 0 | ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; |
305 | 0 | goto exit; |
306 | 0 | } |
307 | | |
308 | 10 | if ((ret = entropy_gather_internal(ctx)) != 0) { |
309 | 0 | goto exit; |
310 | 0 | } |
311 | | |
312 | 10 | thresholds_reached = 1; |
313 | 10 | strong_size = 0; |
314 | 20 | for (i = 0; i < ctx->source_count; i++) { |
315 | 10 | if (ctx->source[i].size < ctx->source[i].threshold) { |
316 | 0 | thresholds_reached = 0; |
317 | 0 | } |
318 | 10 | if (ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG) { |
319 | 10 | strong_size += ctx->source[i].size; |
320 | 10 | } |
321 | 10 | } |
322 | 10 | } while (!thresholds_reached || strong_size < MBEDTLS_ENTROPY_BLOCK_SIZE); |
323 | | |
324 | 10 | 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 | 10 | if ((ret = mbedtls_md_finish(&ctx->accumulator, buf)) != 0) { |
332 | 0 | goto exit; |
333 | 0 | } |
334 | | |
335 | | /* |
336 | | * Reset accumulator and counters and recycle existing entropy |
337 | | */ |
338 | 10 | mbedtls_md_free(&ctx->accumulator); |
339 | 10 | mbedtls_md_init(&ctx->accumulator); |
340 | 10 | ret = mbedtls_md_setup(&ctx->accumulator, |
341 | 10 | mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), 0); |
342 | 10 | if (ret != 0) { |
343 | 0 | goto exit; |
344 | 0 | } |
345 | 10 | ret = mbedtls_md_starts(&ctx->accumulator); |
346 | 10 | if (ret != 0) { |
347 | 0 | goto exit; |
348 | 0 | } |
349 | 10 | if ((ret = mbedtls_md_update(&ctx->accumulator, buf, |
350 | 10 | MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) { |
351 | 0 | goto exit; |
352 | 0 | } |
353 | | |
354 | | /* |
355 | | * Perform second hashing on entropy |
356 | | */ |
357 | 10 | if ((ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_ENTROPY_MD), |
358 | 10 | buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf)) != 0) { |
359 | 0 | goto exit; |
360 | 0 | } |
361 | | |
362 | 20 | for (i = 0; i < ctx->source_count; i++) { |
363 | 10 | ctx->source[i].size = 0; |
364 | 10 | } |
365 | | |
366 | 10 | memcpy(output, buf, len); |
367 | | |
368 | 10 | ret = 0; |
369 | | |
370 | 10 | exit: |
371 | 10 | 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 | 10 | return ret; |
380 | 10 | } |
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 | 0 | { |
408 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
409 | 0 | FILE *f = NULL; |
410 | 0 | unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; |
411 | |
|
412 | 0 | if ((ret = mbedtls_entropy_func(ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE)) != 0) { |
413 | 0 | ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; |
414 | 0 | goto exit; |
415 | 0 | } |
416 | | |
417 | 0 | if ((f = fopen(path, "wb")) == NULL) { |
418 | 0 | ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; |
419 | 0 | goto exit; |
420 | 0 | } |
421 | | |
422 | | /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ |
423 | 0 | mbedtls_setbuf(f, NULL); |
424 | |
|
425 | 0 | if (fwrite(buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f) != MBEDTLS_ENTROPY_BLOCK_SIZE) { |
426 | 0 | ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; |
427 | 0 | goto exit; |
428 | 0 | } |
429 | | |
430 | 0 | ret = 0; |
431 | |
|
432 | 0 | exit: |
433 | 0 | mbedtls_platform_zeroize(buf, sizeof(buf)); |
434 | |
|
435 | 0 | if (f != NULL) { |
436 | 0 | fclose(f); |
437 | 0 | } |
438 | |
|
439 | 0 | return ret; |
440 | 0 | } |
441 | | |
442 | | int mbedtls_entropy_update_seed_file(mbedtls_entropy_context *ctx, const char *path) |
443 | 0 | { |
444 | 0 | int ret = 0; |
445 | 0 | FILE *f; |
446 | 0 | size_t n; |
447 | 0 | unsigned char buf[MBEDTLS_ENTROPY_MAX_SEED_SIZE]; |
448 | |
|
449 | 0 | if ((f = fopen(path, "rb")) == NULL) { |
450 | 0 | return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; |
451 | 0 | } |
452 | | |
453 | | /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ |
454 | 0 | mbedtls_setbuf(f, NULL); |
455 | |
|
456 | 0 | fseek(f, 0, SEEK_END); |
457 | 0 | n = (size_t) ftell(f); |
458 | 0 | fseek(f, 0, SEEK_SET); |
459 | |
|
460 | 0 | if (n > MBEDTLS_ENTROPY_MAX_SEED_SIZE) { |
461 | 0 | n = MBEDTLS_ENTROPY_MAX_SEED_SIZE; |
462 | 0 | } |
463 | |
|
464 | 0 | if (fread(buf, 1, n, f) != n) { |
465 | 0 | ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; |
466 | 0 | } else { |
467 | 0 | ret = mbedtls_entropy_update_manual(ctx, buf, n); |
468 | 0 | } |
469 | |
|
470 | 0 | fclose(f); |
471 | |
|
472 | 0 | mbedtls_platform_zeroize(buf, sizeof(buf)); |
473 | |
|
474 | 0 | if (ret != 0) { |
475 | 0 | return ret; |
476 | 0 | } |
477 | | |
478 | 0 | return mbedtls_entropy_write_seed_file(ctx, path); |
479 | 0 | } |
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 | 0 | { |
489 | 0 | ((void) data); |
490 | |
|
491 | 0 | memset(output, 0x2a, len); |
492 | 0 | *olen = len; |
493 | |
|
494 | 0 | return 0; |
495 | 0 | } |
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 | 0 | { |
605 | 0 | int ret = 1; |
606 | 0 | mbedtls_entropy_context ctx; |
607 | 0 | unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; |
608 | 0 | unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; |
609 | 0 | size_t i, j; |
610 | |
|
611 | 0 | if (verbose != 0) { |
612 | 0 | mbedtls_printf(" ENTROPY test: "); |
613 | 0 | } |
614 | |
|
615 | 0 | mbedtls_entropy_init(&ctx); |
616 | | |
617 | | /* First do a gather to make sure we have default sources */ |
618 | 0 | if ((ret = mbedtls_entropy_gather(&ctx)) != 0) { |
619 | 0 | goto cleanup; |
620 | 0 | } |
621 | | |
622 | 0 | ret = mbedtls_entropy_add_source(&ctx, entropy_dummy_source, NULL, 16, |
623 | 0 | MBEDTLS_ENTROPY_SOURCE_WEAK); |
624 | 0 | if (ret != 0) { |
625 | 0 | goto cleanup; |
626 | 0 | } |
627 | | |
628 | 0 | if ((ret = mbedtls_entropy_update_manual(&ctx, buf, sizeof(buf))) != 0) { |
629 | 0 | goto cleanup; |
630 | 0 | } |
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 | 0 | for (i = 0; i < 8; i++) { |
641 | 0 | if ((ret = mbedtls_entropy_func(&ctx, buf, sizeof(buf))) != 0) { |
642 | 0 | goto cleanup; |
643 | 0 | } |
644 | | |
645 | 0 | for (j = 0; j < sizeof(buf); j++) { |
646 | 0 | acc[j] |= buf[j]; |
647 | 0 | } |
648 | 0 | } |
649 | | |
650 | 0 | for (j = 0; j < sizeof(buf); j++) { |
651 | 0 | if (acc[j] == 0) { |
652 | 0 | ret = 1; |
653 | 0 | goto cleanup; |
654 | 0 | } |
655 | 0 | } |
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 | 0 | cleanup: |
664 | 0 | mbedtls_entropy_free(&ctx); |
665 | |
|
666 | 0 | if (verbose != 0) { |
667 | 0 | if (ret != 0) { |
668 | 0 | mbedtls_printf("failed\n"); |
669 | 0 | } else { |
670 | 0 | mbedtls_printf("passed\n"); |
671 | 0 | } |
672 | |
|
673 | 0 | mbedtls_printf("\n"); |
674 | 0 | } |
675 | |
|
676 | 0 | return ret != 0; |
677 | 0 | } |
678 | | #endif /* MBEDTLS_SELF_TEST */ |
679 | | |
680 | | #endif /* MBEDTLS_ENTROPY_C */ |