mbedtls ported to mbed-classic

Fork of mbedtls by Christopher Haster

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-2015, ARM Limited, All Rights Reserved
00005  *  SPDX-License-Identifier: Apache-2.0
00006  *
00007  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
00008  *  not use this file except in compliance with the License.
00009  *  You may obtain a copy of the License at
00010  *
00011  *  http://www.apache.org/licenses/LICENSE-2.0
00012  *
00013  *  Unless required by applicable law or agreed to in writing, software
00014  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00015  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00016  *  See the License for the specific language governing permissions and
00017  *  limitations under the License.
00018  *
00019  *  This file is part of mbed TLS (https://tls.mbed.org)
00020  */
00021 
00022 #if !defined(MBEDTLS_CONFIG_FILE)
00023 #include "mbedtls/config.h"
00024 #else
00025 #include MBEDTLS_CONFIG_FILE
00026 #endif
00027 
00028 #if defined(MBEDTLS_ENTROPY_C)
00029 
00030 #include "mbedtls/entropy.h"
00031 #include "mbedtls/entropy_poll.h"
00032 
00033 #include <string.h>
00034 
00035 #if defined(MBEDTLS_FS_IO)
00036 #include <stdio.h>
00037 #endif
00038 
00039 #if defined(MBEDTLS_SELF_TEST)
00040 #if defined(MBEDTLS_PLATFORM_C)
00041 #include "mbedtls/platform.h"
00042 #else
00043 #include <stdio.h>
00044 #define mbedtls_printf     printf
00045 #endif /* MBEDTLS_PLATFORM_C */
00046 #endif /* MBEDTLS_SELF_TEST */
00047 
00048 #if defined(MBEDTLS_HAVEGE_C)
00049 #include "mbedtls/havege.h"
00050 #endif
00051 
00052 /* Implementation that should never be optimized out by the compiler */
00053 static void mbedtls_zeroize( void *v, size_t n ) {
00054     volatile unsigned char *p = v; while( n-- ) *p++ = 0;
00055 }
00056 
00057 #define ENTROPY_MAX_LOOP    256     /**< Maximum amount to loop before error */
00058 
00059 void mbedtls_entropy_init( mbedtls_entropy_context *ctx )
00060 {
00061     memset( ctx, 0, sizeof(mbedtls_entropy_context) );
00062 
00063 #if defined(MBEDTLS_THREADING_C)
00064     mbedtls_mutex_init( &ctx->mutex  );
00065 #endif
00066 
00067 #if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
00068     mbedtls_sha512_starts( &ctx->accumulator, 0 );
00069 #else
00070     mbedtls_sha256_starts( &ctx->accumulator, 0 );
00071 #endif
00072 #if defined(MBEDTLS_HAVEGE_C)
00073     mbedtls_havege_init( &ctx->havege_data );
00074 #endif
00075 
00076 #if !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES)
00077 #if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
00078     mbedtls_entropy_add_source( ctx, mbedtls_platform_entropy_poll, NULL,
00079                                 MBEDTLS_ENTROPY_MIN_PLATFORM,
00080                                 MBEDTLS_ENTROPY_SOURCE_STRONG );
00081 #endif
00082 #if defined(MBEDTLS_TIMING_C)
00083     mbedtls_entropy_add_source( ctx, mbedtls_hardclock_poll, NULL,
00084                                 MBEDTLS_ENTROPY_MIN_HARDCLOCK,
00085                                 MBEDTLS_ENTROPY_SOURCE_WEAK );
00086 #endif
00087 #if defined(MBEDTLS_HAVEGE_C)
00088     mbedtls_entropy_add_source( ctx, mbedtls_havege_poll, &ctx->havege_data,
00089                                 MBEDTLS_ENTROPY_MIN_HAVEGE,
00090                                 MBEDTLS_ENTROPY_SOURCE_STRONG );
00091 #endif
00092 #if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
00093     mbedtls_entropy_add_source( ctx, mbedtls_hardware_poll, NULL,
00094                                 MBEDTLS_ENTROPY_MIN_HARDWARE,
00095                                 MBEDTLS_ENTROPY_SOURCE_STRONG );
00096 #endif
00097 #endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */
00098 }
00099 
00100 void mbedtls_entropy_free( mbedtls_entropy_context *ctx )
00101 {
00102 #if defined(MBEDTLS_HAVEGE_C)
00103     mbedtls_havege_free( &ctx->havege_data );
00104 #endif
00105 #if defined(MBEDTLS_THREADING_C)
00106     mbedtls_mutex_free( &ctx->mutex  );
00107 #endif
00108     mbedtls_zeroize( ctx, sizeof( mbedtls_entropy_context ) );
00109 }
00110 
00111 int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx,
00112                         mbedtls_entropy_f_source_ptr f_source, void *p_source,
00113                         size_t threshold, int strong )
00114 {
00115     int index, ret = 0;
00116 
00117 #if defined(MBEDTLS_THREADING_C)
00118     if( ( ret = mbedtls_mutex_lock( &ctx->mutex  ) ) != 0 )
00119         return( ret );
00120 #endif
00121 
00122     index = ctx->source_count;
00123     if( index >= MBEDTLS_ENTROPY_MAX_SOURCES )
00124     {
00125         ret = MBEDTLS_ERR_ENTROPY_MAX_SOURCES;
00126         goto exit;
00127     }
00128 
00129     ctx->source[index].f_source  = f_source;
00130     ctx->source[index].p_source  = p_source;
00131     ctx->source[index].threshold = threshold;
00132     ctx->source[index].strong    = strong;
00133 
00134     ctx->source_count++;
00135 
00136 exit:
00137 #if defined(MBEDTLS_THREADING_C)
00138     if( mbedtls_mutex_unlock( &ctx->mutex  ) != 0 )
00139         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
00140 #endif
00141 
00142     return( ret );
00143 }
00144 
00145 /*
00146  * Entropy accumulator update
00147  */
00148 static int entropy_update( mbedtls_entropy_context *ctx, unsigned char source_id,
00149                            const unsigned char *data, size_t len )
00150 {
00151     unsigned char header[2];
00152     unsigned char tmp[MBEDTLS_ENTROPY_BLOCK_SIZE];
00153     size_t use_len = len;
00154     const unsigned char *p = data;
00155 
00156     if( use_len > MBEDTLS_ENTROPY_BLOCK_SIZE )
00157     {
00158 #if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
00159         mbedtls_sha512( data, len, tmp, 0 );
00160 #else
00161         mbedtls_sha256( data, len, tmp, 0 );
00162 #endif
00163         p = tmp;
00164         use_len = MBEDTLS_ENTROPY_BLOCK_SIZE;
00165     }
00166 
00167     header[0] = source_id;
00168     header[1] = use_len & 0xFF;
00169 
00170 #if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
00171     mbedtls_sha512_update( &ctx->accumulator, header, 2 );
00172     mbedtls_sha512_update( &ctx->accumulator, p, use_len );
00173 #else
00174     mbedtls_sha256_update( &ctx->accumulator, header, 2 );
00175     mbedtls_sha256_update( &ctx->accumulator, p, use_len );
00176 #endif
00177 
00178     return( 0 );
00179 }
00180 
00181 int mbedtls_entropy_update_manual( mbedtls_entropy_context *ctx,
00182                            const unsigned char *data, size_t len )
00183 {
00184     int ret;
00185 
00186 #if defined(MBEDTLS_THREADING_C)
00187     if( ( ret = mbedtls_mutex_lock( &ctx->mutex  ) ) != 0 )
00188         return( ret );
00189 #endif
00190 
00191     ret = entropy_update( ctx, MBEDTLS_ENTROPY_SOURCE_MANUAL, data, len );
00192 
00193 #if defined(MBEDTLS_THREADING_C)
00194     if( mbedtls_mutex_unlock( &ctx->mutex  ) != 0 )
00195         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
00196 #endif
00197 
00198     return( ret );
00199 }
00200 
00201 /*
00202  * Run through the different sources to add entropy to our accumulator
00203  */
00204 static int entropy_gather_internal( mbedtls_entropy_context *ctx )
00205 {
00206     int ret, i, have_one_strong = 0;
00207     unsigned char buf[MBEDTLS_ENTROPY_MAX_GATHER];
00208     size_t olen;
00209 
00210     if( ctx->source_count == 0 )
00211         return( MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED );
00212 
00213     /*
00214      * Run through our entropy sources
00215      */
00216     for( i = 0; i < ctx->source_count; i++ )
00217     {
00218         if( ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG )
00219             have_one_strong = 1;
00220 
00221         olen = 0;
00222         if( ( ret = ctx->source[i].f_source( ctx->source[i].p_source,
00223                         buf, MBEDTLS_ENTROPY_MAX_GATHER, &olen ) ) != 0 )
00224         {
00225             return( ret );
00226         }
00227 
00228         /*
00229          * Add if we actually gathered something
00230          */
00231         if( olen > 0 )
00232         {
00233             entropy_update( ctx, (unsigned char) i, buf, olen );
00234             ctx->source[i].size += olen;
00235         }
00236     }
00237 
00238     if( have_one_strong == 0 )
00239         return( MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE );
00240 
00241     return( 0 );
00242 }
00243 
00244 /*
00245  * Thread-safe wrapper for entropy_gather_internal()
00246  */
00247 int mbedtls_entropy_gather( mbedtls_entropy_context *ctx )
00248 {
00249     int ret;
00250 
00251 #if defined(MBEDTLS_THREADING_C)
00252     if( ( ret = mbedtls_mutex_lock( &ctx->mutex  ) ) != 0 )
00253         return( ret );
00254 #endif
00255 
00256     ret = entropy_gather_internal( ctx );
00257 
00258 #if defined(MBEDTLS_THREADING_C)
00259     if( mbedtls_mutex_unlock( &ctx->mutex  ) != 0 )
00260         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
00261 #endif
00262 
00263     return( ret );
00264 }
00265 
00266 int mbedtls_entropy_func( void *data, unsigned char *output, size_t len )
00267 {
00268     int ret, count = 0, i, done;
00269     mbedtls_entropy_context *ctx = (mbedtls_entropy_context *) data;
00270     unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
00271 
00272     if( len > MBEDTLS_ENTROPY_BLOCK_SIZE )
00273         return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
00274 
00275 #if defined(MBEDTLS_THREADING_C)
00276     if( ( ret = mbedtls_mutex_lock( &ctx->mutex  ) ) != 0 )
00277         return( ret );
00278 #endif
00279 
00280     /*
00281      * Always gather extra entropy before a call
00282      */
00283     do
00284     {
00285         if( count++ > ENTROPY_MAX_LOOP )
00286         {
00287             ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
00288             goto exit;
00289         }
00290 
00291         if( ( ret = entropy_gather_internal( ctx ) ) != 0 )
00292             goto exit;
00293 
00294         done = 1;
00295         for( i = 0; i < ctx->source_count; i++ )
00296             if( ctx->source[i].size < ctx->source[i].threshold )
00297                 done = 0;
00298     }
00299     while( ! done );
00300 
00301     memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE );
00302 
00303 #if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
00304     mbedtls_sha512_finish( &ctx->accumulator, buf );
00305 
00306     /*
00307      * Reset accumulator and counters and recycle existing entropy
00308      */
00309     memset( &ctx->accumulator, 0, sizeof( mbedtls_sha512_context ) );
00310     mbedtls_sha512_starts( &ctx->accumulator, 0 );
00311     mbedtls_sha512_update( &ctx->accumulator, buf, MBEDTLS_ENTROPY_BLOCK_SIZE );
00312 
00313     /*
00314      * Perform second SHA-512 on entropy
00315      */
00316     mbedtls_sha512( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf, 0 );
00317 #else /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */
00318     mbedtls_sha256_finish( &ctx->accumulator, buf );
00319 
00320     /*
00321      * Reset accumulator and counters and recycle existing entropy
00322      */
00323     memset( &ctx->accumulator, 0, sizeof( mbedtls_sha256_context ) );
00324     mbedtls_sha256_starts( &ctx->accumulator, 0 );
00325     mbedtls_sha256_update( &ctx->accumulator, buf, MBEDTLS_ENTROPY_BLOCK_SIZE );
00326 
00327     /*
00328      * Perform second SHA-256 on entropy
00329      */
00330     mbedtls_sha256( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf, 0 );
00331 #endif /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */
00332 
00333     for( i = 0; i < ctx->source_count; i++ )
00334         ctx->source[i].size = 0;
00335 
00336     memcpy( output, buf, len );
00337 
00338     ret = 0;
00339 
00340 exit:
00341 #if defined(MBEDTLS_THREADING_C)
00342     if( mbedtls_mutex_unlock( &ctx->mutex  ) != 0 )
00343         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
00344 #endif
00345 
00346     return( ret );
00347 }
00348 
00349 #if defined(MBEDTLS_FS_IO)
00350 int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *path )
00351 {
00352     int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
00353     FILE *f;
00354     unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
00355 
00356     if( ( f = fopen( path, "wb" ) ) == NULL )
00357         return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR );
00358 
00359     if( ( ret = mbedtls_entropy_func( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 )
00360         goto exit;
00361 
00362     if( fwrite( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) != MBEDTLS_ENTROPY_BLOCK_SIZE )
00363     {
00364         ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
00365         goto exit;
00366     }
00367 
00368     ret = 0;
00369 
00370 exit:
00371     fclose( f );
00372     return( ret );
00373 }
00374 
00375 int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *path )
00376 {
00377     FILE *f;
00378     size_t n;
00379     unsigned char buf[ MBEDTLS_ENTROPY_MAX_SEED_SIZE ];
00380 
00381     if( ( f = fopen( path, "rb" ) ) == NULL )
00382         return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR );
00383 
00384     fseek( f, 0, SEEK_END );
00385     n = (size_t) ftell( f );
00386     fseek( f, 0, SEEK_SET );
00387 
00388     if( n > MBEDTLS_ENTROPY_MAX_SEED_SIZE )
00389         n = MBEDTLS_ENTROPY_MAX_SEED_SIZE;
00390 
00391     if( fread( buf, 1, n, f ) != n )
00392     {
00393         fclose( f );
00394         return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR );
00395     }
00396 
00397     fclose( f );
00398 
00399     mbedtls_entropy_update_manual( ctx, buf, n );
00400 
00401     return( mbedtls_entropy_write_seed_file( ctx, path ) );
00402 }
00403 #endif /* MBEDTLS_FS_IO */
00404 
00405 #if defined(MBEDTLS_SELF_TEST)
00406 /*
00407  * Dummy source function
00408  */
00409 static int entropy_dummy_source( void *data, unsigned char *output,
00410                                  size_t len, size_t *olen )
00411 {
00412     ((void) data);
00413 
00414     memset( output, 0x2a, len );
00415     *olen = len;
00416 
00417     return( 0 );
00418 }
00419 
00420 /*
00421  * The actual entropy quality is hard to test, but we can at least
00422  * test that the functions don't cause errors and write the correct
00423  * amount of data to buffers.
00424  */
00425 int mbedtls_entropy_self_test( int verbose )
00426 {
00427     int ret = 0;
00428     mbedtls_entropy_context ctx;
00429     unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 };
00430     unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 };
00431     size_t i, j;
00432 
00433     if( verbose != 0 )
00434         mbedtls_printf( "  ENTROPY test: " );
00435 
00436     mbedtls_entropy_init( &ctx );
00437 
00438     /* First do a gather to make sure we have default sources */
00439     if( ( ret = mbedtls_entropy_gather( &ctx ) ) != 0 )
00440         goto cleanup;
00441 
00442     ret = mbedtls_entropy_add_source( &ctx, entropy_dummy_source, NULL, 16,
00443                                       MBEDTLS_ENTROPY_SOURCE_WEAK );
00444     if( ret != 0 )
00445         goto cleanup;
00446 
00447     if( ( ret = mbedtls_entropy_update_manual( &ctx, buf, sizeof buf ) ) != 0 )
00448         goto cleanup;
00449 
00450     /*
00451      * To test that mbedtls_entropy_func writes correct number of bytes:
00452      * - use the whole buffer and rely on ASan to detect overruns
00453      * - collect entropy 8 times and OR the result in an accumulator:
00454      *   any byte should then be 0 with probably 2^(-64), so requiring
00455      *   each of the 32 or 64 bytes to be non-zero has a false failure rate
00456      *   of at most 2^(-58) which is acceptable.
00457      */
00458     for( i = 0; i < 8; i++ )
00459     {
00460         if( ( ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ) ) != 0 )
00461             goto cleanup;
00462 
00463         for( j = 0; j < sizeof( buf ); j++ )
00464             acc[j] |= buf[j];
00465     }
00466 
00467     for( j = 0; j < sizeof( buf ); j++ )
00468     {
00469         if( acc[j] == 0 )
00470         {
00471             ret = 1;
00472             goto cleanup;
00473         }
00474     }
00475 
00476 cleanup:
00477     mbedtls_entropy_free( &ctx );
00478 
00479     if( verbose != 0 )
00480     {
00481         if( ret != 0 )
00482             mbedtls_printf( "failed\n" );
00483         else
00484             mbedtls_printf( "passed\n" );
00485 
00486         mbedtls_printf( "\n" );
00487     }
00488 
00489     return( ret != 0 );
00490 }
00491 #endif /* MBEDTLS_SELF_TEST */
00492 
00493 #endif /* MBEDTLS_ENTROPY_C */