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