From f2e16336d56697db29eb7c7dda338f73629977b6 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 26 Jun 2017 13:26:58 +0100 Subject: [PATCH 01/46] Prevent clever optimization to prematurely quit loop in safe memcmp The previous version of `mbedtls_ssl_safer_memcmp` did not qualify the pointers to the arrays to be compared as volatile, theoretically opening the possibility for the compiler to notice that the loop operation `diff |= A[i] ^ B[i]` is pointless if `diff = -1`. This commit changes this. It also declares the stack variable `diff` as volatile, to force read and write in every loop; omitting that, the compiler would still be allowed to get away with reading `A[i]` and `B[i]` but not doing the XOR and not updating `diff`. --- include/mbedtls/ssl_internal.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index 0c93a748e..9eb4a5fa4 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -584,9 +584,9 @@ void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl ); static inline int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ) { size_t i; - const unsigned char *A = (const unsigned char *) a; - const unsigned char *B = (const unsigned char *) b; - unsigned char diff = 0; + volatile const unsigned char *A = (volatile const unsigned char *) a; + volatile const unsigned char *B = (volatile const unsigned char *) b; + volatile unsigned char diff = 0; for( i = 0; i < n; i++ ) diff |= A[i] ^ B[i]; From c26741f8ca4d4d2aa43cad6504ec6935b8774b39 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 26 Jun 2017 13:52:14 +0100 Subject: [PATCH 02/46] Prevent bounds check bypass through overflow in PSK identity parsing The check `if( *p + n > end )` in `ssl_parse_client_psk_identity` is unsafe because `*p + n` might overflow, thus bypassing the check. As `n` is a user-specified value up to 65K, this is relevant if the library happens to be located in the last 65K of virtual memory. This commit replaces the check by a safe version. --- library/ssl_srv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 01b4ada30..27ed25836 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3252,7 +3252,7 @@ static int ssl_parse_client_psk_identity( mbedtls_ssl_context *ssl, unsigned cha /* * Receive client pre-shared key identity name */ - if( *p + 2 > end ) + if( end - *p < 2 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); @@ -3261,7 +3261,7 @@ static int ssl_parse_client_psk_identity( mbedtls_ssl_context *ssl, unsigned cha n = ( (*p)[0] << 8 ) | (*p)[1]; *p += 2; - if( n < 1 || n > 65535 || *p + n > end ) + if( n < 1 || n > 65535 || n > (size_t) ( end - *p ) ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); From ea0fad432766d1e923964d269f528cd8fb760e02 Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Fri, 23 Jun 2017 16:23:21 +0100 Subject: [PATCH 03/46] Zeroize tmp buf on fail in load_file() dhm.c --- library/dhm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/dhm.c b/library/dhm.c index 0f4d31643..d895eec40 100644 --- a/library/dhm.c +++ b/library/dhm.c @@ -539,7 +539,10 @@ static int load_file( const char *path, unsigned char **buf, size_t *n ) if( fread( *buf, 1, *n, f ) != *n ) { fclose( f ); + + mbedtls_zeroize( *buf, *n + 1 ); mbedtls_free( *buf ); + return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); } From 2390c2ad9e6e40a40058a782c10fc1d7a80ac03d Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Fri, 23 Jun 2017 16:30:31 +0100 Subject: [PATCH 04/46] Zeroize tmp buf in mbedtls_md_file() md.c --- library/md.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/md.c b/library/md.c index eda98f636..75b971795 100644 --- a/library/md.c +++ b/library/md.c @@ -312,12 +312,11 @@ int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, unsigne md_info->update_func( ctx.md_ctx, buf, n ); if( ferror( f ) != 0 ) - { ret = MBEDTLS_ERR_MD_FILE_IO_ERROR; - goto cleanup; - } + else + md_info->finish_func( ctx.md_ctx, output ); - md_info->finish_func( ctx.md_ctx, output ); + mbedtls_zeroize( buf, sizeof( buf ) ); cleanup: fclose( f ); From 81284add2e0d1b154dd8895400a19e0d16dbee55 Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Mon, 26 Jun 2017 09:58:59 +0100 Subject: [PATCH 05/46] Zeroize tmp bufs in entropy.c functions --- library/entropy.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/library/entropy.c b/library/entropy.c index cdbd35c34..f68d68656 100644 --- a/library/entropy.c +++ b/library/entropy.c @@ -222,7 +222,7 @@ static int entropy_gather_internal( mbedtls_entropy_context *ctx ) if( ( ret = ctx->source[i].f_source( ctx->source[i].p_source, buf, MBEDTLS_ENTROPY_MAX_GATHER, &olen ) ) != 0 ) { - return( ret ); + goto cleanup; } /* @@ -236,9 +236,12 @@ static int entropy_gather_internal( mbedtls_entropy_context *ctx ) } if( have_one_strong == 0 ) - return( MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE ); + ret = MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE; - return( 0 ); +cleanup: + mbedtls_zeroize( buf, sizeof( buf ) ); + + return( ret ); } /* @@ -338,6 +341,8 @@ int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ) ret = 0; exit: + mbedtls_zeroize( buf, sizeof( buf ) ); + #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); @@ -368,12 +373,15 @@ int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *p ret = 0; exit: + mbedtls_zeroize( buf, sizeof( buf ) ); + fclose( f ); return( ret ); } int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *path ) { + int ret = 0; FILE *f; size_t n; unsigned char buf[ MBEDTLS_ENTROPY_MAX_SEED_SIZE ]; @@ -389,14 +397,16 @@ int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char * n = MBEDTLS_ENTROPY_MAX_SEED_SIZE; if( fread( buf, 1, n, f ) != n ) - { - fclose( f ); - return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); - } + ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + else + ret = mbedtls_entropy_update_manual( ctx, buf, n ); fclose( f ); - mbedtls_entropy_update_manual( ctx, buf, n ); + mbedtls_zeroize( buf, sizeof( buf ) ); + + if( ret != 0 ) + return( ret ); return( mbedtls_entropy_write_seed_file( ctx, path ) ); } From f11316119257683e10248e1b8546530b14bebbc6 Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Mon, 26 Jun 2017 10:22:24 +0100 Subject: [PATCH 06/46] Zeroize tmp bufs in hmac_drbg.c functions --- library/hmac_drbg.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/library/hmac_drbg.c b/library/hmac_drbg.c index bf5f9b5bd..24c609e9c 100644 --- a/library/hmac_drbg.c +++ b/library/hmac_drbg.c @@ -364,11 +364,14 @@ int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const cha exit: fclose( f ); + mbedtls_zeroize( buf, sizeof( buf ) ); + return( ret ); } int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) { + int ret = 0; FILE *f; size_t n; unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; @@ -387,14 +390,16 @@ int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const ch } if( fread( buf, 1, n, f ) != n ) - { - fclose( f ); - return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); - } + ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; + else + mbedtls_hmac_drbg_update( ctx, buf, n ); fclose( f ); - mbedtls_hmac_drbg_update( ctx, buf, n ); + mbedtls_zeroize( buf, sizeof( buf ) ); + + if( ret != 0 ) + return( ret ); return( mbedtls_hmac_drbg_write_seed_file( ctx, path ) ); } From e7c839bf025c6efa05c3ee86d9959c07a95104b4 Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Mon, 26 Jun 2017 10:36:20 +0100 Subject: [PATCH 07/46] Zeroize return buf on failure in pkparse.c --- library/pkparse.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/pkparse.c b/library/pkparse.c index f0a12f983..d427c525f 100644 --- a/library/pkparse.c +++ b/library/pkparse.c @@ -101,7 +101,10 @@ int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ) if( fread( *buf, 1, *n, f ) != *n ) { fclose( f ); + + mbedtls_zeroize( *buf, *n ); mbedtls_free( *buf ); + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); } From e0a727ec4e6b93c60880131430411a2777b9c081 Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Mon, 26 Jun 2017 10:56:58 +0100 Subject: [PATCH 08/46] Zeroize tmp bufs in ctr_drbg.c functions --- library/ctr_drbg.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c index 646196eb1..c7f06b9c2 100644 --- a/library/ctr_drbg.c +++ b/library/ctr_drbg.c @@ -430,12 +430,11 @@ int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char goto exit; if( fwrite( buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f ) != MBEDTLS_CTR_DRBG_MAX_INPUT ) - { ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; - goto exit; - } + else + ret = 0; - ret = 0; + mbedtls_zeroize( buf, sizeof( buf ) ); exit: fclose( f ); @@ -444,6 +443,7 @@ exit: int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ) { + int ret = 0; FILE *f; size_t n; unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ]; @@ -456,20 +456,18 @@ int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char fseek( f, 0, SEEK_SET ); if( n > MBEDTLS_CTR_DRBG_MAX_INPUT ) - { - fclose( f ); - return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); - } - - if( fread( buf, 1, n, f ) != n ) - { - fclose( f ); - return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); - } + ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; + else if( fread( buf, 1, n, f ) != n ) + ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + else + mbedtls_ctr_drbg_update( ctx, buf, n ); fclose( f ); - mbedtls_ctr_drbg_update( ctx, buf, n ); + mbedtls_zeroize( buf, sizeof( buf ) ); + + if( ret != 0 ) + return( ret ); return( mbedtls_ctr_drbg_write_seed_file( ctx, path ) ); } From 64f0e093163935b105a845a3abcb26fa16cd608b Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Mon, 26 Jun 2017 11:20:02 +0100 Subject: [PATCH 09/46] Zeroize tmp buf in mbedtls_mpi_fill_random() --- library/bignum.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/bignum.c b/library/bignum.c index 52edd3def..142aeaca2 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -1877,6 +1877,8 @@ int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) ); cleanup: + mbedtls_zeroize( buf, sizeof( buf ) ); + return( ret ); } From 1b7d6f8c039574f5e85552da5e8d24eb0023050a Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Mon, 26 Jun 2017 11:35:17 +0100 Subject: [PATCH 10/46] Zeroize old psk buf when changing value in ssl_tls --- library/ssl_tls.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index bd2c27057..09f6bfad7 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -5872,6 +5872,7 @@ int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf, if( conf->psk != NULL || conf->psk_identity != NULL ) { + mbedtls_zeroize( conf->psk, conf->psk_len ); mbedtls_free( conf->psk ); mbedtls_free( conf->psk_identity ); conf->psk = NULL; @@ -5907,7 +5908,10 @@ int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); if( ssl->handshake->psk != NULL ) + { + mbedtls_zeroize( ssl->handshake->psk, ssl->handshake->psk_len ); mbedtls_free( ssl->handshake->psk ); + } if( ( ssl->handshake->psk = mbedtls_calloc( 1, psk_len ) ) == NULL ) return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); From 4f02a7bd6a25540c5d948affff71829ef0a28578 Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Mon, 26 Jun 2017 11:44:54 +0100 Subject: [PATCH 11/46] Zeroize heap buf on failure in pem.c --- library/pem.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/pem.c b/library/pem.c index 8dd86a4ac..a09257cc7 100644 --- a/library/pem.c +++ b/library/pem.c @@ -341,6 +341,7 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) if( pwd == NULL ) { + mbedtls_zeroize( buf, len ); mbedtls_free( buf ); return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ); } @@ -369,10 +370,12 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const */ if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 ) { + mbedtls_zeroize( buf, len ); mbedtls_free( buf ); return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ); } #else + mbedtls_zeroize( buf, len ); mbedtls_free( buf ); return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE ); #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && From c17cc44ed937d09704cd47e2e8af683692aab92a Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Tue, 27 Jun 2017 16:57:26 +0100 Subject: [PATCH 12/46] Zeroize tmp buf in ctr_drbg_write_seed_file() --- library/ctr_drbg.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c index c7f06b9c2..e8fdd9b6c 100644 --- a/library/ctr_drbg.c +++ b/library/ctr_drbg.c @@ -434,9 +434,9 @@ int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char else ret = 0; +exit: mbedtls_zeroize( buf, sizeof( buf ) ); -exit: fclose( f ); return( ret ); } @@ -456,8 +456,12 @@ int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char fseek( f, 0, SEEK_SET ); if( n > MBEDTLS_CTR_DRBG_MAX_INPUT ) - ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; - else if( fread( buf, 1, n, f ) != n ) + { + fclose( f ); + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + } + + if( fread( buf, 1, n, f ) != n ) ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; else mbedtls_ctr_drbg_update( ctx, buf, n ); From 3d23146f626d9bd3bfd0fc048474321dd12c34ba Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Wed, 5 Jul 2017 14:25:21 +0100 Subject: [PATCH 13/46] Set len var to 0 when buf is freed in ssl_tls.c --- library/ssl_tls.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 09f6bfad7..6c4c3e10e 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -5870,13 +5870,19 @@ int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf, return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); } - if( conf->psk != NULL || conf->psk_identity != NULL ) + if( conf->psk != NULL ) { mbedtls_zeroize( conf->psk, conf->psk_len ); + mbedtls_free( conf->psk ); - mbedtls_free( conf->psk_identity ); conf->psk = NULL; + conf->psk_len = 0; + } + if( conf->psk_identity != NULL ) + { + mbedtls_free( conf->psk_identity ); conf->psk_identity = NULL; + conf->psk_identity_len = 0; } if( ( conf->psk = mbedtls_calloc( 1, psk_len ) ) == NULL || @@ -5911,6 +5917,7 @@ int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, { mbedtls_zeroize( ssl->handshake->psk, ssl->handshake->psk_len ); mbedtls_free( ssl->handshake->psk ); + ssl->handshake->psk_len = 0; } if( ( ssl->handshake->psk = mbedtls_calloc( 1, psk_len ) ) == NULL ) From 55a5235ea15b13023ea396b4dcaf91a64b9cec48 Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Wed, 5 Jul 2017 15:40:17 +0100 Subject: [PATCH 14/46] Add ChangeLog entry for buf zeroize --- ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index 47ede8db3..fc1a4fd6e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ mbed TLS ChangeLog (Sorted per branch, date) += mbed TLS 2.1.x released xxxx-xx-xx + +Security + * Ensure that buffers are cleared after use if they contain sensitive data. + Changes were introduced in multiple places in the library. Cannot be + triggered remotely. + = mbed TLS 2.1.8 released 2017-06-21 Security From bab1edc7219ff8f68c6612e144b9ee9afa1b81f1 Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Wed, 5 Jul 2017 15:45:47 +0100 Subject: [PATCH 15/46] Zeroize tmp buffer in entropy_update() --- library/entropy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/entropy.c b/library/entropy.c index f68d68656..0d9a8150b 100644 --- a/library/entropy.c +++ b/library/entropy.c @@ -175,6 +175,8 @@ static int entropy_update( mbedtls_entropy_context *ctx, unsigned char source_id mbedtls_sha256_update( &ctx->accumulator, p, use_len ); #endif + mbedtls_zeroize( tmp, sizeof( tmp ) ); + return( 0 ); } From 11d2db1701ed77484c1cef5dc8a612d8b32661af Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Thu, 6 Jul 2017 17:17:43 +0100 Subject: [PATCH 16/46] Improve ChangeLog entry --- ChangeLog | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index fc1a4fd6e..52408a5b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,8 +4,7 @@ mbed TLS ChangeLog (Sorted per branch, date) Security * Ensure that buffers are cleared after use if they contain sensitive data. - Changes were introduced in multiple places in the library. Cannot be - triggered remotely. + Changes were introduced in multiple places in the library. = mbed TLS 2.1.8 released 2017-06-21 From 246b1634ff6be81d956d7c7c60d7edb13e701f2d Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Fri, 7 Jul 2017 10:46:51 +0100 Subject: [PATCH 17/46] Zeroize buf if mbedtls_base64_decode() fails --- library/pem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/library/pem.c b/library/pem.c index a09257cc7..ea36df882 100644 --- a/library/pem.c +++ b/library/pem.c @@ -331,6 +331,7 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const if( ( ret = mbedtls_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 ) { + mbedtls_zeroize( buf, len ); mbedtls_free( buf ); return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); } From 4dc8af77a91ec3129c66bc686d470fd8cfca80f5 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Tue, 5 Sep 2017 15:34:35 +0300 Subject: [PATCH 18/46] Backport 2.1:Set PEM buffer to zero before freeing Set PEM buffer to zero before freeing it, to avoid private keys being leaked to memory after releasing it. --- ChangeLog | 6 ++++++ library/pem.c | 1 + 2 files changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index 1d06476d7..f32c7299a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ mbed TLS ChangeLog (Sorted per branch, date) += mbed TLS x.x.x branch released xxxx-xx-xx + +Security + * Set PEM buffer to zero before freeing it, to avoid decoded private keys + being leaked to memory after release. + = mbed TLS 2.1.9 branch released 2017-08-10 Security diff --git a/library/pem.c b/library/pem.c index 8dd86a4ac..4c2337393 100644 --- a/library/pem.c +++ b/library/pem.c @@ -387,6 +387,7 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const void mbedtls_pem_free( mbedtls_pem_context *ctx ) { + memset( ctx->buf, 0, ctx->buflen ); mbedtls_free( ctx->buf ); mbedtls_free( ctx->info ); From 82a4b8186d2073896df012a379daed17b1978c2f Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Tue, 5 Sep 2017 17:17:31 +0300 Subject: [PATCH 19/46] update after Andres comments Update after Andres coments: 1. zeroize the buffer in `mbedtls_pem_read_buffer()` before freeing it 2. use `mbedtls_zeroize()` instead of `memset()` --- library/pem.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/pem.c b/library/pem.c index 4c2337393..f7051ecd2 100644 --- a/library/pem.c +++ b/library/pem.c @@ -331,7 +331,9 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const if( ( ret = mbedtls_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 ) { + mbedtls_zeroize( buf, len ); mbedtls_free( buf ); + buf = NULL; return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); } @@ -341,7 +343,9 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) if( pwd == NULL ) { + mbedtls_zeroize( buf, len ); mbedtls_free( buf ); + buf = NULL; return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ); } @@ -369,7 +373,9 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const */ if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 ) { + mbedtls_zeroize( buf, len ); mbedtls_free( buf ); + buf = NULL; return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ); } #else @@ -387,7 +393,8 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const void mbedtls_pem_free( mbedtls_pem_context *ctx ) { - memset( ctx->buf, 0, ctx->buflen ); + if( ctx->buf ) + mbedtls_zeroize( ctx->buf, ctx->buflen ); mbedtls_free( ctx->buf ); mbedtls_free( ctx->info ); From 070c809c79ff685b8913625233061749d5356984 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Wed, 6 Sep 2017 17:09:41 +0300 Subject: [PATCH 20/46] Adress Hannos's comments Remove zeroizing buffer, as it was done already in PR #369 Check that buffer is not null by `!= NULL` statement --- library/pem.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/library/pem.c b/library/pem.c index f7051ecd2..2f20b1e44 100644 --- a/library/pem.c +++ b/library/pem.c @@ -331,9 +331,7 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const if( ( ret = mbedtls_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 ) { - mbedtls_zeroize( buf, len ); mbedtls_free( buf ); - buf = NULL; return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); } @@ -343,9 +341,7 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) if( pwd == NULL ) { - mbedtls_zeroize( buf, len ); mbedtls_free( buf ); - buf = NULL; return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ); } @@ -373,9 +369,7 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const */ if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 ) { - mbedtls_zeroize( buf, len ); mbedtls_free( buf ); - buf = NULL; return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ); } #else @@ -393,7 +387,7 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const void mbedtls_pem_free( mbedtls_pem_context *ctx ) { - if( ctx->buf ) + if( ctx->buf != NULL ) mbedtls_zeroize( ctx->buf, ctx->buflen ); mbedtls_free( ctx->buf ); mbedtls_free( ctx->info ); From 6cf9af3aabe9c1b94c5650eaa3f4507aebf5e297 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Wed, 20 Sep 2017 13:46:37 +0100 Subject: [PATCH 21/46] DHM: Add negative tests for parameter checking A bug in the dhm_check_range() function makes it pass even when the parameters are not in the range. This commit adds tests for signalling this problem as well as a couple of other negative tests. --- tests/suites/test_suite_dhm.data | 18 +++++++++++++++--- tests/suites/test_suite_dhm.function | 7 +++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/tests/suites/test_suite_dhm.data b/tests/suites/test_suite_dhm.data index f2cdeffa5..e351ebdd4 100644 --- a/tests/suites/test_suite_dhm.data +++ b/tests/suites/test_suite_dhm.data @@ -1,11 +1,23 @@ Diffie-Hellman full exchange #1 -dhm_do_dhm:10:"23":10:"5" +dhm_do_dhm:10:"23":10:"5":0 Diffie-Hellman full exchange #2 -dhm_do_dhm:10:"93450983094850938450983409623":10:"9345098304850938450983409622" +dhm_do_dhm:10:"93450983094850938450983409623":10:"9345098304850938450983409622":0 Diffie-Hellman full exchange #3 -dhm_do_dhm:10:"93450983094850938450983409623982317398171298719873918739182739712938719287391879381271":10:"9345098309485093845098340962223981329819812792137312973297123912791271" +dhm_do_dhm:10:"93450983094850938450983409623982317398171298719873918739182739712938719287391879381271":10:"9345098309485093845098340962223981329819812792137312973297123912791271":0 + +Diffie-Hellman trivial subgroup #1 +dhm_do_dhm:10:"23":10:"1":MBEDTLS_ERR_DHM_BAD_INPUT_DATA + +Diffie-Hellman trivial subgroup #2 +dhm_do_dhm:10:"23":10:"-1":MBEDTLS_ERR_DHM_BAD_INPUT_DATA + +Diffie-Hellman small modulus +dhm_do_dhm:10:"3":10:"5":MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + +Diffie-Hellman zero modulus +dhm_do_dhm:10:"0":10:"5":MBEDTLS_ERR_DHM_BAD_INPUT_DATA Diffie-Hallman load parameters from file dhm_file:"data_files/dhparams.pem":"9e35f430443a09904f3a39a979797d070df53378e79c2438bef4e761f3c714553328589b041c809be1d6c6b5f1fc9f47d3a25443188253a992a56818b37ba9de5a40d362e56eff0be5417474c125c199272c8fe41dea733df6f662c92ae76556e755d10c64e6a50968f67fc6ea73d0dca8569be2ba204e23580d8bca2f4975b3":"02":128 diff --git a/tests/suites/test_suite_dhm.function b/tests/suites/test_suite_dhm.function index 002c20bf4..b41c79804 100644 --- a/tests/suites/test_suite_dhm.function +++ b/tests/suites/test_suite_dhm.function @@ -9,7 +9,7 @@ /* BEGIN_CASE */ void dhm_do_dhm( int radix_P, char *input_P, - int radix_G, char *input_G ) + int radix_G, char *input_G, int result ) { mbedtls_dhm_context ctx_srv; mbedtls_dhm_context ctx_cli; @@ -44,7 +44,10 @@ void dhm_do_dhm( int radix_P, char *input_P, /* * First key exchange */ - TEST_ASSERT( mbedtls_dhm_make_params( &ctx_srv, x_size, ske, &ske_len, &rnd_pseudo_rand, &rnd_info ) == 0 ); + TEST_ASSERT( mbedtls_dhm_make_params( &ctx_srv, x_size, ske, &ske_len, &rnd_pseudo_rand, &rnd_info ) == result ); + if ( result != 0 ) + goto exit; + ske[ske_len++] = 0; ske[ske_len++] = 0; TEST_ASSERT( mbedtls_dhm_read_params( &ctx_cli, &p, ske + ske_len ) == 0 ); From f341083b3c1f65383a9081ae1576308a72450472 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Wed, 20 Sep 2017 15:33:24 +0100 Subject: [PATCH 22/46] DHM: Fix dhm_check_range() always returning 0 Although the variable ret was initialised to an error, the MBEDTLS_MPI_CHK macro was overwriting it. Therefore it ended up being 0 whenewer the bignum computation was successfull and stayed 0 independently of the actual check. --- ChangeLog | 6 +++++- library/dhm.c | 11 +++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8f7843dc6..24bcde50f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,10 @@ mbed TLS ChangeLog (Sorted per branch, date) -= mbed TLS 2.1.x released xxxx-xx-xx += mbed TLS 2.1.x branch released xxxx-xx-xx + +Security + * Fix dhm_check_range() failing to detect trivial subgroups and potentially + leaking 1 bit of the private key. Reported by prashantkspatil. Bugfix * Fix ssl_parse_record_header() to silently discard invalid DTLS records diff --git a/library/dhm.c b/library/dhm.c index dc72c5361..0e0bdad21 100644 --- a/library/dhm.c +++ b/library/dhm.c @@ -90,6 +90,9 @@ static int dhm_read_bignum( mbedtls_mpi *X, * * Parameter should be: 2 <= public_param <= P - 2 * + * This means that we need to return an error if + * public_param < 2 or public_param > P-2 + * * For more information on the attack, see: * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643 @@ -97,17 +100,17 @@ static int dhm_read_bignum( mbedtls_mpi *X, static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P ) { mbedtls_mpi L, U; - int ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA; + int ret = 0; mbedtls_mpi_init( &L ); mbedtls_mpi_init( &U ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &L, 2 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) ); - if( mbedtls_mpi_cmp_mpi( param, &L ) >= 0 && - mbedtls_mpi_cmp_mpi( param, &U ) <= 0 ) + if( mbedtls_mpi_cmp_mpi( param, &L ) < 0 || + mbedtls_mpi_cmp_mpi( param, &U ) > 0 ) { - ret = 0; + ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA; } cleanup: From 6499bedfa838118149368ee30c9660b499c686bd Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 18 Sep 2017 10:54:39 +0100 Subject: [PATCH 23/46] Add compile-time checks for size of record content and payload --- include/mbedtls/ssl_internal.h | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index 0c93a748e..4d03c9213 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -24,6 +24,7 @@ #define MBEDTLS_SSL_INTERNAL_H #include "ssl.h" +#include "cipher.h" #if defined(MBEDTLS_MD5_C) #include "md5.h" @@ -134,13 +135,31 @@ #define MBEDTLS_SSL_PADDING_ADD 0 #endif -#define MBEDTLS_SSL_BUFFER_LEN ( MBEDTLS_SSL_MAX_CONTENT_LEN \ - + MBEDTLS_SSL_COMPRESSION_ADD \ - + 29 /* counter + header + IV */ \ - + MBEDTLS_SSL_MAC_ADD \ - + MBEDTLS_SSL_PADDING_ADD \ +#define MBEDTLS_SSL_PAYLOAD_LEN ( MBEDTLS_SSL_MAX_CONTENT_LEN \ + + MBEDTLS_SSL_COMPRESSION_ADD \ + + MBEDTLS_MAX_IV_LENGTH \ + + MBEDTLS_SSL_MAC_ADD \ + + MBEDTLS_SSL_PADDING_ADD \ ) +/* + * Check that we obey the standard's message size bounds + */ + +#if MBEDTLS_SSL_MAX_CONTENT_LEN > 16384 +#error Bad configuration - record content too large. +#endif + +#if MBEDTLS_SSL_PAYLOAD_LEN > 16384 + 2048 +#error Bad configuration - protected record payload too large. +#endif + +#define MBEDTLS_SSL_BUFFER_LEN ( MBEDTLS_SSL_PAYLOAD_LEN \ + + 5 /* TLS record header */ \ + + 8 /* Additional DTLS fields */ \ + ) + + /* * TLS extension flags (for extensions with outgoing ServerHello content * that need it (e.g. for RENEGOTIATION_INFO the server already knows because From aede1836301114c35ee2886119e31b72d99833ce Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 18 Sep 2017 10:55:31 +0100 Subject: [PATCH 24/46] Add run-time check for record content size in ssl_encrypt_buf --- library/ssl_tls.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index ba586a05e..6840ca0c6 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1259,6 +1259,13 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_BUF( 4, "before encrypt: output payload", ssl->out_msg, ssl->out_msglen ); + if( ssl->out_msglen > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record content too large, maximum %d", + MBEDTLS_SSL_MAX_CONTENT_LEN ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + /* * Add MAC before if needed */ From 0983dc49d6897a4244564fa2fc92d1d068ef4484 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 18 Sep 2017 10:55:54 +0100 Subject: [PATCH 25/46] Add run-time check for handshake message size in ssl_write_record --- library/ssl_tls.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 6840ca0c6..906d6ac4d 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -2731,6 +2731,15 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) { /* Make room for the additional DTLS fields */ + if( MBEDTLS_SSL_MAX_CONTENT_LEN - ssl->out_msglen < 8 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS handshake message too large: " + "size %u, maximum %u", + (unsigned) ( ssl->in_hslen - 4 ), + (unsigned) ( MBEDTLS_SSL_MAX_CONTENT_LEN - 12 ) ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + memmove( ssl->out_msg + 12, ssl->out_msg + 4, len - 4 ); ssl->out_msglen += 8; len += 8; From fbaeea4693486b35587ec9eafc9ffa09cdcfe309 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 18 Sep 2017 11:07:25 +0100 Subject: [PATCH 26/46] Adapt ChangeLog --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 8f7843dc6..ac8ba3f97 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,8 @@ mbed TLS ChangeLog (Sorted per branch, date) Bugfix * Fix ssl_parse_record_header() to silently discard invalid DTLS records as recommended in RFC 6347 Section 4.1.2.7. + * Add size-checks for record and handshake message content, securing + fragile yet non-exploitable code-paths. = mbed TLS 2.1.9 branch released 2017-08-10 From 6e052b0fbe4d822c4281ceeaca91452731ca25f8 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 4 Oct 2017 13:47:33 +0100 Subject: [PATCH 27/46] Improve debugging output --- library/ssl_tls.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 906d6ac4d..5c012a198 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1261,7 +1261,8 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) if( ssl->out_msglen > MBEDTLS_SSL_MAX_CONTENT_LEN ) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record content too large, maximum %d", + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record content %u too large, maximum %d", + (unsigned) ssl->out_msglen, MBEDTLS_SSL_MAX_CONTENT_LEN ) ); return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); } From 0ca15967d16305456499c5f203b7c200ae3351ef Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 4 Oct 2017 13:56:42 +0100 Subject: [PATCH 28/46] Don't allocate space for DTLS header if DTLS is disabled --- include/mbedtls/ssl_internal.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index 4d03c9213..2d99d4018 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -154,11 +154,17 @@ #error Bad configuration - protected record payload too large. #endif -#define MBEDTLS_SSL_BUFFER_LEN ( MBEDTLS_SSL_PAYLOAD_LEN \ - + 5 /* TLS record header */ \ - + 8 /* Additional DTLS fields */ \ - ) +#if !defined(MBEDTLS_SSL_PROTO_DTLS) +/* https://tools.ietf.org/html/rfc5246#section-6.2 */ +#define MBEDTLS_SSL_HEADER_LEN 5 +#else +/* https://tools.ietf.org/html/rfc6347#section-4.1 */ +/* 8 additional bytes for epoch and sequence number */ +#define MBEDTLS_SSL_HEADER_LEN 13 +#endif +#define MBEDTLS_SSL_BUFFER_LEN \ + ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_PAYLOAD_LEN ) ) /* * TLS extension flags (for extensions with outgoing ServerHello content From 5c3247120fea5c83f494fde79657a19e07eac46d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 17 Oct 2017 19:01:38 +0200 Subject: [PATCH 29/46] RSA: Fix buffer overflow in PSS signature verification Fix buffer overflow in RSA-PSS signature verification when the hash is too large for the key size. Found by Seth Terashima, Qualcomm. Added a non-regression test and a positive test with the smallest permitted key size for a SHA-512 hash. --- ChangeLog | 5 ++++ library/rsa.c | 2 ++ tests/data_files/rsa512.key | 9 ++++++++ tests/data_files/rsa521.key | 9 ++++++++ tests/data_files/rsa522.key | 9 ++++++++ tests/data_files/rsa528.key | 9 ++++++++ tests/suites/test_suite_pkcs1_v21.data | 32 ++++++++++++++++++++++++++ 7 files changed, 75 insertions(+) create mode 100644 tests/data_files/rsa512.key create mode 100644 tests/data_files/rsa521.key create mode 100644 tests/data_files/rsa522.key create mode 100644 tests/data_files/rsa528.key diff --git a/ChangeLog b/ChangeLog index 8f7843dc6..24835cd53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,11 @@ mbed TLS ChangeLog (Sorted per branch, date) = mbed TLS 2.1.x released xxxx-xx-xx +Security + * Fix buffer overflow in RSA-PSS verification when the hash is too + large for the key size. Found by Seth Terashima, Qualcomm Product + Security Initiative, Qualcomm Technologies Inc. + Bugfix * Fix ssl_parse_record_header() to silently discard invalid DTLS records as recommended in RFC 6347 Section 4.1.2.7. diff --git a/library/rsa.c b/library/rsa.c index 40ea642dc..db078d91c 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1369,6 +1369,8 @@ int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); hlen = mbedtls_md_get_size( md_info ); + if( siglen < hlen + 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); slen = siglen - hlen - 1; /* Currently length of salt + padding */ memset( zeros, 0, 8 ); diff --git a/tests/data_files/rsa512.key b/tests/data_files/rsa512.key new file mode 100644 index 000000000..1fd7987c2 --- /dev/null +++ b/tests/data_files/rsa512.key @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBOwIBAAJBALB20jJQgW+aqwIwfkUrl/DK51mDabQWJOivx5caWaE4kvZLB+qm +7JKMFgstbsj50N1bY8izrAdntPZciS9WwQ8CAwEAAQJAKYfNcIoB7II6PQmsrhrU +Z5dZW3fSKNANX7X/A1DwR0DlF8uZnpWsWbYcRoXX7QjvepZqc54wryhW55Wlm6yI +AQIhAOJIaLjSpbHjzzcJQ7mylxn2WGIlbJPPzJ9OaFZCZQvxAiEAx6OEAvl6JKa6 +6a+N2Wvhtcgb4qqR6UHQGJQYGJz5nP8CIAvgoR6ScAAWZRoOcm+c4DGMrLb6H+ji +T2tNQkzEz2kBAiEAmw34GStU36STpa6RGJ4+tyZN6jWakDVqf7x+HpfFE1cCIQDc +KzXIxec2taye4OeIa1v4W/MigMmYE9w93Uw/Qi3azA== +-----END RSA PRIVATE KEY----- diff --git a/tests/data_files/rsa521.key b/tests/data_files/rsa521.key new file mode 100644 index 000000000..0b940aa6e --- /dev/null +++ b/tests/data_files/rsa521.key @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBPQIBAAJCATG2mGDzy5v4XqNY/fK9KZDxt3qA1qT9+BekPdiWvffdJq+KwCN/ +Um4NM7EFyXH9vU/6ns6Z/EafMez0Kej1YsHDAgMBAAECQCdoYjwdMSHp4kksL5Aa +0kDc58ni0chy9IgXo+FHjTVmR9DkaZANrwfVvYMJxqYCZo0im1Dw7ZJBUDJQNXnl +ZokCIRiSk66I24AWa7XGUFvatVwXWi2ACE4QEKqzWQe1mQ24/wIhDHD1TCKpqucA +XDI+1N7EHs+fN4CfTSWe8FPGiK6q3VM9AiESrKKLi/q011U4KeS8SfR2blDcL2cg +XFkuQWqxzzLoGOUCIQmgl5E0+Ypwe0zc7NYZFDarf4+ZjqxKQnXCvk0irMHcGQIh +EVPli6RQb3Gcx7vXJHltzSTno7NElzBDRMBVUlBmVxAJ +-----END RSA PRIVATE KEY----- diff --git a/tests/data_files/rsa522.key b/tests/data_files/rsa522.key new file mode 100644 index 000000000..18fbe70ca --- /dev/null +++ b/tests/data_files/rsa522.key @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBPgIBAAJCAtMCdT492ij0L02fkshkdCDqb7yXwQ+EmLlmqVPzV2mNZYEGDf4y +yKuY20vFzirN8MHm5ASnWhMoJVDBqjfTzci/AgMBAAECQU05ffxf7uVg74yC9tKg +qCa746NpMh3OM+HZrUxiOXv0sJMRXNEPD5HNLtgcNY6MI5NYbUvkOXktnFZpxWYP +TH7BAiEeFJGs5Z6gRd2v/IbYLMFDHgjqho04INGTOvnyI7lGVKUCIRgJM7moFuoM +UrKTmJK1uOzauWEykCKgc6BGH6TGZoEWkwIhBzQn2v82qO1ydOYGKRk2w2sa+Yd1 +pH5/kkHqf+m8QjKdAiEQ9eVW+4J30wxD0JyX4b1E/S5UpN5KYNhWX0US+6D3NBsC +IRxePzdQlutZWg0Cnku3QE1tOLBCFlP7QVVl5FbKcY5H5w== +-----END RSA PRIVATE KEY----- diff --git a/tests/data_files/rsa528.key b/tests/data_files/rsa528.key new file mode 100644 index 000000000..fd463b54d --- /dev/null +++ b/tests/data_files/rsa528.key @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBRQIBAAJDAOMcJG1GSFmEJh/RdMqz1DVzRGAuzXk8R9vlQlLTe7NQvGNDWbGV +FVQggORySktnIpG+V8dkj1Finq7yNOhH2ZzGXwIDAQABAkMAsWYyLglQSlwnS4NZ +L1z4zieTqW3lomWr2+BgxkHbxl2w0Rx4L+Ezp+YK6mhtIQWNkoytPvWJJMS7Jrkg +agMAHQJBAiIA+F1y5GO0Bv+igsNLXwwtbCqs8hAkavU9W8egt/oDbhzbAiIA6hds +PZp/s1X7n7dwfmebSs+3vLZFuQfifN8XZLw0CXHNAiEuEzgDQrPdMIN3er96zImI +rYoUBgabiQ9u/WPFfa4xOU0CIgDDYC089Tfjy72pPgcr2PkpZVhqro5esg/8PI5f +yxx7TXkCIgCYoE8Y5IxomtL1ub1AQzPe9UyyUGzQB1yWeiloJh6LjxA= +-----END RSA PRIVATE KEY----- diff --git a/tests/suites/test_suite_pkcs1_v21.data b/tests/suites/test_suite_pkcs1_v21.data index ac16beb8a..6d31494e5 100644 --- a/tests/suites/test_suite_pkcs1_v21.data +++ b/tests/suites/test_suite_pkcs1_v21.data @@ -787,3 +787,35 @@ RSASSA-PSS Signature verify options #13 (MGF1 alg != MSG hash alg, arg wrong) depends_on:MBEDTLS_SHA256_C pkcs1_rsassa_pss_verify_ext:1024:16:"00dd118a9f99bab068ca2aea3b6a6d5997ed4ec954e40deecea07da01eaae80ec2bb1340db8a128e891324a5c5f5fad8f590d7c8cacbc5fe931dafda1223735279461abaa0572b761631b3a8afe7389b088b63993a0a25ee45d21858bab9931aedd4589a631b37fcf714089f856549f359326dd1e0e86dde52ed66b4a90bda4095":16:"010001":MBEDTLS_MD_NONE:MBEDTLS_MD_SHA256:MBEDTLS_MD_SHA1:MBEDTLS_RSA_SALT_LEN_ANY:"c0719e9a8d5d838d861dc6f675c899d2b309a3a65bb9fe6b11e5afcbf9a2c0b1":"7fc506d26ca3b22922a1ce39faaedd273161b82d9443c56f1a034f131ae4a18cae1474271cb4b66a17d9707ca58b0bdbd3c406b7e65bbcc9bbbce94dc45de807b4989b23b3e4db74ca29298137837eb90cc83d3219249bc7d480fceaf075203a86e54c4ecfa4e312e39f8f69d76534089a36ed9049ca9cfd5ab1db1fa75fe5c8":0:MBEDTLS_ERR_RSA_INVALID_PADDING +RSASSA-PSS verify ext, 512-bit key, empty salt, good signature +depends_on:MBEDTLS_SHA256_C +pkcs1_rsassa_pss_verify_ext:512:16:"00b076d23250816f9aab02307e452b97f0cae7598369b41624e8afc7971a59a13892f64b07eaa6ec928c160b2d6ec8f9d0dd5b63c8b3ac0767b4f65c892f56c10f":16:"010001":MBEDTLS_MD_SHA256:MBEDTLS_MD_SHA256:MBEDTLS_MD_SHA256:0:"":"ace8b03347da1b9a7a5e94a0d76359bb39c819bb170bef38ea84995ed653446c0ae87ede434cdf9d0cb2d7bf164cf427892363e6855a1d24d0ce5dd72acaf246":0:0 + +RSASSA-PSS verify ext, 512-bit key, empty salt, bad signature +depends_on:MBEDTLS_SHA256_C +pkcs1_rsassa_pss_verify_ext:512:16:"00b076d23250816f9aab02307e452b97f0cae7598369b41624e8afc7971a59a13892f64b07eaa6ec928c160b2d6ec8f9d0dd5b63c8b3ac0767b4f65c892f56c10f":16:"010001":MBEDTLS_MD_SHA256:MBEDTLS_MD_SHA256:MBEDTLS_MD_SHA256:0:"":"ace8b03347da1b9a7a5e94a0d76359bb39c819bb170bef38ea84995ed653446c0ae87ede434cdf9d0cb2d7bf164cf427892363e6855a1d24d0ce5dd72acaf247":MBEDTLS_ERR_RSA_INVALID_PADDING:MBEDTLS_ERR_RSA_INVALID_PADDING + +RSASSA-PSS verify ext, 522-bit key, SHA-512, empty salt, good signature +depends_on:MBEDTLS_SHA512_C +pkcs1_rsassa_pss_verify_ext:522:16:"02d302753e3dda28f42f4d9f92c8647420ea6fbc97c10f8498b966a953f357698d6581060dfe32c8ab98db4bc5ce2acdf0c1e6e404a75a13282550c1aa37d3cdc8bf":16:"010001":MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:0:"":"016752ae0b5dfbade6bbd3dd37868d48c8d741f92dca41c360aeda553204c2212a117b1a3d77e0d3f48723503c46e16c8a64de00f1dee3e37e478417452630859486":0:0 + +RSASSA-PSS verify ext, 528-bit key, SHA-512, saltlen=64, good signature with saltlen=0 +depends_on:MBEDTLS_SHA512_C +pkcs1_rsassa_pss_verify_ext:528:16:"00e31c246d46485984261fd174cab3d4357344602ecd793c47dbe54252d37bb350bc634359b19515542080e4724a4b672291be57c7648f51629eaef234e847d99cc65f":16:"010001":MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:64:"":"a9ad7994ba3a1071124153486924448cc67a5af3a5d34e9261d53770782cc85f58e2edde5f7004652a645e3e9606530eb57de41df7298ae2be9dec69cc0d613ab629":0:MBEDTLS_ERR_RSA_INVALID_PADDING + +RSASSA-PSS verify ext, 528-bit key, SHA-512, empty salt, good signature +depends_on:MBEDTLS_SHA512_C +pkcs1_rsassa_pss_verify_ext:528:16:"00e31c246d46485984261fd174cab3d4357344602ecd793c47dbe54252d37bb350bc634359b19515542080e4724a4b672291be57c7648f51629eaef234e847d99cc65f":16:"010001":MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:0:"":"a9ad7994ba3a1071124153486924448cc67a5af3a5d34e9261d53770782cc85f58e2edde5f7004652a645e3e9606530eb57de41df7298ae2be9dec69cc0d613ab629":0:0 + +RSASSA-PSS verify ext, 528-bit key, SHA-512, saltlen=64, good signature with saltlen=0 +depends_on:MBEDTLS_SHA512_C +pkcs1_rsassa_pss_verify_ext:528:16:"00e31c246d46485984261fd174cab3d4357344602ecd793c47dbe54252d37bb350bc634359b19515542080e4724a4b672291be57c7648f51629eaef234e847d99cc65f":16:"010001":MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:64:"":"a9ad7994ba3a1071124153486924448cc67a5af3a5d34e9261d53770782cc85f58e2edde5f7004652a645e3e9606530eb57de41df7298ae2be9dec69cc0d613ab629":0:MBEDTLS_ERR_RSA_INVALID_PADDING + +RSASSA-PSS verify ext, 512-bit key, SHA-512 (hash too large) +depends_on:MBEDTLS_SHA512_C +pkcs1_rsassa_pss_verify_ext:512:16:"00b076d23250816f9aab02307e452b97f0cae7598369b41624e8afc7971a59a13892f64b07eaa6ec928c160b2d6ec8f9d0dd5b63c8b3ac0767b4f65c892f56c10f":16:"010001":MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:0:"":"ace8b03347da1b9a7a5e94a0d76359bb39c819bb170bef38ea84995ed653446c0ae87ede434cdf9d0cb2d7bf164cf427892363e6855a1d24d0ce5dd72acaf246":MBEDTLS_ERR_RSA_BAD_INPUT_DATA:MBEDTLS_ERR_RSA_BAD_INPUT_DATA + +RSASSA-PSS verify ext, 521-bit key, SHA-512, empty salt, bad signature +depends_on:MBEDTLS_SHA512_C +pkcs1_rsassa_pss_verify_ext:521:16:"0131b69860f3cb9bf85ea358fdf2bd2990f1b77a80d6a4fdf817a43dd896bdf7dd26af8ac0237f526e0d33b105c971fdbd4ffa9ece99fc469f31ecf429e8f562c1c3":16:"010001":MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:0:"":"00471794655837da498cbf27242807b40593a353c707eb22fd2cc5a3259e728ac4f1df676043eeec8e16c1175b3d9ac8cae72ec1d5772dd69de71c5677f19031568e":MBEDTLS_ERR_RSA_INVALID_PADDING:MBEDTLS_ERR_RSA_INVALID_PADDING + From d0cd855145bd6f582947114b47f12502ba3ef4d8 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 17 Oct 2017 19:02:13 +0200 Subject: [PATCH 30/46] RSA: Fix another buffer overflow in PSS signature verification Fix buffer overflow in RSA-PSS signature verification when the masking operation results in an all-zero buffer. This could happen at any key size. --- ChangeLog | 2 ++ library/rsa.c | 21 +++++++++++---------- tests/suites/test_suite_pkcs1_v21.data | 4 ++++ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 24835cd53..51c002cad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,8 @@ Security * Fix buffer overflow in RSA-PSS verification when the hash is too large for the key size. Found by Seth Terashima, Qualcomm Product Security Initiative, Qualcomm Technologies Inc. + * Fix buffer overflow in RSA-PSS verification when the unmasked + data is all zeros. Bugfix * Fix ssl_parse_record_header() to silently discard invalid DTLS records diff --git a/library/rsa.c b/library/rsa.c index db078d91c..9e05b4b16 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1326,10 +1326,11 @@ int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, size_t siglen; unsigned char *p; unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + unsigned char *hash_start; unsigned char result[MBEDTLS_MD_MAX_SIZE]; unsigned char zeros[8]; unsigned int hlen; - size_t slen, msb; + size_t observed_salt_len, msb; const mbedtls_md_info_t *md_info; mbedtls_md_context_t md_ctx; @@ -1371,7 +1372,7 @@ int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, hlen = mbedtls_md_get_size( md_info ); if( siglen < hlen + 2 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); - slen = siglen - hlen - 1; /* Currently length of salt + padding */ + hash_start = buf + siglen - hlen - 1; memset( zeros, 0, 8 ); @@ -1386,6 +1387,7 @@ int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, p++; siglen -= 1; } + else if( buf[0] >> ( 8 - siglen * 8 + msb ) ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); @@ -1396,25 +1398,24 @@ int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, return( ret ); } - mgf_mask( p, siglen - hlen - 1, p + siglen - hlen - 1, hlen, &md_ctx ); + mgf_mask( p, siglen - hlen - 1, hash_start, hlen, &md_ctx ); buf[0] &= 0xFF >> ( siglen * 8 - msb ); - while( p < buf + siglen && *p == 0 ) + while( p < hash_start - 1 && *p == 0 ) p++; - if( p == buf + siglen || + if( p == hash_start || *p++ != 0x01 ) { mbedtls_md_free( &md_ctx ); return( MBEDTLS_ERR_RSA_INVALID_PADDING ); } - /* Actual salt len */ - slen -= p - buf; + observed_salt_len = hash_start - p; if( expected_salt_len != MBEDTLS_RSA_SALT_LEN_ANY && - slen != (size_t) expected_salt_len ) + observed_salt_len != (size_t) expected_salt_len ) { mbedtls_md_free( &md_ctx ); return( MBEDTLS_ERR_RSA_INVALID_PADDING ); @@ -1425,12 +1426,12 @@ int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, mbedtls_md_starts( &md_ctx ); mbedtls_md_update( &md_ctx, zeros, 8 ); mbedtls_md_update( &md_ctx, hash, hashlen ); - mbedtls_md_update( &md_ctx, p, slen ); + mbedtls_md_update( &md_ctx, p, observed_salt_len ); mbedtls_md_finish( &md_ctx, result ); mbedtls_md_free( &md_ctx ); - if( memcmp( p + slen, result, hlen ) == 0 ) + if( memcmp( hash_start, result, hlen ) == 0 ) return( 0 ); else return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); diff --git a/tests/suites/test_suite_pkcs1_v21.data b/tests/suites/test_suite_pkcs1_v21.data index 6d31494e5..7c202e9cd 100644 --- a/tests/suites/test_suite_pkcs1_v21.data +++ b/tests/suites/test_suite_pkcs1_v21.data @@ -819,3 +819,7 @@ RSASSA-PSS verify ext, 521-bit key, SHA-512, empty salt, bad signature depends_on:MBEDTLS_SHA512_C pkcs1_rsassa_pss_verify_ext:521:16:"0131b69860f3cb9bf85ea358fdf2bd2990f1b77a80d6a4fdf817a43dd896bdf7dd26af8ac0237f526e0d33b105c971fdbd4ffa9ece99fc469f31ecf429e8f562c1c3":16:"010001":MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:0:"":"00471794655837da498cbf27242807b40593a353c707eb22fd2cc5a3259e728ac4f1df676043eeec8e16c1175b3d9ac8cae72ec1d5772dd69de71c5677f19031568e":MBEDTLS_ERR_RSA_INVALID_PADDING:MBEDTLS_ERR_RSA_INVALID_PADDING +RSASSA-PSS verify ext, all-zero padding, automatic salt length +depends_on:MBEDTLS_SHA256_C +pkcs1_rsassa_pss_verify_ext:512:16:"00b076d23250816f9aab02307e452b97f0cae7598369b41624e8afc7971a59a13892f64b07eaa6ec928c160b2d6ec8f9d0dd5b63c8b3ac0767b4f65c892f56c10f":16:"010001":MBEDTLS_MD_NONE:MBEDTLS_MD_SHA256:MBEDTLS_MD_SHA256:MBEDTLS_RSA_SALT_LEN_ANY:"":"63a35294577c7e593170378175b7df27c293dae583ec2a971426eb2d66f2af483e897bfae5dc20300a9d61a3644e08c3aee61a463690a3498901563c46041056":MBEDTLS_ERR_RSA_INVALID_PADDING:MBEDTLS_ERR_RSA_INVALID_PADDING + From 9e2058281daa77d88cdf17d63cf30dbeaf39905b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 18 Oct 2017 19:03:42 +0200 Subject: [PATCH 31/46] RSA PSS: fix minimum length check for keys of size 8N+1 The check introduced by the previous security fix was off by one. It fixed the buffer overflow but was not compliant with the definition of PSS which technically led to accepting some invalid signatures (but not signatures made without the private key). --- library/rsa.c | 7 ++++--- tests/suites/test_suite_pkcs1_v21.data | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index 9e05b4b16..8933aa15e 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1370,9 +1370,6 @@ int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); hlen = mbedtls_md_get_size( md_info ); - if( siglen < hlen + 2 ) - return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); - hash_start = buf + siglen - hlen - 1; memset( zeros, 0, 8 ); @@ -1391,6 +1388,10 @@ int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, if( buf[0] >> ( 8 - siglen * 8 + msb ) ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + if( siglen < hlen + 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + hash_start = p + siglen - hlen - 1; + mbedtls_md_init( &md_ctx ); if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) { diff --git a/tests/suites/test_suite_pkcs1_v21.data b/tests/suites/test_suite_pkcs1_v21.data index 7c202e9cd..7785b1232 100644 --- a/tests/suites/test_suite_pkcs1_v21.data +++ b/tests/suites/test_suite_pkcs1_v21.data @@ -817,7 +817,7 @@ pkcs1_rsassa_pss_verify_ext:512:16:"00b076d23250816f9aab02307e452b97f0cae7598369 RSASSA-PSS verify ext, 521-bit key, SHA-512, empty salt, bad signature depends_on:MBEDTLS_SHA512_C -pkcs1_rsassa_pss_verify_ext:521:16:"0131b69860f3cb9bf85ea358fdf2bd2990f1b77a80d6a4fdf817a43dd896bdf7dd26af8ac0237f526e0d33b105c971fdbd4ffa9ece99fc469f31ecf429e8f562c1c3":16:"010001":MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:0:"":"00471794655837da498cbf27242807b40593a353c707eb22fd2cc5a3259e728ac4f1df676043eeec8e16c1175b3d9ac8cae72ec1d5772dd69de71c5677f19031568e":MBEDTLS_ERR_RSA_INVALID_PADDING:MBEDTLS_ERR_RSA_INVALID_PADDING +pkcs1_rsassa_pss_verify_ext:521:16:"0131b69860f3cb9bf85ea358fdf2bd2990f1b77a80d6a4fdf817a43dd896bdf7dd26af8ac0237f526e0d33b105c971fdbd4ffa9ece99fc469f31ecf429e8f562c1c3":16:"010001":MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:0:"":"00471794655837da498cbf27242807b40593a353c707eb22fd2cc5a3259e728ac4f1df676043eeec8e16c1175b3d9ac8cae72ec1d5772dd69de71c5677f19031568e":MBEDTLS_ERR_RSA_BAD_INPUT_DATA:MBEDTLS_ERR_RSA_BAD_INPUT_DATA RSASSA-PSS verify ext, all-zero padding, automatic salt length depends_on:MBEDTLS_SHA256_C From 31a2d14b92be6bbf66f3103bbdb04fb3aa26d72f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 19 Oct 2017 15:23:49 +0200 Subject: [PATCH 32/46] RSA PSS: fix first byte check for keys of size 8N+1 For a key of size 8N+1, check that the first byte after applying the public key operation is 0 (it could have been 1 instead). The code was incorrectly doing a no-op check instead, which led to invalid signatures being accepted. Not a security flaw, since you would need the private key to craft such an invalid signature, but a bug nonetheless. --- library/rsa.c | 9 ++++----- tests/suites/test_suite_pkcs1_v21.data | 8 ++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index 8933aa15e..d923bc924 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1377,16 +1377,15 @@ int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, // msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; - // Compensate for boundary condition when applying mask - // + if( buf[0] >> ( 8 - siglen * 8 + msb ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* Compensate for boundary condition when applying mask */ if( msb % 8 == 0 ) { p++; siglen -= 1; } - else - if( buf[0] >> ( 8 - siglen * 8 + msb ) ) - return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); if( siglen < hlen + 2 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); diff --git a/tests/suites/test_suite_pkcs1_v21.data b/tests/suites/test_suite_pkcs1_v21.data index 7785b1232..6258c6262 100644 --- a/tests/suites/test_suite_pkcs1_v21.data +++ b/tests/suites/test_suite_pkcs1_v21.data @@ -819,6 +819,14 @@ RSASSA-PSS verify ext, 521-bit key, SHA-512, empty salt, bad signature depends_on:MBEDTLS_SHA512_C pkcs1_rsassa_pss_verify_ext:521:16:"0131b69860f3cb9bf85ea358fdf2bd2990f1b77a80d6a4fdf817a43dd896bdf7dd26af8ac0237f526e0d33b105c971fdbd4ffa9ece99fc469f31ecf429e8f562c1c3":16:"010001":MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:MBEDTLS_MD_SHA512:0:"":"00471794655837da498cbf27242807b40593a353c707eb22fd2cc5a3259e728ac4f1df676043eeec8e16c1175b3d9ac8cae72ec1d5772dd69de71c5677f19031568e":MBEDTLS_ERR_RSA_BAD_INPUT_DATA:MBEDTLS_ERR_RSA_BAD_INPUT_DATA +RSASSA-PSS verify ext, 521-bit key, SHA-256, empty salt, good signature +depends_on:MBEDTLS_SHA256_C +pkcs1_rsassa_pss_verify_ext:521:16:"0131b69860f3cb9bf85ea358fdf2bd2990f1b77a80d6a4fdf817a43dd896bdf7dd26af8ac0237f526e0d33b105c971fdbd4ffa9ece99fc469f31ecf429e8f562c1c3":16:"010001":MBEDTLS_MD_SHA256:MBEDTLS_MD_SHA256:MBEDTLS_MD_SHA256:0:"41":"009c4941157fa36288e467310b198ab0c615c40963d611ffeef03000549ded809235955ecc57adba44782e9497c004f480ba2b3d58db8335fe0b391075c02c843a6d":0:0 + +RSASSA-PSS verify ext, 521-bit key, SHA-256, empty salt, flipped-highest-bit signature +depends_on:MBEDTLS_SHA256_C +pkcs1_rsassa_pss_verify_ext:521:16:"0131b69860f3cb9bf85ea358fdf2bd2990f1b77a80d6a4fdf817a43dd896bdf7dd26af8ac0237f526e0d33b105c971fdbd4ffa9ece99fc469f31ecf429e8f562c1c3":16:"010001":MBEDTLS_MD_SHA256:MBEDTLS_MD_SHA256:MBEDTLS_MD_SHA256:0:"41":"00e11a2403df681c44a1f73f014b6c9ad17847d0b673f7c2a801cee208d10ab5792c10cd0cd495a4b331aaa521409fca7cb1b0d978b3a84cd67e28078b98753e9466":MBEDTLS_ERR_RSA_BAD_INPUT_DATA:MBEDTLS_ERR_RSA_BAD_INPUT_DATA + RSASSA-PSS verify ext, all-zero padding, automatic salt length depends_on:MBEDTLS_SHA256_C pkcs1_rsassa_pss_verify_ext:512:16:"00b076d23250816f9aab02307e452b97f0cae7598369b41624e8afc7971a59a13892f64b07eaa6ec928c160b2d6ec8f9d0dd5b63c8b3ac0767b4f65c892f56c10f":16:"010001":MBEDTLS_MD_NONE:MBEDTLS_MD_SHA256:MBEDTLS_MD_SHA256:MBEDTLS_RSA_SALT_LEN_ANY:"":"63a35294577c7e593170378175b7df27c293dae583ec2a971426eb2d66f2af483e897bfae5dc20300a9d61a3644e08c3aee61a463690a3498901563c46041056":MBEDTLS_ERR_RSA_INVALID_PADDING:MBEDTLS_ERR_RSA_INVALID_PADDING From 9745cfd87d53c8c1752ff688c55ca7ab00efe4ce Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 19 Oct 2017 17:46:14 +0200 Subject: [PATCH 33/46] RSA PSS: remove redundant check; changelog Remove a check introduced in the previous buffer overflow fix with keys of size 8N+1 which the subsequent fix for buffer start calculations made redundant. Added a changelog entry for the buffer start calculation fix. --- ChangeLog | 2 ++ library/rsa.c | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 51c002cad..487a59a06 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,8 @@ Security data is all zeros. Bugfix + * Fix some invalid RSA-PSS signatures with keys of size 8N+1 that were + accepted. Generating these signatures required the private key. * Fix ssl_parse_record_header() to silently discard invalid DTLS records as recommended in RFC 6347 Section 4.1.2.7. diff --git a/library/rsa.c b/library/rsa.c index d923bc924..d2bddf662 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1405,8 +1405,7 @@ int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, while( p < hash_start - 1 && *p == 0 ) p++; - if( p == hash_start || - *p++ != 0x01 ) + if( *p++ != 0x01 ) { mbedtls_md_free( &md_ctx ); return( MBEDTLS_ERR_RSA_INVALID_PADDING ); From cb2ba29c49be581a267e0a86c7a854ddad65067c Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 17 Oct 2017 15:17:05 +0100 Subject: [PATCH 34/46] Mention that mpi_fill_random interprets PRNG output as big-endian --- include/mbedtls/bignum.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/mbedtls/bignum.h b/include/mbedtls/bignum.h index 1a5b4b675..030982d86 100644 --- a/include/mbedtls/bignum.h +++ b/include/mbedtls/bignum.h @@ -648,6 +648,10 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi * * \return 0 if successful, * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * + * \note The bytes obtained from the PRNG are interpreted + * as a big-endian representation of an MPI; this can + * be relevant in applications like deterministic ECDSA. */ int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, int (*f_rng)(void *, unsigned char *, size_t), From 7d80688e5316663a4cfeaad59e7b29cf89d4634b Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 17 Oct 2017 15:17:27 +0100 Subject: [PATCH 35/46] Make mpi_read_binary time constant This commit modifies mpi_read_binary to always allocate the minimum number of limbs required to hold the entire buffer provided to the function, regardless of its content. Previously, leading zero bytes in the input data were detected and used to reduce memory footprint and time, but this non-constant behavior turned out to be non-tolerable for the cryptographic applications this function is used for. --- library/bignum.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 52edd3def..886429206 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -672,16 +672,20 @@ cleanup: int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen ) { int ret; - size_t i, j, n; + size_t i, j; + size_t const limbs = CHARS_TO_LIMBS( buflen ); - for( n = 0; n < buflen; n++ ) - if( buf[n] != 0 ) - break; + /* Ensure that target MPI has exactly the necessary number of limbs */ + if( X->n != limbs ) + { + mbedtls_mpi_free( X ); + mbedtls_mpi_init( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) ); + } - MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); - for( i = buflen, j = 0; i > n; i--, j++ ) + for( i = buflen, j = 0; i > 0; i--, j++ ) X->p[j / ciL] |= ((mbedtls_mpi_uint) buf[i - 1]) << ((j % ciL) << 3); cleanup: From b3088b4b378914a058853be2835476255639e4ad Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 17 Oct 2017 15:19:38 +0100 Subject: [PATCH 36/46] Fix information leak in ecp_gen_keypair_base The function mbedtls_ecp_gen_keypair_base did not wipe the stack buffer used to hold the private exponent before returning. This commit fixes this by not using a stack buffer in the first place but instead calling mpi_fill_random directly to acquire the necessary random MPI. --- library/ecp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/ecp.c b/library/ecp.c index 1d4f5cba2..5787b9b2c 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -1830,7 +1830,6 @@ int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp { /* SEC1 3.2.1: Generate d such that 1 <= n < N */ int count = 0; - unsigned char rnd[MBEDTLS_ECP_MAX_BYTES]; /* * Match the procedure given in RFC 6979 (deterministic ECDSA): @@ -1841,8 +1840,7 @@ int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp */ do { - MBEDTLS_MPI_CHK( f_rng( p_rng, rnd, n_size ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( d, rnd, n_size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( d, n_size, f_rng, p_rng ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( d, 8 * n_size - grp->nbits ) ); /* From 0f49bbc1fc63feafed4b295c1bb0880385faffed Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 18 Oct 2017 12:41:30 +0100 Subject: [PATCH 37/46] Zeroize stack before returning from mpi_fill_random --- library/bignum.c | 1 + 1 file changed, 1 insertion(+) diff --git a/library/bignum.c b/library/bignum.c index 886429206..25fe8beeb 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -1881,6 +1881,7 @@ int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) ); cleanup: + mbedtls_zeroize( buf, sizeof( buf ) ); return( ret ); } From cf873f74d40690e1c76ade0b6dadf228bc71d398 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 19 Oct 2017 09:13:35 +0100 Subject: [PATCH 38/46] Adapt ChangeLog --- ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index 8f7843dc6..55e8cf16a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,13 @@ mbed TLS ChangeLog (Sorted per branch, date) = mbed TLS 2.1.x released xxxx-xx-xx +Security + * Make mbedtls_mpi_read_binary constant-time with respect to + the input data. Previously, trailing zero bytes were detected + and omitted for the sake of saving memory, but potentially + leading to slight timing differences. + Reported by Marco Macchetti, Kudelski Group. + Bugfix * Fix ssl_parse_record_header() to silently discard invalid DTLS records as recommended in RFC 6347 Section 4.1.2.7. From 25e39d38bd295eef1c5cac5976afee2dcf265517 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 19 Oct 2017 10:10:18 +0100 Subject: [PATCH 39/46] Add ChangeLog message for EC private exponent information leak --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 55e8cf16a..4e919c98a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,8 @@ Security and omitted for the sake of saving memory, but potentially leading to slight timing differences. Reported by Marco Macchetti, Kudelski Group. + * Wipe stack buffer temporarily holding EC private exponent + after keypair generation. Bugfix * Fix ssl_parse_record_header() to silently discard invalid DTLS records From ce516ff449d9e2eeaaf917a85de78ee1ca0efa13 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 9 Nov 2017 18:57:39 +0000 Subject: [PATCH 40/46] Fix heap corruption in ssl_decrypt_buf Previously, MAC validation for an incoming record proceeded as follows: 1) Make a copy of the MAC contained in the record; 2) Compute the expected MAC in place, overwriting the presented one; 3) Compare both. This resulted in a record buffer overflow if truncated MAC was used, as in this case the record buffer only reserved 10 bytes for the MAC, but the MAC computation routine in 2) always wrote a full digest. For specially crafted records, this could be used to perform a controlled write of up to 6 bytes past the boundary of the heap buffer holding the record, thereby corrupting the heap structures and potentially leading to a crash or remote code execution. This commit fixes this by making the following change: 1) Compute the expected MAC in a temporary buffer that has the size of the underlying message digest. 2) Compare to this to the MAC contained in the record, potentially restricting to the first 10 bytes if truncated HMAC is used. A similar fix is applied to the encryption routine `ssl_encrypt_buf`. --- library/ssl_tls.c | 36 +++++++++++++++++------------------- tests/ssl-opt.sh | 20 ++++++++++---------- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 8088e881c..1b8d7df58 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1284,14 +1284,17 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) defined(MBEDTLS_SSL_PROTO_TLS1_2) if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) { + unsigned char mac[MBEDTLS_SSL_MAC_ADD]; + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_ctr, 8 ); mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_hdr, 3 ); mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_len, 2 ); mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_msg, ssl->out_msglen ); - mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc, - ssl->out_msg + ssl->out_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc, mac ); mbedtls_md_hmac_reset( &ssl->transform_out->md_ctx_enc ); + + memcpy( ssl->out_msg + ssl->out_msglen, mac, ssl->transform_out->maclen ); } else #endif @@ -1553,8 +1556,6 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) return( 0 ); } -#define SSL_MAX_MAC_SIZE 48 - static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) { size_t i; @@ -1722,7 +1723,7 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) if( ssl->session_in->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED ) { - unsigned char computed_mac[SSL_MAX_MAC_SIZE]; + unsigned char mac_expect[MBEDTLS_SSL_MAC_ADD]; unsigned char pseudo_hdr[13]; MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); @@ -1740,16 +1741,16 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, pseudo_hdr, 13 ); mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_iv, ssl->in_msglen ); - mbedtls_md_hmac_finish( &ssl->transform_in->md_ctx_dec, computed_mac ); + mbedtls_md_hmac_finish( &ssl->transform_in->md_ctx_dec, mac_expect ); mbedtls_md_hmac_reset( &ssl->transform_in->md_ctx_dec ); MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", ssl->in_iv + ssl->in_msglen, ssl->transform_in->maclen ); - MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", computed_mac, + MBEDTLS_SSL_DEBUG_BUF( 4, "expected mac", mac_expect, ssl->transform_in->maclen ); - if( mbedtls_ssl_safer_memcmp( ssl->in_iv + ssl->in_msglen, computed_mac, - ssl->transform_in->maclen ) != 0 ) + if( mbedtls_ssl_safer_memcmp( ssl->in_iv + ssl->in_msglen, mac_expect, + ssl->transform_in->maclen ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); @@ -1909,15 +1910,13 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) #if defined(SSL_SOME_MODES_USE_MAC) if( auth_done == 0 ) { - unsigned char tmp[SSL_MAX_MAC_SIZE]; + unsigned char mac_expect[MBEDTLS_SSL_MAC_ADD]; ssl->in_msglen -= ssl->transform_in->maclen; ssl->in_len[0] = (unsigned char)( ssl->in_msglen >> 8 ); ssl->in_len[1] = (unsigned char)( ssl->in_msglen ); - memcpy( tmp, ssl->in_msg + ssl->in_msglen, ssl->transform_in->maclen ); - #if defined(MBEDTLS_SSL_PROTO_SSL3) if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) { @@ -1956,8 +1955,7 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_len, 2 ); mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_msg, ssl->in_msglen ); - mbedtls_md_hmac_finish( &ssl->transform_in->md_ctx_dec, - ssl->in_msg + ssl->in_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_in->md_ctx_dec, mac_expect ); /* Call mbedtls_md_process at least once due to cache attacks */ for( j = 0; j < extra_run + 1; j++ ) mbedtls_md_process( &ssl->transform_in->md_ctx_dec, ssl->in_msg ); @@ -1972,12 +1970,12 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); } - MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", tmp, ssl->transform_in->maclen ); - MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", ssl->in_msg + ssl->in_msglen, - ssl->transform_in->maclen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "expected mac", mac_expect, ssl->transform_in->maclen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", ssl->in_msg + ssl->in_msglen, + ssl->transform_in->maclen ); - if( mbedtls_ssl_safer_memcmp( tmp, ssl->in_msg + ssl->in_msglen, - ssl->transform_in->maclen ) != 0 ) + if( mbedtls_ssl_safer_memcmp( ssl->in_msg + ssl->in_msglen, mac_expect, + ssl->transform_in->maclen ) != 0 ) { #if defined(MBEDTLS_SSL_DEBUG_ALL) MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index d8f0fd720..5a1ef5bfb 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -699,40 +699,40 @@ run_test "Truncated HMAC: client default, server default" \ "$P_SRV debug_level=4" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \ 0 \ - -s "dumping 'computed mac' (20 bytes)" \ - -S "dumping 'computed mac' (10 bytes)" + -s "dumping 'expected mac' (20 bytes)" \ + -S "dumping 'expected mac' (10 bytes)" run_test "Truncated HMAC: client disabled, server default" \ "$P_SRV debug_level=4" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ trunc_hmac=0" \ 0 \ - -s "dumping 'computed mac' (20 bytes)" \ - -S "dumping 'computed mac' (10 bytes)" + -s "dumping 'expected mac' (20 bytes)" \ + -S "dumping 'expected mac' (10 bytes)" run_test "Truncated HMAC: client enabled, server default" \ "$P_SRV debug_level=4" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ trunc_hmac=1" \ 0 \ - -s "dumping 'computed mac' (20 bytes)" \ - -S "dumping 'computed mac' (10 bytes)" + -s "dumping 'expected mac' (20 bytes)" \ + -S "dumping 'expected mac' (10 bytes)" run_test "Truncated HMAC: client enabled, server disabled" \ "$P_SRV debug_level=4 trunc_hmac=0" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ trunc_hmac=1" \ 0 \ - -s "dumping 'computed mac' (20 bytes)" \ - -S "dumping 'computed mac' (10 bytes)" + -s "dumping 'expected mac' (20 bytes)" \ + -S "dumping 'expected mac' (10 bytes)" run_test "Truncated HMAC: client enabled, server enabled" \ "$P_SRV debug_level=4 trunc_hmac=1" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ trunc_hmac=1" \ 0 \ - -S "dumping 'computed mac' (20 bytes)" \ - -s "dumping 'computed mac' (10 bytes)" + -S "dumping 'expected mac' (20 bytes)" \ + -s "dumping 'expected mac' (10 bytes)" # Tests for Encrypt-then-MAC extension From b09c5721f57d6988ec4a1dadeac7e6cc6ca65b9c Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 20 Nov 2017 10:43:35 +0000 Subject: [PATCH 41/46] Adapt ChangeLog --- ChangeLog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index 1b01eb682..e5ba2139b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,14 @@ mbed TLS ChangeLog (Sorted per branch, date) = mbed TLS 2.1.10 branch released 2017-xx-xx +Security + * Fix heap corruption in implementation of truncated HMAC extension. + When the truncated HMAC extension is enabled and CBC is used, + sending a malicious application packet can be used to selectively + corrupt 6 bytes on the peer's heap, potentially leading to crash or + remote code execution. This can be triggered remotely from either + side in both TLS and DTLS. + Bugfix * Fix ssl_parse_record_header() to silently discard invalid DTLS records as recommended in RFC 6347 Section 4.1.2.7. From 86eece9e878dc78f4427ad911211dcfd2948ada9 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 23 Nov 2017 19:04:39 +0100 Subject: [PATCH 42/46] ChangeLog entry for ssl_parse_client_psk_identity fix --- ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 47ede8db3..ef3f633e1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ mbed TLS ChangeLog (Sorted per branch, date) += mbed TLS 2.1.x released xxxx-xx-xx + +Security + * Fix unsafe bounds check in ssl_parse_client_psk_identity() when adding + 64kB to the address of the SSL buffer wraps around. + = mbed TLS 2.1.8 released 2017-06-21 Security From 2f615af5cf99acffbf4a8d045481373578fae01b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 28 Nov 2017 13:34:24 +0100 Subject: [PATCH 43/46] add changelog entry --- ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 47ede8db3..094d712f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ mbed TLS ChangeLog (Sorted per branch, date) += mbed TLS 2.1.x released xxxx-xx-xx + +Security + + * Tighten should-be-constant-time memcmp against compiler optimizations. + = mbed TLS 2.1.8 released 2017-06-21 Security From e40802aebc22bb107f532cdf7eaf1f9fc20aaf1b Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 7 Dec 2017 08:22:51 +0000 Subject: [PATCH 44/46] Correct record header size in case of TLS The previous commit reduced the internal header size to 5 bytes in case of TLS. This is not a valid since in that situation Mbed TLS internally uses the first 8 bytes of the message buffer for the implicit record sequence number. --- include/mbedtls/ssl_internal.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index 2d99d4018..c1534420a 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -154,14 +154,10 @@ #error Bad configuration - protected record payload too large. #endif -#if !defined(MBEDTLS_SSL_PROTO_DTLS) -/* https://tools.ietf.org/html/rfc5246#section-6.2 */ -#define MBEDTLS_SSL_HEADER_LEN 5 -#else -/* https://tools.ietf.org/html/rfc6347#section-4.1 */ -/* 8 additional bytes for epoch and sequence number */ +/* Note: Even though the TLS record header is only 5 bytes + long, we're internally using 8 bytes to store the + implicit sequence number. */ #define MBEDTLS_SSL_HEADER_LEN 13 -#endif #define MBEDTLS_SSL_BUFFER_LEN \ ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_PAYLOAD_LEN ) ) From b67a5c1f29ffa4f9620c125efb1164bf0ccbfc2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 18 Dec 2017 18:04:59 +0100 Subject: [PATCH 45/46] Fix SSLv3 MAC computation In a previous PR (Fix heap corruption in implementation of truncated HMAC extension #425) the place where MAC is computed was changed from the end of the SSL I/O buffer to a local buffer (then (part of) the content of the local buffer is either copied to the output buffer of compare to the input buffer). Unfortunately, this change was made only for TLS 1.0 and later, leaving SSL 3.0 in an inconsistent state due to ssl_mac() still writing to the old, hard-coded location, which, for MAC verification, resulted in later comparing the end of the input buffer (containing the computed MAC) to the local buffer (uninitialised), most likely resulting in MAC verification failure, hence no interop (even with ourselves). This commit completes the move to using a local buffer by using this strategy for SSL 3.0 too. Fortunately ssl_mac() was static so it's not a problem to change its signature. --- library/ssl_tls.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 16b4d4884..a9ba6e53b 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1194,9 +1194,11 @@ int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exch /* * SSLv3.0 MAC functions */ -static void ssl_mac( mbedtls_md_context_t *md_ctx, unsigned char *secret, - unsigned char *buf, size_t len, - unsigned char *ctr, int type ) +static void ssl_mac( mbedtls_md_context_t *md_ctx, + const unsigned char *secret, + const unsigned char *buf, size_t len, + const unsigned char *ctr, int type, + unsigned char out[20] ) { unsigned char header[11]; unsigned char padding[48]; @@ -1221,14 +1223,14 @@ static void ssl_mac( mbedtls_md_context_t *md_ctx, unsigned char *secret, mbedtls_md_update( md_ctx, padding, padlen ); mbedtls_md_update( md_ctx, header, 11 ); mbedtls_md_update( md_ctx, buf, len ); - mbedtls_md_finish( md_ctx, buf + len ); + mbedtls_md_finish( md_ctx, out ); memset( padding, 0x5C, padlen ); mbedtls_md_starts( md_ctx ); mbedtls_md_update( md_ctx, secret, md_size ); mbedtls_md_update( md_ctx, padding, padlen ); - mbedtls_md_update( md_ctx, buf + len, md_size ); - mbedtls_md_finish( md_ctx, buf + len ); + mbedtls_md_update( md_ctx, out, md_size ); + mbedtls_md_finish( md_ctx, out ); } #endif /* MBEDTLS_SSL_PROTO_SSL3 */ @@ -1273,10 +1275,15 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_SSL_PROTO_SSL3) if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) { + unsigned char mac[20]; /* SHA-1 at most */ + ssl_mac( &ssl->transform_out->md_ctx_enc, ssl->transform_out->mac_enc, ssl->out_msg, ssl->out_msglen, - ssl->out_ctr, ssl->out_msgtype ); + ssl->out_ctr, ssl->out_msgtype, + mac ); + + memcpy( ssl->out_msg + ssl->out_msglen, mac, ssl->transform_out->maclen ); } else #endif @@ -1923,7 +1930,8 @@ static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) ssl_mac( &ssl->transform_in->md_ctx_dec, ssl->transform_in->mac_dec, ssl->in_msg, ssl->in_msglen, - ssl->in_ctr, ssl->in_msgtype ); + ssl->in_ctr, ssl->in_msgtype, + mac_expect ); } else #endif /* MBEDTLS_SSL_PROTO_SSL3 */ From 4b133e6dcf8cd1a05b6a05949f0db3996d39a7ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 19 Dec 2017 10:03:46 +0100 Subject: [PATCH 46/46] Fix magic constant in previous commit --- library/ssl_tls.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index a9ba6e53b..da0806678 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1194,11 +1194,12 @@ int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exch /* * SSLv3.0 MAC functions */ +#define SSL_MAC_MAX_BYTES 20 /* MD-5 or SHA-1 */ static void ssl_mac( mbedtls_md_context_t *md_ctx, const unsigned char *secret, const unsigned char *buf, size_t len, const unsigned char *ctr, int type, - unsigned char out[20] ) + unsigned char out[SSL_MAC_MAX_BYTES] ) { unsigned char header[11]; unsigned char padding[48]; @@ -1275,7 +1276,7 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_SSL_PROTO_SSL3) if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) { - unsigned char mac[20]; /* SHA-1 at most */ + unsigned char mac[SSL_MAC_MAX_BYTES]; ssl_mac( &ssl->transform_out->md_ctx_enc, ssl->transform_out->mac_enc,