From d9aa84dc0d42dcb5e23ba2bb47ce39592193b8f1 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 11 Sep 2018 15:34:17 +0200 Subject: [PATCH 1/9] CTR_DRBG: clean stack buffers Wipe stack buffers that may contain sensitive data (data that contributes to the DRBG state. --- library/ctr_drbg.c | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c index fead18f72..559538121 100644 --- a/library/ctr_drbg.c +++ b/library/ctr_drbg.c @@ -299,9 +299,7 @@ static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx, * Crypt counter block */ if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, p ) ) != 0 ) - { - return( ret ); - } + goto exit; p += MBEDTLS_CTR_DRBG_BLOCKSIZE; } @@ -313,12 +311,12 @@ static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx, * Update key and counter */ if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 ) - { - return( ret ); - } + goto exit; memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE, MBEDTLS_CTR_DRBG_BLOCKSIZE ); - return( 0 ); +exit: + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + return( ret ); } /* CTR_DRBG_Instantiate with derivation function (SP 800-90A §10.2.1.3.2) @@ -347,6 +345,7 @@ void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, block_cipher_df( add_input, additional, add_len ); ctr_drbg_update_internal( ctx, add_input ); + mbedtls_platform_zeroize( add_input, sizeof( add_input ) ); } } @@ -399,20 +398,18 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, * Reduce to 384 bits */ if( ( ret = block_cipher_df( seed, seed, seedlen ) ) != 0 ) - { - return( ret ); - } + goto exit; /* * Update state */ if( ( ret = ctr_drbg_update_internal( ctx, seed ) ) != 0 ) - { - return( ret ); - } + goto exit; ctx->reseed_counter = 1; - return( 0 ); +exit: + mbedtls_platform_zeroize( seed, sizeof( seed ) ); + return( ret ); } /* CTR_DRBG_Generate with derivation function (SP 800-90A §10.2.1.5.2) @@ -467,13 +464,9 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng, if( add_len > 0 ) { if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 ) - { - return( ret ); - } + goto exit; if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 ) - { - return( ret ); - } + goto exit; } while( output_len > 0 ) @@ -489,9 +482,7 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng, * Crypt counter block */ if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, tmp ) ) != 0 ) - { - return( ret ); - } + goto exit; use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE ) ? MBEDTLS_CTR_DRBG_BLOCKSIZE : output_len; @@ -504,12 +495,13 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng, } if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 ) - { - return( ret ); - } + goto exit; ctx->reseed_counter++; +exit: + mbedtls_platform_zeroize( add_input, sizeof( add_input ) ); + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); return( 0 ); } From afa803775a1bf4f5bd0cd147bf4984785b576a04 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 11 Sep 2018 15:35:41 +0200 Subject: [PATCH 2/9] HMAC_DRBG: clean stack buffers Wipe stack buffers that may contain sensitive data (data that contributes to the DRBG state. --- library/hmac_drbg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/hmac_drbg.c b/library/hmac_drbg.c index dad55ff86..65c8daccd 100644 --- a/library/hmac_drbg.c +++ b/library/hmac_drbg.c @@ -89,6 +89,8 @@ void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ); } + + mbedtls_platform_zeroize( K, sizeof( K ) ); } /* @@ -154,6 +156,7 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, ctx->reseed_counter = 1; /* 4. Done */ + mbedtls_platform_zeroize( seed, seedlen ); return( 0 ); } From 1b09f4027e1b2ad6c383e8f1f50ce8a9bc9e5804 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 11 Sep 2018 18:53:58 +0200 Subject: [PATCH 3/9] Add ChangeLog entry for wiping sensitive buffers --- ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 8f0e8c1c7..3d0c7e8ba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ mbed TLS ChangeLog (Sorted per branch, date) += mbed TLS 2.x.x branch released xxxx-xx-xx + +Security + * Wipe sensitive buffers on the stack in the CTR_DRBG and HMAC_DRBG + modules. + = mbed TLS 2.14.0 branch released 2018-11-19 Security From d919993b76e51e6d822e5eb0af1d7ce1e23964bf Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 11 Sep 2018 16:41:54 +0200 Subject: [PATCH 4/9] CTR_DRBG: deprecate mbedtls_ctr_drbg_update because it ignores errors Deprecate mbedtls_ctr_drbg_update (which returns void) in favor of a new function mbedtls_ctr_drbg_update_ret which reports error. --- include/mbedtls/ctr_drbg.h | 36 ++++++++++++++++++-- library/ctr_drbg.c | 41 ++++++++++++++++------- tests/suites/test_suite_ctr_drbg.function | 8 +++-- 3 files changed, 67 insertions(+), 18 deletions(-) diff --git a/include/mbedtls/ctr_drbg.h b/include/mbedtls/ctr_drbg.h index c91ca58b3..9a3aba0d3 100644 --- a/include/mbedtls/ctr_drbg.h +++ b/include/mbedtls/ctr_drbg.h @@ -248,9 +248,12 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, * \param additional The data to update the state with. * \param add_len Length of \p additional data. * + * \return \c 0 on success. + * \return An error from the underlying AES cipher on failure. */ -void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, - const unsigned char *additional, size_t add_len ); +int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ); /** * \brief This function updates a CTR_DRBG instance with additional @@ -290,6 +293,35 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng, int mbedtls_ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len ); + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function updates the state of the CTR_DRBG context. + * + * \deprecated Superseded by mbedtls_ctr_drbg_update_ret() + * in 2.16.0. + * + * \note If \p add_len is greater than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, only the first + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT Bytes are used. + * The remaining Bytes are silently discarded. + * + * \param ctx The CTR_DRBG context. + * \param additional The data to update the state with. + * \param add_len Length of \p additional data. + */ +MBEDTLS_DEPRECATED void mbedtls_ctr_drbg_update( + mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ); +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + #if defined(MBEDTLS_FS_IO) /** * \brief This function writes a seed file. diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c index 559538121..a264dedb0 100644 --- a/library/ctr_drbg.c +++ b/library/ctr_drbg.c @@ -331,24 +331,39 @@ exit: * and with outputs * ctx = initial_working_state */ -void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, - const unsigned char *additional, size_t add_len ) +int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ) { unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; + int ret; - if( add_len > 0 ) - { - /* MAX_INPUT would be more logical here, but we have to match - * block_cipher_df()'s limits since we can't propagate errors */ - if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) - add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT; + if( add_len == 0 ) + return( 0 ); - block_cipher_df( add_input, additional, add_len ); - ctr_drbg_update_internal( ctx, add_input ); - mbedtls_platform_zeroize( add_input, sizeof( add_input ) ); - } + if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 ) + goto exit; + if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 ) + goto exit; + +exit: + mbedtls_platform_zeroize( add_input, sizeof( add_input ) ); + return( ret ); } +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ) +{ + /* MAX_INPUT would be more logical here, but we have to match + * block_cipher_df()'s limits since we can't propagate errors */ + if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) + add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT; + (void) mbedtls_ctr_drbg_update_ret( ctx, additional, add_len ); +} +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + /* CTR_DRBG_Reseed with derivation function (SP 800-90A §10.2.1.4.2) * mbedtls_ctr_drbg_reseed(ctx, additional, len) * implements @@ -573,7 +588,7 @@ int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char if( fread( buf, 1, n, f ) != n ) ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; else - mbedtls_ctr_drbg_update( ctx, buf, n ); + ret = mbedtls_ctr_drbg_update_ret( ctx, buf, n ); fclose( f ); diff --git a/tests/suites/test_suite_ctr_drbg.function b/tests/suites/test_suite_ctr_drbg.function index f10e98aa5..4a97826f6 100644 --- a/tests/suites/test_suite_ctr_drbg.function +++ b/tests/suites/test_suite_ctr_drbg.function @@ -244,9 +244,11 @@ void ctr_drbg_entropy_usage( ) } TEST_ASSERT( last_idx == test_offset_idx ); - /* Call update with too much data (sizeof entropy > MAX(_SEED)_INPUT) - * (just make sure it doesn't cause memory corruption) */ - mbedtls_ctr_drbg_update( &ctx, entropy, sizeof( entropy ) ); + /* Call update with too much data (sizeof entropy > MAX(_SEED)_INPUT). + * Make sure it's detected as an error and doesn't cause memory + * corruption. */ + TEST_ASSERT( mbedtls_ctr_drbg_update_ret( + &ctx, entropy, sizeof( entropy ) ) != 0 ); /* Now enable PR, so the next few calls should all reseed */ mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON ); From e0e9c573ad613bdb897cd548ec55a96b3f843190 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 11 Sep 2018 16:47:16 +0200 Subject: [PATCH 5/9] HMAC_DRBG: deprecate mbedtls_hmac_drbg_update because it ignores errors Deprecate mbedtls_hmac_drbg_update (which returns void) in favor of a new function mbedtls_hmac_drbg_update_ret which reports error. --- include/mbedtls/hmac_drbg.h | 30 ++++++++++++++- library/hmac_drbg.c | 73 ++++++++++++++++++++++++++++--------- 2 files changed, 84 insertions(+), 19 deletions(-) diff --git a/include/mbedtls/hmac_drbg.h b/include/mbedtls/hmac_drbg.h index 3bc675ec7..146367b9d 100644 --- a/include/mbedtls/hmac_drbg.h +++ b/include/mbedtls/hmac_drbg.h @@ -195,10 +195,13 @@ void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx, * \param additional Additional data to update state with, or NULL * \param add_len Length of additional data, or 0 * + * \return \c 0 on success, or an error from the underlying + * hash calculation. + * * \note Additional data is optional, pass NULL and 0 as second * third argument if no additional data is being used. */ -void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, +int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx, const unsigned char *additional, size_t add_len ); /** @@ -257,6 +260,31 @@ int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len */ void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx ); +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief HMAC_DRBG update state + * + * \deprecated Superseded by mbedtls_hmac_drbg_update_ret() + * in 2.16.0. + * + * \param ctx HMAC_DRBG context + * \param additional Additional data to update state with, or NULL + * \param add_len Length of additional data, or 0 + * + * \note Additional data is optional, pass NULL and 0 as second + * third argument if no additional data is being used. + */ +MBEDTLS_DEPRECATED void mbedtls_hmac_drbg_update( + mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + #if defined(MBEDTLS_FS_IO) /** * \brief Write a seed file diff --git a/library/hmac_drbg.c b/library/hmac_drbg.c index 65c8daccd..7f6535477 100644 --- a/library/hmac_drbg.c +++ b/library/hmac_drbg.c @@ -66,33 +66,60 @@ void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx ) /* * HMAC_DRBG update, using optional additional data (10.1.2.2) */ -void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, - const unsigned char *additional, size_t add_len ) +int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ) { size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info ); unsigned char rounds = ( additional != NULL && add_len != 0 ) ? 2 : 1; unsigned char sep[1]; unsigned char K[MBEDTLS_MD_MAX_SIZE]; + int ret; for( sep[0] = 0; sep[0] < rounds; sep[0]++ ) { /* Step 1 or 4 */ - mbedtls_md_hmac_reset( &ctx->md_ctx ); - mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); - mbedtls_md_hmac_update( &ctx->md_ctx, sep, 1 ); + if( ( ret = mbedtls_md_hmac_reset( &ctx->md_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + ctx->V, md_len ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + sep, 1 ) ) != 0 ) + goto exit; if( rounds == 2 ) - mbedtls_md_hmac_update( &ctx->md_ctx, additional, add_len ); - mbedtls_md_hmac_finish( &ctx->md_ctx, K ); + { + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + additional, add_len ) ) != 0 ) + goto exit; + } + if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, K ) ) != 0 ) + goto exit; /* Step 2 or 5 */ - mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len ); - mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); - mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ); + if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + ctx->V, md_len ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ) ) != 0 ) + goto exit; } +exit: mbedtls_platform_zeroize( K, sizeof( K ) ); + return( ret ); } +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ) +{ + (void) mbedtls_hmac_drbg_update_ret( ctx, additional, add_len ); +} +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + /* * Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA) */ @@ -113,7 +140,8 @@ int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx, mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, mbedtls_md_get_size( md_info ) ); memset( ctx->V, 0x01, mbedtls_md_get_size( md_info ) ); - mbedtls_hmac_drbg_update( ctx, data, data_len ); + if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, data, data_len ) ) != 0 ) + return( ret ); return( 0 ); } @@ -126,6 +154,7 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, { unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT]; size_t seedlen; + int ret; /* III. Check input length */ if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT || @@ -150,14 +179,16 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, } /* 2. Update state */ - mbedtls_hmac_drbg_update( ctx, seed, seedlen ); + if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, seed, seedlen ) ) != 0 ) + goto exit; /* 3. Reset reseed_counter */ ctx->reseed_counter = 1; +exit: /* 4. Done */ mbedtls_platform_zeroize( seed, seedlen ); - return( 0 ); + return( ret ); } /* @@ -276,7 +307,11 @@ int mbedtls_hmac_drbg_random_with_add( void *p_rng, /* 2. Use additional data if any */ if( additional != NULL && add_len != 0 ) - mbedtls_hmac_drbg_update( ctx, additional, add_len ); + { + if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, + additional, add_len ) ) != 0 ) + goto exit; + } /* 3, 4, 5. Generate bytes */ while( left != 0 ) @@ -293,13 +328,16 @@ int mbedtls_hmac_drbg_random_with_add( void *p_rng, } /* 6. Update */ - mbedtls_hmac_drbg_update( ctx, additional, add_len ); + if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, + additional, add_len ) ) != 0 ) + goto exit; /* 7. Update reseed counter */ ctx->reseed_counter++; +exit: /* 8. Done */ - return( 0 ); + return( ret ); } /* @@ -391,8 +429,7 @@ int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const ch if( fread( buf, 1, n, f ) != n ) ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; else - mbedtls_hmac_drbg_update( ctx, buf, n ); - + ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n ); fclose( f ); mbedtls_platform_zeroize( buf, sizeof( buf ) ); From b7f71c8bc1f84584b7aec8c6c02bbd693d3be21f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 11 Sep 2018 16:54:57 +0200 Subject: [PATCH 6/9] HMAC_DRBG: report all errors from HMAC functions Make sure that any error from mbedtls_md_hmac_xxx is propagated. --- library/hmac_drbg.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/library/hmac_drbg.c b/library/hmac_drbg.c index 7f6535477..d5ac2f6ad 100644 --- a/library/hmac_drbg.c +++ b/library/hmac_drbg.c @@ -137,7 +137,9 @@ int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx, * Use the V memory location, which is currently all 0, to initialize the * MD context with an all-zero key. Then set V to its initial value. */ - mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, mbedtls_md_get_size( md_info ) ); + if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, + mbedtls_md_get_size( md_info ) ) ) != 0 ) + return( ret ); memset( ctx->V, 0x01, mbedtls_md_get_size( md_info ) ); if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, data, data_len ) ) != 0 ) @@ -166,7 +168,8 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, memset( seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ); /* IV. Gather entropy_len bytes of entropy for the seed */ - if( ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) != 0 ) + if( ( ret = ctx->f_entropy( ctx->p_entropy, + seed, ctx->entropy_len ) ) != 0 ) return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED ); seedlen = ctx->entropy_len; @@ -214,7 +217,8 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, * Use the V memory location, which is currently all 0, to initialize the * MD context with an all-zero key. Then set V to its initial value. */ - mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size ); + if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size ) ) != 0 ) + return( ret ); memset( ctx->V, 0x01, md_size ); ctx->f_entropy = f_entropy; @@ -318,9 +322,13 @@ int mbedtls_hmac_drbg_random_with_add( void *p_rng, { size_t use_len = left > md_len ? md_len : left; - mbedtls_md_hmac_reset( &ctx->md_ctx ); - mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); - mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ); + if( ( ret = mbedtls_md_hmac_reset( &ctx->md_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + ctx->V, md_len ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ) ) != 0 ) + goto exit; memcpy( out, ctx->V, use_len ); out += use_len; @@ -430,6 +438,7 @@ int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const ch ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; else ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n ); + fclose( f ); mbedtls_platform_zeroize( buf, sizeof( buf ) ); From 8220466297a06e91944151d4a1e2f7781e3011ae Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 11 Sep 2018 18:43:09 +0200 Subject: [PATCH 7/9] Streamline mbedtls_xxx_drbg_update_seed_file Refactor mbedtls_ctr_drbg_update_seed_file and mbedtls_hmac_drbg_update_seed_file to make the error logic clearer. The new code does not use fseek, so it works with non-seekable files. --- library/ctr_drbg.c | 31 ++++++++++++++++--------------- library/hmac_drbg.c | 31 ++++++++++++++++--------------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c index a264dedb0..fb121575b 100644 --- a/library/ctr_drbg.c +++ b/library/ctr_drbg.c @@ -568,35 +568,36 @@ exit: int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ) { int ret = 0; - FILE *f; + FILE *f = NULL; size_t n; unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ]; + unsigned char c; if( ( f = fopen( path, "rb" ) ) == NULL ) return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); - fseek( f, 0, SEEK_END ); - n = (size_t) ftell( f ); - fseek( f, 0, SEEK_SET ); - - if( n > MBEDTLS_CTR_DRBG_MAX_INPUT ) + n = fread( buf, 1, sizeof( buf ), f ); + if( fread( &c, 1, 1, f ) != 0 ) { - fclose( f ); - return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; + goto exit; } - - if( fread( buf, 1, n, f ) != n ) + if( n == 0 || ferror( f ) ) + { ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; - else - ret = mbedtls_ctr_drbg_update_ret( ctx, buf, n ); - + goto exit; + } fclose( f ); + f = NULL; + ret = mbedtls_ctr_drbg_update_ret( ctx, buf, n ); + +exit: mbedtls_platform_zeroize( buf, sizeof( buf ) ); - + if( f != NULL ) + fclose( f ); if( ret != 0 ) return( ret ); - return( mbedtls_ctr_drbg_write_seed_file( ctx, path ) ); } #endif /* MBEDTLS_FS_IO */ diff --git a/library/hmac_drbg.c b/library/hmac_drbg.c index d5ac2f6ad..c50330e7d 100644 --- a/library/hmac_drbg.c +++ b/library/hmac_drbg.c @@ -417,35 +417,36 @@ exit: int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) { int ret = 0; - FILE *f; + FILE *f = NULL; size_t n; unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; + unsigned char c; if( ( f = fopen( path, "rb" ) ) == NULL ) return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); - fseek( f, 0, SEEK_END ); - n = (size_t) ftell( f ); - fseek( f, 0, SEEK_SET ); - - if( n > MBEDTLS_HMAC_DRBG_MAX_INPUT ) + n = fread( buf, 1, sizeof( buf ), f ); + if( fread( &c, 1, 1, f ) != 0 ) { - fclose( f ); - return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + ret = MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG; + goto exit; } - - if( fread( buf, 1, n, f ) != n ) + if( n == 0 || ferror( f ) ) + { ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; - else - ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n ); - + goto exit; + } fclose( f ); + f = NULL; + ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n ); + +exit: mbedtls_platform_zeroize( buf, sizeof( buf ) ); - + if( f != NULL ) + fclose( f ); if( ret != 0 ) return( ret ); - return( mbedtls_hmac_drbg_write_seed_file( ctx, path ) ); } #endif /* MBEDTLS_FS_IO */ From 5da0505842aca20e129d33b21b07d703aa1de51c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 11 Sep 2018 18:59:55 +0200 Subject: [PATCH 8/9] Add ChangeLog entry for deprecation of mbedtls_xxx_drbg_update Fixes ARMmbed/mbedtls#1798 --- ChangeLog | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ChangeLog b/ChangeLog index 3d0c7e8ba..a3e0aeb88 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,19 @@ Security * Wipe sensitive buffers on the stack in the CTR_DRBG and HMAC_DRBG modules. +API Changes + * The following functions in the random generator modules have been + deprecated and replaced as shown below. The new functions change + the return type from void to int to allow returning error codes when + using MBEDTLS__ALT for the underlying AES or message digest + primitive. Fixes #1798. + mbedtls_ctr_drbg_update() -> mbedtls_ctr_drbg_update_ret() + mbedtls_hmac_drbg_update() -> mbedtls_hmac_drbg_update_ret() + +New deprecations + * Deprecate mbedtls_ctr_drbg_update and mbedtls_hmac_drbg_update + in favor of functions that can return an error code. + = mbed TLS 2.14.0 branch released 2018-11-19 Security From c4a8017e3ed289f2600948489f0a60b2648e35cd Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 12 Sep 2018 19:15:53 +0200 Subject: [PATCH 9/9] mbedtls_ctr_drbg_update_ret: correct doc for input length limit Unlike mbedtls_ctr_drbg_update, this function returns an error if the length limit is exceeded, rather than silently truncating the input. --- include/mbedtls/ctr_drbg.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/include/mbedtls/ctr_drbg.h b/include/mbedtls/ctr_drbg.h index 9a3aba0d3..10f9389d9 100644 --- a/include/mbedtls/ctr_drbg.h +++ b/include/mbedtls/ctr_drbg.h @@ -239,16 +239,15 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, /** * \brief This function updates the state of the CTR_DRBG context. * - * \note If \p add_len is greater than - * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, only the first - * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT Bytes are used. - * The remaining Bytes are silently discarded. - * * \param ctx The CTR_DRBG context. * \param additional The data to update the state with. - * \param add_len Length of \p additional data. + * \param add_len Length of \p additional in bytes. This must be at + * most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. * * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG if + * \p add_len is more than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. * \return An error from the underlying AES cipher on failure. */ int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx,