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 
mbedtls_entropy_init(mbedtls_entropy_context * ctx)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 
mbedtls_entropy_free(mbedtls_entropy_context * ctx)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 
mbedtls_entropy_add_source(mbedtls_entropy_context * ctx,mbedtls_entropy_f_source_ptr f_source,void * p_source,size_t threshold,int strong)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  */
entropy_update(mbedtls_entropy_context * ctx,unsigned char source_id,const unsigned char * data,size_t len)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 
mbedtls_entropy_update_manual(mbedtls_entropy_context * ctx,const unsigned char * data,size_t len)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  */
entropy_gather_internal(mbedtls_entropy_context * ctx)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  */
mbedtls_entropy_gather(mbedtls_entropy_context * ctx)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 
mbedtls_entropy_func(void * data,unsigned char * output,size_t len)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)
mbedtls_entropy_update_nv_seed(mbedtls_entropy_context * ctx)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)
mbedtls_entropy_write_seed_file(mbedtls_entropy_context * ctx,const char * path)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 
mbedtls_entropy_update_seed_file(mbedtls_entropy_context * ctx,const char * path)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  */
entropy_dummy_source(void * data,unsigned char * output,size_t len,size_t * olen)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 
mbedtls_entropy_source_self_test_gather(unsigned char * buf,size_t buf_len)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 
mbedtls_entropy_source_self_test_check_bits(const unsigned char * buf,size_t buf_len)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  */
mbedtls_entropy_source_self_test(int verbose)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  */
mbedtls_entropy_self_test(int verbose)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