mbed TLS library

Dependents:   HTTPClient-SSL WS_SERVER

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers entropy.c Source File

entropy.c

00001 /*
00002  *  Entropy accumulator implementation
00003  *
00004  *  Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
00005  *
00006  *  This file is part of mbed TLS (https://tls.mbed.org)
00007  *
00008  *  This program is free software; you can redistribute it and/or modify
00009  *  it under the terms of the GNU General Public License as published by
00010  *  the Free Software Foundation; either version 2 of the License, or
00011  *  (at your option) any later version.
00012  *
00013  *  This program is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *  GNU General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU General Public License along
00019  *  with this program; if not, write to the Free Software Foundation, Inc.,
00020  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00021  */
00022 
00023 #if !defined(POLARSSL_CONFIG_FILE)
00024 #include "polarssl/config.h"
00025 #else
00026 #include POLARSSL_CONFIG_FILE
00027 #endif
00028 
00029 #if defined(POLARSSL_ENTROPY_C)
00030 
00031 #include "polarssl/entropy.h"
00032 #include "polarssl/entropy_poll.h"
00033 
00034 #include <string.h>
00035 
00036 #if defined(POLARSSL_FS_IO)
00037 #include <stdio.h>
00038 #endif
00039 
00040 #if defined(POLARSSL_SELF_TEST)
00041 #if defined(POLARSSL_PLATFORM_C)
00042 #include "polarssl/platform.h"
00043 #else
00044 #include <stdio.h>
00045 #define polarssl_printf     printf
00046 #endif /* POLARSSL_PLATFORM_C */
00047 #endif /* POLARSSL_SELF_TEST */
00048 
00049 #if defined(POLARSSL_HAVEGE_C)
00050 #include "polarssl/havege.h"
00051 #endif
00052 
00053 /* Implementation that should never be optimized out by the compiler */
00054 static void polarssl_zeroize( void *v, size_t n ) {
00055     volatile unsigned char *p = v; while( n-- ) *p++ = 0;
00056 }
00057 
00058 #define ENTROPY_MAX_LOOP    256     /**< Maximum amount to loop before error */
00059 
00060 void entropy_init( entropy_context *ctx )
00061 {
00062     memset( ctx, 0, sizeof(entropy_context) );
00063 
00064 #if defined(POLARSSL_THREADING_C)
00065     polarssl_mutex_init( &ctx->mutex  );
00066 #endif
00067 
00068 #if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR)
00069     sha512_starts( &ctx->accumulator, 0 );
00070 #else
00071     sha256_starts( &ctx->accumulator, 0 );
00072 #endif
00073 #if defined(POLARSSL_HAVEGE_C)
00074     havege_init( &ctx->havege_data );
00075 #endif
00076 
00077 #if !defined(POLARSSL_NO_DEFAULT_ENTROPY_SOURCES)
00078 #if !defined(POLARSSL_NO_PLATFORM_ENTROPY)
00079     entropy_add_source( ctx, platform_entropy_poll, NULL,
00080                         ENTROPY_MIN_PLATFORM );
00081 #endif
00082 #if defined(POLARSSL_TIMING_C)
00083     entropy_add_source( ctx, hardclock_poll, NULL, ENTROPY_MIN_HARDCLOCK );
00084 #endif
00085 #if defined(POLARSSL_HAVEGE_C)
00086     entropy_add_source( ctx, havege_poll, &ctx->havege_data,
00087                         ENTROPY_MIN_HAVEGE );
00088 #endif
00089 #endif /* POLARSSL_NO_DEFAULT_ENTROPY_SOURCES */
00090 }
00091 
00092 void entropy_free( entropy_context *ctx )
00093 {
00094 #if defined(POLARSSL_HAVEGE_C)
00095     havege_free( &ctx->havege_data );
00096 #endif
00097 #if defined(POLARSSL_THREADING_C)
00098     polarssl_mutex_free( &ctx->mutex  );
00099 #endif
00100     polarssl_zeroize( ctx, sizeof( entropy_context ) );
00101 }
00102 
00103 int entropy_add_source( entropy_context *ctx,
00104                         f_source_ptr f_source, void *p_source,
00105                         size_t threshold )
00106 {
00107     int index, ret = 0;
00108 
00109 #if defined(POLARSSL_THREADING_C)
00110     if( ( ret = polarssl_mutex_lock( &ctx->mutex  ) ) != 0 )
00111         return( ret );
00112 #endif
00113 
00114     index = ctx->source_count;
00115     if( index >= ENTROPY_MAX_SOURCES )
00116     {
00117         ret = POLARSSL_ERR_ENTROPY_MAX_SOURCES;
00118         goto exit;
00119     }
00120 
00121     ctx->source[index].f_source = f_source;
00122     ctx->source[index].p_source = p_source;
00123     ctx->source[index].threshold = threshold;
00124 
00125     ctx->source_count++;
00126 
00127 exit:
00128 #if defined(POLARSSL_THREADING_C)
00129     if( polarssl_mutex_unlock( &ctx->mutex  ) != 0 )
00130         return( POLARSSL_ERR_THREADING_MUTEX_ERROR );
00131 #endif
00132 
00133     return( ret );
00134 }
00135 
00136 /*
00137  * Entropy accumulator update
00138  */
00139 static int entropy_update( entropy_context *ctx, unsigned char source_id,
00140                            const unsigned char *data, size_t len )
00141 {
00142     unsigned char header[2];
00143     unsigned char tmp[ENTROPY_BLOCK_SIZE];
00144     size_t use_len = len;
00145     const unsigned char *p = data;
00146 
00147     if( use_len > ENTROPY_BLOCK_SIZE )
00148     {
00149 #if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR)
00150         sha512( data, len, tmp, 0 );
00151 #else
00152         sha256( data, len, tmp, 0 );
00153 #endif
00154         p = tmp;
00155         use_len = ENTROPY_BLOCK_SIZE;
00156     }
00157 
00158     header[0] = source_id;
00159     header[1] = use_len & 0xFF;
00160 
00161 #if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR)
00162     sha512_update( &ctx->accumulator, header, 2 );
00163     sha512_update( &ctx->accumulator, p, use_len );
00164 #else
00165     sha256_update( &ctx->accumulator, header, 2 );
00166     sha256_update( &ctx->accumulator, p, use_len );
00167 #endif
00168 
00169     return( 0 );
00170 }
00171 
00172 int entropy_update_manual( entropy_context *ctx,
00173                            const unsigned char *data, size_t len )
00174 {
00175     int ret;
00176 
00177 #if defined(POLARSSL_THREADING_C)
00178     if( ( ret = polarssl_mutex_lock( &ctx->mutex  ) ) != 0 )
00179         return( ret );
00180 #endif
00181 
00182     ret = entropy_update( ctx, ENTROPY_SOURCE_MANUAL, data, len );
00183 
00184 #if defined(POLARSSL_THREADING_C)
00185     if( polarssl_mutex_unlock( &ctx->mutex  ) != 0 )
00186         return( POLARSSL_ERR_THREADING_MUTEX_ERROR );
00187 #endif
00188 
00189     return( ret );
00190 }
00191 
00192 /*
00193  * Run through the different sources to add entropy to our accumulator
00194  */
00195 static int entropy_gather_internal( entropy_context *ctx )
00196 {
00197     int ret, i;
00198     unsigned char buf[ENTROPY_MAX_GATHER];
00199     size_t olen;
00200 
00201     if( ctx->source_count == 0 )
00202         return( POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED );
00203 
00204     /*
00205      * Run through our entropy sources
00206      */
00207     for( i = 0; i < ctx->source_count; i++ )
00208     {
00209         olen = 0;
00210         if( ( ret = ctx->source[i].f_source( ctx->source[i].p_source,
00211                         buf, ENTROPY_MAX_GATHER, &olen ) ) != 0 )
00212         {
00213             return( ret );
00214         }
00215 
00216         /*
00217          * Add if we actually gathered something
00218          */
00219         if( olen > 0 )
00220         {
00221             entropy_update( ctx, (unsigned char) i, buf, olen );
00222             ctx->source[i].size += olen;
00223         }
00224     }
00225 
00226     return( 0 );
00227 }
00228 
00229 /*
00230  * Thread-safe wrapper for entropy_gather_internal()
00231  */
00232 int entropy_gather( entropy_context *ctx )
00233 {
00234     int ret;
00235 
00236 #if defined(POLARSSL_THREADING_C)
00237     if( ( ret = polarssl_mutex_lock( &ctx->mutex  ) ) != 0 )
00238         return( ret );
00239 #endif
00240 
00241     ret = entropy_gather_internal( ctx );
00242 
00243 #if defined(POLARSSL_THREADING_C)
00244     if( polarssl_mutex_unlock( &ctx->mutex  ) != 0 )
00245         return( POLARSSL_ERR_THREADING_MUTEX_ERROR );
00246 #endif
00247 
00248     return( ret );
00249 }
00250 
00251 int entropy_func( void *data, unsigned char *output, size_t len )
00252 {
00253     int ret, count = 0, i, reached;
00254     entropy_context *ctx = (entropy_context *) data;
00255     unsigned char buf[ENTROPY_BLOCK_SIZE];
00256 
00257     if( len > ENTROPY_BLOCK_SIZE )
00258         return( POLARSSL_ERR_ENTROPY_SOURCE_FAILED );
00259 
00260 #if defined(POLARSSL_THREADING_C)
00261     if( ( ret = polarssl_mutex_lock( &ctx->mutex  ) ) != 0 )
00262         return( ret );
00263 #endif
00264 
00265     /*
00266      * Always gather extra entropy before a call
00267      */
00268     do
00269     {
00270         if( count++ > ENTROPY_MAX_LOOP )
00271         {
00272             ret = POLARSSL_ERR_ENTROPY_SOURCE_FAILED;
00273             goto exit;
00274         }
00275 
00276         if( ( ret = entropy_gather_internal( ctx ) ) != 0 )
00277             goto exit;
00278 
00279         reached = 0;
00280 
00281         for( i = 0; i < ctx->source_count; i++ )
00282             if( ctx->source[i].size >= ctx->source[i].threshold )
00283                 reached++;
00284     }
00285     while( reached != ctx->source_count );
00286 
00287     memset( buf, 0, ENTROPY_BLOCK_SIZE );
00288 
00289 #if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR)
00290     sha512_finish( &ctx->accumulator, buf );
00291 
00292     /*
00293      * Reset accumulator and counters and recycle existing entropy
00294      */
00295     memset( &ctx->accumulator, 0, sizeof( sha512_context ) );
00296     sha512_starts( &ctx->accumulator, 0 );
00297     sha512_update( &ctx->accumulator, buf, ENTROPY_BLOCK_SIZE );
00298 
00299     /*
00300      * Perform second SHA-512 on entropy
00301      */
00302     sha512( buf, ENTROPY_BLOCK_SIZE, buf, 0 );
00303 #else /* POLARSSL_ENTROPY_SHA512_ACCUMULATOR */
00304     sha256_finish( &ctx->accumulator, buf );
00305 
00306     /*
00307      * Reset accumulator and counters and recycle existing entropy
00308      */
00309     memset( &ctx->accumulator, 0, sizeof( sha256_context ) );
00310     sha256_starts( &ctx->accumulator, 0 );
00311     sha256_update( &ctx->accumulator, buf, ENTROPY_BLOCK_SIZE );
00312 
00313     /*
00314      * Perform second SHA-256 on entropy
00315      */
00316     sha256( buf, ENTROPY_BLOCK_SIZE, buf, 0 );
00317 #endif /* POLARSSL_ENTROPY_SHA512_ACCUMULATOR */
00318 
00319     for( i = 0; i < ctx->source_count; i++ )
00320         ctx->source[i].size = 0;
00321 
00322     memcpy( output, buf, len );
00323 
00324     ret = 0;
00325 
00326 exit:
00327 #if defined(POLARSSL_THREADING_C)
00328     if( polarssl_mutex_unlock( &ctx->mutex  ) != 0 )
00329         return( POLARSSL_ERR_THREADING_MUTEX_ERROR );
00330 #endif
00331 
00332     return( ret );
00333 }
00334 
00335 #if defined(POLARSSL_FS_IO)
00336 int entropy_write_seed_file( entropy_context *ctx, const char *path )
00337 {
00338     int ret = POLARSSL_ERR_ENTROPY_FILE_IO_ERROR;
00339     FILE *f;
00340     unsigned char buf[ENTROPY_BLOCK_SIZE];
00341 
00342     if( ( f = fopen( path, "wb" ) ) == NULL )
00343         return( POLARSSL_ERR_ENTROPY_FILE_IO_ERROR );
00344 
00345     if( ( ret = entropy_func( ctx, buf, ENTROPY_BLOCK_SIZE ) ) != 0 )
00346         goto exit;
00347 
00348     if( fwrite( buf, 1, ENTROPY_BLOCK_SIZE, f ) != ENTROPY_BLOCK_SIZE )
00349     {
00350         ret = POLARSSL_ERR_ENTROPY_FILE_IO_ERROR;
00351         goto exit;
00352     }
00353 
00354     ret = 0;
00355 
00356 exit:
00357     fclose( f );
00358     return( ret );
00359 }
00360 
00361 int entropy_update_seed_file( entropy_context *ctx, const char *path )
00362 {
00363     FILE *f;
00364     size_t n;
00365     unsigned char buf[ ENTROPY_MAX_SEED_SIZE ];
00366 
00367     if( ( f = fopen( path, "rb" ) ) == NULL )
00368         return( POLARSSL_ERR_ENTROPY_FILE_IO_ERROR );
00369 
00370     fseek( f, 0, SEEK_END );
00371     n = (size_t) ftell( f );
00372     fseek( f, 0, SEEK_SET );
00373 
00374     if( n > ENTROPY_MAX_SEED_SIZE )
00375         n = ENTROPY_MAX_SEED_SIZE;
00376 
00377     if( fread( buf, 1, n, f ) != n )
00378     {
00379         fclose( f );
00380         return( POLARSSL_ERR_ENTROPY_FILE_IO_ERROR );
00381     }
00382 
00383     fclose( f );
00384 
00385     entropy_update_manual( ctx, buf, n );
00386 
00387     return( entropy_write_seed_file( ctx, path ) );
00388 }
00389 #endif /* POLARSSL_FS_IO */
00390 
00391 #if defined(POLARSSL_SELF_TEST)
00392 /*
00393  * Dummy source function
00394  */
00395 static int entropy_dummy_source( void *data, unsigned char *output,
00396                                  size_t len, size_t *olen )
00397 {
00398     ((void) data);
00399 
00400     memset( output, 0x2a, len );
00401     *olen = len;
00402 
00403     return( 0 );
00404 }
00405 
00406 /*
00407  * The actual entropy quality is hard to test, but we can at least
00408  * test that the functions don't cause errors and write the correct
00409  * amount of data to buffers.
00410  */
00411 int entropy_self_test( int verbose )
00412 {
00413     int ret = 0;
00414     entropy_context ctx;
00415     unsigned char buf[ENTROPY_BLOCK_SIZE] = { 0 };
00416     unsigned char acc[ENTROPY_BLOCK_SIZE] = { 0 };
00417     size_t i, j;
00418 
00419     if( verbose != 0 )
00420         polarssl_printf( "  ENTROPY test: " );
00421 
00422     entropy_init( &ctx );
00423 
00424     ret = entropy_add_source( &ctx, entropy_dummy_source, NULL, 16 );
00425     if( ret != 0 )
00426         goto cleanup;
00427 
00428     if( ( ret = entropy_gather( &ctx ) ) != 0 )
00429         goto cleanup;
00430 
00431     if( ( ret = entropy_update_manual( &ctx, buf, sizeof buf ) ) != 0 )
00432         goto cleanup;
00433 
00434     /*
00435      * To test that entropy_func writes correct number of bytes:
00436      * - use the whole buffer and rely on ASan to detect overruns
00437      * - collect entropy 8 times and OR the result in an accumulator:
00438      *   any byte should then be 0 with probably 2^(-64), so requiring
00439      *   each of the 32 or 64 bytes to be non-zero has a false failure rate
00440      *   of at most 2^(-58) which is acceptable.
00441      */
00442     for( i = 0; i < 8; i++ )
00443     {
00444         if( ( ret = entropy_func( &ctx, buf, sizeof( buf ) ) ) != 0 )
00445             goto cleanup;
00446 
00447         for( j = 0; j < sizeof( buf ); j++ )
00448             acc[j] |= buf[j];
00449     }
00450 
00451     for( j = 0; j < sizeof( buf ); j++ )
00452     {
00453         if( acc[j] == 0 )
00454         {
00455             ret = 1;
00456             goto cleanup;
00457         }
00458     }
00459 
00460 cleanup:
00461     entropy_free( &ctx );
00462 
00463     if( verbose != 0 )
00464     {
00465         if( ret != 0 )
00466             polarssl_printf( "failed\n" );
00467         else
00468             polarssl_printf( "passed\n" );
00469 
00470         polarssl_printf( "\n" );
00471     }
00472 
00473     return( ret != 0 );
00474 }
00475 #endif /* POLARSSL_SELF_TEST */
00476 
00477 #endif /* POLARSSL_ENTROPY_C */
00478