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