• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* BEGIN_HEADER */
2#include "mbedtls/entropy.h"
3#include "mbedtls/entropy_poll.h"
4#include "mbedtls/md.h"
5#include "string.h"
6
7/*
8 * Number of calls made to entropy_dummy_source()
9 */
10static size_t entropy_dummy_calls;
11
12/*
13 * Dummy entropy source
14 *
15 * If data is NULL, write exactly the requested length.
16 * Otherwise, write the length indicated by data or error if negative
17 */
18static int entropy_dummy_source( void *data, unsigned char *output,
19                                 size_t len, size_t *olen )
20{
21    entropy_dummy_calls++;
22
23    if( data == NULL )
24        *olen = len;
25    else
26    {
27        int *d = (int *) data;
28
29        if( *d < 0 )
30            return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
31        else
32            *olen = *d;
33    }
34
35    memset( output, 0x2a, *olen );
36
37    return( 0 );
38}
39
40#if defined(MBEDTLS_ENTROPY_NV_SEED)
41/*
42 * Ability to clear entropy sources to allow testing with just predefined
43 * entropy sources. This function or tests depending on it might break if there
44 * are internal changes to how entropy sources are registered.
45 *
46 * To be called immediately after mbedtls_entropy_init().
47 *
48 * Just resetting the counter. New sources will overwrite existing ones.
49 * This might break memory checks in the future if sources need 'free-ing' then
50 * as well.
51 */
52void entropy_clear_sources( mbedtls_entropy_context *ctx )
53{
54    ctx->source_count = 0;
55}
56
57/*
58 * NV seed read/write functions that use a buffer instead of a file
59 */
60static unsigned char buffer_seed[MBEDTLS_ENTROPY_BLOCK_SIZE];
61
62int buffer_nv_seed_read( unsigned char *buf, size_t buf_len )
63{
64    if( buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE )
65        return( -1 );
66
67    memcpy( buf, buffer_seed, MBEDTLS_ENTROPY_BLOCK_SIZE );
68    return( 0 );
69}
70
71int buffer_nv_seed_write( unsigned char *buf, size_t buf_len )
72{
73    if( buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE )
74        return( -1 );
75
76    memcpy( buffer_seed, buf, MBEDTLS_ENTROPY_BLOCK_SIZE );
77    return( 0 );
78}
79
80/*
81 * NV seed read/write helpers that fill the base seedfile
82 */
83int write_nv_seed( unsigned char *buf, size_t buf_len )
84{
85    FILE *f;
86
87    if( buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE )
88        return( -1 );
89
90    if( ( f = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "w" ) ) == NULL )
91        return( -1 );
92
93    if( fwrite( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) !=
94                    MBEDTLS_ENTROPY_BLOCK_SIZE )
95        return( -1 );
96
97    fclose( f );
98
99    return( 0 );
100}
101
102int read_nv_seed( unsigned char *buf, size_t buf_len )
103{
104    FILE *f;
105
106    if( buf_len != MBEDTLS_ENTROPY_BLOCK_SIZE )
107        return( -1 );
108
109    if( ( f = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "rb" ) ) == NULL )
110        return( -1 );
111
112    if( fread( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) !=
113                    MBEDTLS_ENTROPY_BLOCK_SIZE )
114        return( -1 );
115
116    fclose( f );
117
118    return( 0 );
119}
120#endif /* MBEDTLS_ENTROPY_NV_SEED */
121/* END_HEADER */
122
123/* BEGIN_DEPENDENCIES
124 * depends_on:MBEDTLS_ENTROPY_C
125 * END_DEPENDENCIES
126 */
127
128/* BEGIN_CASE */
129void entropy_init_free( int reinit )
130{
131    mbedtls_entropy_context ctx;
132
133    /* Double free is not explicitly documented to work, but it is convenient
134     * to call mbedtls_entropy_free() unconditionally on an error path without
135     * checking whether it has already been called in the success path. */
136
137    mbedtls_entropy_init( &ctx );
138    mbedtls_entropy_free( &ctx );
139
140    if( reinit )
141        mbedtls_entropy_init( &ctx );
142    mbedtls_entropy_free( &ctx );
143
144    /* This test case always succeeds, functionally speaking. A plausible
145     * bug might trigger an invalid pointer dereference or a memory leak. */
146    goto exit;
147}
148/* END_CASE */
149
150/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
151void entropy_seed_file( char * path, int ret )
152{
153    mbedtls_entropy_context ctx;
154
155    mbedtls_entropy_init( &ctx );
156
157    TEST_ASSERT( mbedtls_entropy_write_seed_file( &ctx, path ) == ret );
158    TEST_ASSERT( mbedtls_entropy_update_seed_file( &ctx, path ) == ret );
159
160exit:
161    mbedtls_entropy_free( &ctx );
162}
163/* END_CASE */
164
165/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
166void entropy_write_base_seed_file( int ret )
167{
168    mbedtls_entropy_context ctx;
169
170    mbedtls_entropy_init( &ctx );
171
172    TEST_ASSERT( mbedtls_entropy_write_seed_file( &ctx, MBEDTLS_PLATFORM_STD_NV_SEED_FILE ) == ret );
173    TEST_ASSERT( mbedtls_entropy_update_seed_file( &ctx, MBEDTLS_PLATFORM_STD_NV_SEED_FILE ) == ret );
174
175exit:
176    mbedtls_entropy_free( &ctx );
177}
178/* END_CASE */
179
180/* BEGIN_CASE */
181void entropy_too_many_sources(  )
182{
183    mbedtls_entropy_context ctx;
184    size_t i;
185
186    mbedtls_entropy_init( &ctx );
187
188    /*
189     * It's hard to tell precisely when the error will occur,
190     * since we don't know how many sources were automatically added.
191     */
192    for( i = 0; i < MBEDTLS_ENTROPY_MAX_SOURCES; i++ )
193        (void) mbedtls_entropy_add_source( &ctx, entropy_dummy_source, NULL,
194                                           16, MBEDTLS_ENTROPY_SOURCE_WEAK );
195
196    TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, NULL,
197                                             16, MBEDTLS_ENTROPY_SOURCE_WEAK )
198                 == MBEDTLS_ERR_ENTROPY_MAX_SOURCES );
199
200exit:
201    mbedtls_entropy_free( &ctx );
202}
203/* END_CASE */
204
205/* BEGIN_CASE depends_on:ENTROPY_HAVE_STRONG */
206void entropy_func_len( int len, int ret )
207{
208    mbedtls_entropy_context ctx;
209    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE + 10] = { 0 };
210    unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE + 10] = { 0 };
211    size_t i, j;
212
213    mbedtls_entropy_init( &ctx );
214
215    /*
216     * See comments in mbedtls_entropy_self_test()
217     */
218    for( i = 0; i < 8; i++ )
219    {
220        TEST_ASSERT( mbedtls_entropy_func( &ctx, buf, len ) == ret );
221        for( j = 0; j < sizeof( buf ); j++ )
222            acc[j] |= buf[j];
223    }
224
225    if( ret == 0 )
226        for( j = 0; j < (size_t) len; j++ )
227            TEST_ASSERT( acc[j] != 0 );
228
229    for( j = len; j < sizeof( buf ); j++ )
230        TEST_ASSERT( acc[j] == 0 );
231
232exit:
233    mbedtls_entropy_free( &ctx );
234}
235/* END_CASE */
236
237/* BEGIN_CASE */
238void entropy_source_fail( char * path )
239{
240    mbedtls_entropy_context ctx;
241    int fail = -1;
242    unsigned char buf[16];
243
244    mbedtls_entropy_init( &ctx );
245
246    TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source,
247                                             &fail, 16,
248                                             MBEDTLS_ENTROPY_SOURCE_WEAK )
249                 == 0 );
250
251    TEST_ASSERT( mbedtls_entropy_func( &ctx, buf, sizeof( buf ) )
252                 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
253    TEST_ASSERT( mbedtls_entropy_gather( &ctx )
254                 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
255#if defined(MBEDTLS_FS_IO) && defined(MBEDTLS_ENTROPY_NV_SEED)
256    TEST_ASSERT( mbedtls_entropy_write_seed_file( &ctx, path )
257                 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
258    TEST_ASSERT( mbedtls_entropy_update_seed_file( &ctx, path )
259                 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
260#else
261    ((void) path);
262#endif
263
264exit:
265    mbedtls_entropy_free( &ctx );
266}
267/* END_CASE */
268
269/* BEGIN_CASE depends_on:ENTROPY_HAVE_STRONG */
270void entropy_threshold( int threshold, int chunk_size, int result )
271{
272    mbedtls_entropy_context ctx;
273    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 };
274    int ret;
275
276    mbedtls_entropy_init( &ctx );
277
278    TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source,
279                                     &chunk_size, threshold,
280                                     MBEDTLS_ENTROPY_SOURCE_WEAK ) == 0 );
281
282    entropy_dummy_calls = 0;
283    ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) );
284
285    if( result >= 0 )
286    {
287        TEST_ASSERT( ret == 0 );
288#if defined(MBEDTLS_ENTROPY_NV_SEED)
289        // Two times as much calls due to the NV seed update
290        result *= 2;
291#endif
292        TEST_ASSERT( entropy_dummy_calls == (size_t) result );
293    }
294    else
295    {
296        TEST_ASSERT( ret == result );
297    }
298
299exit:
300    mbedtls_entropy_free( &ctx );
301}
302/* END_CASE */
303
304/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
305void nv_seed_file_create(  )
306{
307    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
308
309    memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
310
311    TEST_ASSERT( write_nv_seed( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
312}
313/* END_CASE */
314
315/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO:MBEDTLS_PLATFORM_NV_SEED_ALT */
316void entropy_nv_seed_std_io(  )
317{
318    unsigned char io_seed[MBEDTLS_ENTROPY_BLOCK_SIZE];
319    unsigned char check_seed[MBEDTLS_ENTROPY_BLOCK_SIZE];
320
321    memset( io_seed, 1, MBEDTLS_ENTROPY_BLOCK_SIZE );
322    memset( check_seed, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
323
324    mbedtls_platform_set_nv_seed( mbedtls_platform_std_nv_seed_read,
325                                  mbedtls_platform_std_nv_seed_write );
326
327    /* Check if platform NV read and write manipulate the same data */
328    TEST_ASSERT( write_nv_seed( io_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
329    TEST_ASSERT( mbedtls_nv_seed_read( check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) ==
330                    MBEDTLS_ENTROPY_BLOCK_SIZE );
331
332    TEST_ASSERT( memcmp( io_seed, check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
333
334    memset( check_seed, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
335
336    /* Check if platform NV write and raw read manipulate the same data */
337    TEST_ASSERT( mbedtls_nv_seed_write( io_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) ==
338                    MBEDTLS_ENTROPY_BLOCK_SIZE );
339    TEST_ASSERT( read_nv_seed( check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
340
341    TEST_ASSERT( memcmp( io_seed, check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
342}
343/* END_CASE */
344
345/* BEGIN_CASE depends_on:MBEDTLS_MD_C:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_PLATFORM_NV_SEED_ALT */
346void entropy_nv_seed( data_t * read_seed )
347{
348#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
349    const mbedtls_md_info_t *md_info =
350        mbedtls_md_info_from_type( MBEDTLS_MD_SHA512 );
351#elif defined(MBEDTLS_ENTROPY_SHA256_ACCUMULATOR)
352    const mbedtls_md_info_t *md_info =
353        mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 );
354#else
355#error "Unsupported entropy accumulator"
356#endif
357    mbedtls_md_context_t accumulator;
358    mbedtls_entropy_context ctx;
359    int (*original_mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len ) =
360        mbedtls_nv_seed_read;
361    int (*original_mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len ) =
362        mbedtls_nv_seed_write;
363
364    unsigned char header[2];
365    unsigned char entropy[MBEDTLS_ENTROPY_BLOCK_SIZE];
366    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
367    unsigned char empty[MBEDTLS_ENTROPY_BLOCK_SIZE];
368    unsigned char check_seed[MBEDTLS_ENTROPY_BLOCK_SIZE];
369    unsigned char check_entropy[MBEDTLS_ENTROPY_BLOCK_SIZE];
370
371    memset( entropy, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
372    memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
373    memset( empty, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
374    memset( check_seed, 2, MBEDTLS_ENTROPY_BLOCK_SIZE );
375    memset( check_entropy, 3, MBEDTLS_ENTROPY_BLOCK_SIZE );
376
377    // Make sure we read/write NV seed from our buffers
378    mbedtls_platform_set_nv_seed( buffer_nv_seed_read, buffer_nv_seed_write );
379
380    mbedtls_md_init( &accumulator );
381    mbedtls_entropy_init( &ctx );
382    entropy_clear_sources( &ctx );
383
384    TEST_ASSERT( mbedtls_entropy_add_source( &ctx, mbedtls_nv_seed_poll, NULL,
385                                             MBEDTLS_ENTROPY_BLOCK_SIZE,
386                                             MBEDTLS_ENTROPY_SOURCE_STRONG ) == 0 );
387
388    // Set the initial NV seed to read
389    TEST_ASSERT( read_seed->len >= MBEDTLS_ENTROPY_BLOCK_SIZE );
390    memcpy( buffer_seed, read_seed->x, MBEDTLS_ENTROPY_BLOCK_SIZE );
391
392    // Do an entropy run
393    TEST_ASSERT( mbedtls_entropy_func( &ctx, entropy, sizeof( entropy ) ) == 0 );
394    // Determine what should have happened with manual entropy internal logic
395
396    // Init accumulator
397    header[1] = MBEDTLS_ENTROPY_BLOCK_SIZE;
398    TEST_ASSERT( mbedtls_md_setup( &accumulator, md_info, 0 ) == 0 );
399
400    // First run for updating write_seed
401    header[0] = 0;
402    TEST_ASSERT( mbedtls_md_starts( &accumulator ) == 0 );
403    TEST_ASSERT( mbedtls_md_update( &accumulator, header, 2 ) == 0 );
404    TEST_ASSERT( mbedtls_md_update( &accumulator,
405                                    read_seed->x, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
406    TEST_ASSERT( mbedtls_md_finish( &accumulator, buf ) == 0 );
407
408    TEST_ASSERT( mbedtls_md_starts( &accumulator ) == 0 );
409    TEST_ASSERT( mbedtls_md_update( &accumulator,
410                                    buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
411
412    TEST_ASSERT( mbedtls_md( md_info, buf, MBEDTLS_ENTROPY_BLOCK_SIZE,
413                             check_seed ) == 0 );
414
415    // Second run for actual entropy (triggers mbedtls_entropy_update_nv_seed)
416    header[0] = MBEDTLS_ENTROPY_SOURCE_MANUAL;
417    TEST_ASSERT( mbedtls_md_update( &accumulator, header, 2 ) == 0 );
418    TEST_ASSERT( mbedtls_md_update( &accumulator,
419                                    empty, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
420
421    header[0] = 0;
422    TEST_ASSERT( mbedtls_md_update( &accumulator, header, 2 ) == 0 );
423    TEST_ASSERT( mbedtls_md_update( &accumulator,
424                                    check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
425    TEST_ASSERT( mbedtls_md_finish( &accumulator, buf ) == 0 );
426
427    TEST_ASSERT( mbedtls_md( md_info, buf, MBEDTLS_ENTROPY_BLOCK_SIZE,
428                             check_entropy ) == 0 );
429
430    // Check result of both NV file and entropy received with the manual calculations
431    TEST_ASSERT( memcmp( check_seed, buffer_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
432    TEST_ASSERT( memcmp( check_entropy, entropy, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
433
434exit:
435    mbedtls_md_free( &accumulator );
436    mbedtls_entropy_free( &ctx );
437    mbedtls_nv_seed_read = original_mbedtls_nv_seed_read;
438    mbedtls_nv_seed_write = original_mbedtls_nv_seed_write;
439}
440/* END_CASE */
441
442/* BEGIN_CASE depends_on:ENTROPY_HAVE_STRONG:MBEDTLS_SELF_TEST */
443void entropy_selftest( int result )
444{
445    TEST_ASSERT( mbedtls_entropy_self_test( 1 ) == result );
446}
447/* END_CASE */
448