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