• 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 */
166void entropy_too_many_sources(  )
167{
168    mbedtls_entropy_context ctx;
169    size_t i;
170
171    mbedtls_entropy_init( &ctx );
172
173    /*
174     * It's hard to tell precisely when the error will occur,
175     * since we don't know how many sources were automatically added.
176     */
177    for( i = 0; i < MBEDTLS_ENTROPY_MAX_SOURCES; i++ )
178        (void) mbedtls_entropy_add_source( &ctx, entropy_dummy_source, NULL,
179                                           16, MBEDTLS_ENTROPY_SOURCE_WEAK );
180
181    TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source, NULL,
182                                             16, MBEDTLS_ENTROPY_SOURCE_WEAK )
183                 == MBEDTLS_ERR_ENTROPY_MAX_SOURCES );
184
185exit:
186    mbedtls_entropy_free( &ctx );
187}
188/* END_CASE */
189
190/* BEGIN_CASE depends_on:ENTROPY_HAVE_STRONG */
191void entropy_func_len( int len, int ret )
192{
193    mbedtls_entropy_context ctx;
194    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE + 10] = { 0 };
195    unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE + 10] = { 0 };
196    size_t i, j;
197
198    mbedtls_entropy_init( &ctx );
199
200    /*
201     * See comments in mbedtls_entropy_self_test()
202     */
203    for( i = 0; i < 8; i++ )
204    {
205        TEST_ASSERT( mbedtls_entropy_func( &ctx, buf, len ) == ret );
206        for( j = 0; j < sizeof( buf ); j++ )
207            acc[j] |= buf[j];
208    }
209
210    if( ret == 0 )
211        for( j = 0; j < (size_t) len; j++ )
212            TEST_ASSERT( acc[j] != 0 );
213
214    for( j = len; j < sizeof( buf ); j++ )
215        TEST_ASSERT( acc[j] == 0 );
216
217exit:
218    mbedtls_entropy_free( &ctx );
219}
220/* END_CASE */
221
222/* BEGIN_CASE */
223void entropy_source_fail( char * path )
224{
225    mbedtls_entropy_context ctx;
226    int fail = -1;
227    unsigned char buf[16];
228
229    mbedtls_entropy_init( &ctx );
230
231    TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source,
232                                             &fail, 16,
233                                             MBEDTLS_ENTROPY_SOURCE_WEAK )
234                 == 0 );
235
236    TEST_ASSERT( mbedtls_entropy_func( &ctx, buf, sizeof( buf ) )
237                 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
238    TEST_ASSERT( mbedtls_entropy_gather( &ctx )
239                 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
240#if defined(MBEDTLS_FS_IO) && defined(MBEDTLS_ENTROPY_NV_SEED)
241    TEST_ASSERT( mbedtls_entropy_write_seed_file( &ctx, path )
242                 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
243    TEST_ASSERT( mbedtls_entropy_update_seed_file( &ctx, path )
244                 == MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
245#else
246    ((void) path);
247#endif
248
249exit:
250    mbedtls_entropy_free( &ctx );
251}
252/* END_CASE */
253
254/* BEGIN_CASE depends_on:ENTROPY_HAVE_STRONG */
255void entropy_threshold( int threshold, int chunk_size, int result )
256{
257    mbedtls_entropy_context ctx;
258    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 };
259    int ret;
260
261    mbedtls_entropy_init( &ctx );
262
263    TEST_ASSERT( mbedtls_entropy_add_source( &ctx, entropy_dummy_source,
264                                     &chunk_size, threshold,
265                                     MBEDTLS_ENTROPY_SOURCE_WEAK ) == 0 );
266
267    entropy_dummy_calls = 0;
268    ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) );
269
270    if( result >= 0 )
271    {
272        TEST_ASSERT( ret == 0 );
273#if defined(MBEDTLS_ENTROPY_NV_SEED)
274        // Two times as much calls due to the NV seed update
275        result *= 2;
276#endif
277        TEST_ASSERT( entropy_dummy_calls == (size_t) result );
278    }
279    else
280    {
281        TEST_ASSERT( ret == result );
282    }
283
284exit:
285    mbedtls_entropy_free( &ctx );
286}
287/* END_CASE */
288
289/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
290void nv_seed_file_create(  )
291{
292    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
293
294    memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
295
296    TEST_ASSERT( write_nv_seed( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
297}
298/* END_CASE */
299
300/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO:MBEDTLS_PLATFORM_NV_SEED_ALT */
301void entropy_nv_seed_std_io(  )
302{
303    unsigned char io_seed[MBEDTLS_ENTROPY_BLOCK_SIZE];
304    unsigned char check_seed[MBEDTLS_ENTROPY_BLOCK_SIZE];
305
306    memset( io_seed, 1, MBEDTLS_ENTROPY_BLOCK_SIZE );
307    memset( check_seed, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
308
309    mbedtls_platform_set_nv_seed( mbedtls_platform_std_nv_seed_read,
310                                  mbedtls_platform_std_nv_seed_write );
311
312    /* Check if platform NV read and write manipulate the same data */
313    TEST_ASSERT( write_nv_seed( io_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
314    TEST_ASSERT( mbedtls_nv_seed_read( check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) ==
315                    MBEDTLS_ENTROPY_BLOCK_SIZE );
316
317    TEST_ASSERT( memcmp( io_seed, check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
318
319    memset( check_seed, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
320
321    /* Check if platform NV write and raw read manipulate the same data */
322    TEST_ASSERT( mbedtls_nv_seed_write( io_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) ==
323                    MBEDTLS_ENTROPY_BLOCK_SIZE );
324    TEST_ASSERT( read_nv_seed( check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
325
326    TEST_ASSERT( memcmp( io_seed, check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
327}
328/* END_CASE */
329
330/* BEGIN_CASE depends_on:MBEDTLS_MD_C:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_PLATFORM_NV_SEED_ALT */
331void entropy_nv_seed( data_t * read_seed )
332{
333#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
334    const mbedtls_md_info_t *md_info =
335        mbedtls_md_info_from_type( MBEDTLS_MD_SHA512 );
336#elif defined(MBEDTLS_ENTROPY_SHA256_ACCUMULATOR)
337    const mbedtls_md_info_t *md_info =
338        mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 );
339#else
340#error "Unsupported entropy accumulator"
341#endif
342    mbedtls_md_context_t accumulator;
343    mbedtls_entropy_context ctx;
344    int (*original_mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len ) =
345        mbedtls_nv_seed_read;
346    int (*original_mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len ) =
347        mbedtls_nv_seed_write;
348
349    unsigned char header[2];
350    unsigned char entropy[MBEDTLS_ENTROPY_BLOCK_SIZE];
351    unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
352    unsigned char empty[MBEDTLS_ENTROPY_BLOCK_SIZE];
353    unsigned char check_seed[MBEDTLS_ENTROPY_BLOCK_SIZE];
354    unsigned char check_entropy[MBEDTLS_ENTROPY_BLOCK_SIZE];
355
356    memset( entropy, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
357    memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
358    memset( empty, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
359    memset( check_seed, 2, MBEDTLS_ENTROPY_BLOCK_SIZE );
360    memset( check_entropy, 3, MBEDTLS_ENTROPY_BLOCK_SIZE );
361
362    // Make sure we read/write NV seed from our buffers
363    mbedtls_platform_set_nv_seed( buffer_nv_seed_read, buffer_nv_seed_write );
364
365    mbedtls_md_init( &accumulator );
366    mbedtls_entropy_init( &ctx );
367    entropy_clear_sources( &ctx );
368
369    TEST_ASSERT( mbedtls_entropy_add_source( &ctx, mbedtls_nv_seed_poll, NULL,
370                                             MBEDTLS_ENTROPY_BLOCK_SIZE,
371                                             MBEDTLS_ENTROPY_SOURCE_STRONG ) == 0 );
372
373    // Set the initial NV seed to read
374    TEST_ASSERT( read_seed->len >= MBEDTLS_ENTROPY_BLOCK_SIZE );
375    memcpy( buffer_seed, read_seed->x, MBEDTLS_ENTROPY_BLOCK_SIZE );
376
377    // Do an entropy run
378    TEST_ASSERT( mbedtls_entropy_func( &ctx, entropy, sizeof( entropy ) ) == 0 );
379    // Determine what should have happened with manual entropy internal logic
380
381    // Init accumulator
382    header[1] = MBEDTLS_ENTROPY_BLOCK_SIZE;
383    TEST_ASSERT( mbedtls_md_setup( &accumulator, md_info, 0 ) == 0 );
384
385    // First run for updating write_seed
386    header[0] = 0;
387    TEST_ASSERT( mbedtls_md_starts( &accumulator ) == 0 );
388    TEST_ASSERT( mbedtls_md_update( &accumulator, header, 2 ) == 0 );
389    TEST_ASSERT( mbedtls_md_update( &accumulator,
390                                    read_seed->x, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
391    TEST_ASSERT( mbedtls_md_finish( &accumulator, buf ) == 0 );
392
393    TEST_ASSERT( mbedtls_md_starts( &accumulator ) == 0 );
394    TEST_ASSERT( mbedtls_md_update( &accumulator,
395                                    buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
396
397    TEST_ASSERT( mbedtls_md( md_info, buf, MBEDTLS_ENTROPY_BLOCK_SIZE,
398                             check_seed ) == 0 );
399
400    // Second run for actual entropy (triggers mbedtls_entropy_update_nv_seed)
401    header[0] = MBEDTLS_ENTROPY_SOURCE_MANUAL;
402    TEST_ASSERT( mbedtls_md_update( &accumulator, header, 2 ) == 0 );
403    TEST_ASSERT( mbedtls_md_update( &accumulator,
404                                    empty, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
405
406    header[0] = 0;
407    TEST_ASSERT( mbedtls_md_update( &accumulator, header, 2 ) == 0 );
408    TEST_ASSERT( mbedtls_md_update( &accumulator,
409                                    check_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
410    TEST_ASSERT( mbedtls_md_finish( &accumulator, buf ) == 0 );
411
412    TEST_ASSERT( mbedtls_md( md_info, buf, MBEDTLS_ENTROPY_BLOCK_SIZE,
413                             check_entropy ) == 0 );
414
415    // Check result of both NV file and entropy received with the manual calculations
416    TEST_ASSERT( memcmp( check_seed, buffer_seed, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
417    TEST_ASSERT( memcmp( check_entropy, entropy, MBEDTLS_ENTROPY_BLOCK_SIZE ) == 0 );
418
419exit:
420    mbedtls_md_free( &accumulator );
421    mbedtls_entropy_free( &ctx );
422    mbedtls_nv_seed_read = original_mbedtls_nv_seed_read;
423    mbedtls_nv_seed_write = original_mbedtls_nv_seed_write;
424}
425/* END_CASE */
426
427/* BEGIN_CASE depends_on:ENTROPY_HAVE_STRONG:MBEDTLS_SELF_TEST */
428void entropy_selftest( int result )
429{
430    TEST_ASSERT( mbedtls_entropy_self_test( 1 ) == result );
431}
432/* END_CASE */
433