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