summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Cowgill <jcowgill@debian.org>2018-12-07 09:24:43 +0000
committerJames Cowgill <jcowgill@debian.org>2018-12-07 09:24:43 +0000
commit750a680ed676821e98d825ff1dc57d0954e0727a (patch)
treea446ad093483081d9fe546a5bf7913d60089f4de
parent65df33566b7892fd4bef47b29eb7f7840ecfec1d (diff)
parent60fbd5bdf05c223b641677204469b53c2ff39d4e (diff)
Merge tag 'mbedtls-2.14.1' into debian/master
Mbed TLS version 2.14.1
-rw-r--r--ChangeLog29
-rw-r--r--doxygen/input/doc_mainpage.h2
-rw-r--r--doxygen/mbedtls.doxyfile2
-rw-r--r--include/mbedtls/ctr_drbg.h39
-rw-r--r--include/mbedtls/hmac_drbg.h22
-rw-r--r--include/mbedtls/version.h8
-rw-r--r--library/CMakeLists.txt6
-rw-r--r--library/bignum.c45
-rw-r--r--library/ctr_drbg.c82
-rw-r--r--library/hmac_drbg.c93
-rw-r--r--library/rsa.c247
-rw-r--r--tests/suites/test_suite_ctr_drbg.function8
-rw-r--r--tests/suites/test_suite_pkcs1_v15.data90
-rw-r--r--tests/suites/test_suite_pkcs1_v15.function148
-rw-r--r--tests/suites/test_suite_version.data4
15 files changed, 683 insertions, 142 deletions
diff --git a/ChangeLog b/ChangeLog
index 8f0e8c1c..5219cfe5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,34 @@
mbed TLS ChangeLog (Sorted per branch, date)
+= mbed TLS 2.14.1 branch released 2018-11-30
+
+Security
+ * Fix timing variations and memory access variations in RSA PKCS#1 v1.5
+ decryption that could lead to a Bleichenbacher-style padding oracle
+ attack. In TLS, this affects servers that accept ciphersuites based on
+ RSA decryption (i.e. ciphersuites whose name contains RSA but not
+ (EC)DH(E)). Discovered by Eyal Ronen (Weizmann Institute), Robert Gillham
+ (University of Adelaide), Daniel Genkin (University of Michigan),
+ Adi Shamir (Weizmann Institute), David Wong (NCC Group), and Yuval Yarom
+ (University of Adelaide, Data61). The attack is described in more detail
+ in the paper available here: http://cat.eyalro.net/cat.pdf CVE-2018-19608
+ * In mbedtls_mpi_write_binary(), don't leak the exact size of the number
+ via branching and memory access patterns. An attacker who could submit
+ a plaintext for RSA PKCS#1 v1.5 decryption but only observe the timing
+ of the decryption and not its result could nonetheless decrypt RSA
+ plaintexts and forge RSA signatures. Other asymmetric algorithms may
+ have been similarly vulnerable. Reported by Eyal Ronen, Robert Gillham,
+ Daniel Genkin, Adi Shamir, David Wong and Yuval Yarom.
+ * Wipe sensitive buffers on the stack in the CTR_DRBG and HMAC_DRBG
+ modules.
+
+API Changes
+ * The new functions mbedtls_ctr_drbg_update_ret() and
+ mbedtls_hmac_drbg_update_ret() are similar to mbedtls_ctr_drbg_update()
+ and mbedtls_hmac_drbg_update() respectively, but the new functions
+ report errors whereas the old functions return void. We recommend that
+ applications use the new functions.
+
= mbed TLS 2.14.0 branch released 2018-11-19
Security
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index 44280d25..bfba2d96 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -24,7 +24,7 @@
*/
/**
- * @mainpage mbed TLS v2.14.0 source code documentation
+ * @mainpage mbed TLS v2.14.1 source code documentation
*
* This documentation describes the internal structure of mbed TLS. It was
* automatically generated from specially formatted comment blocks in
diff --git a/doxygen/mbedtls.doxyfile b/doxygen/mbedtls.doxyfile
index fd22cdbc..f75e3f5b 100644
--- a/doxygen/mbedtls.doxyfile
+++ b/doxygen/mbedtls.doxyfile
@@ -28,7 +28,7 @@ DOXYFILE_ENCODING = UTF-8
# identify the project. Note that if you do not use Doxywizard you need
# to put quotes around the project name if it contains spaces.
-PROJECT_NAME = "mbed TLS v2.14.0"
+PROJECT_NAME = "mbed TLS v2.14.1"
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
diff --git a/include/mbedtls/ctr_drbg.h b/include/mbedtls/ctr_drbg.h
index c91ca58b..304bc911 100644
--- a/include/mbedtls/ctr_drbg.h
+++ b/include/mbedtls/ctr_drbg.h
@@ -237,20 +237,41 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
const unsigned char *additional, size_t len );
/**
- * \brief This function updates the state of the CTR_DRBG context.
+ * \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 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,
+ const unsigned char *additional,
+ size_t add_len );
+
+/**
+ * \brief This function updates the state of the CTR_DRBG context.
*
- * \param ctx The CTR_DRBG context.
- * \param additional The data to update the state with.
- * \param add_len Length of \p additional data.
+ * \warning This function cannot report errors. You should use
+ * mbedtls_ctr_drbg_update_ret() instead.
*
+ * \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.
*/
void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx,
- const unsigned char *additional, size_t add_len );
+ const unsigned char *additional,
+ size_t add_len );
/**
* \brief This function updates a CTR_DRBG instance with additional
diff --git a/include/mbedtls/hmac_drbg.h b/include/mbedtls/hmac_drbg.h
index 3bc675ec..2e1108b0 100644
--- a/include/mbedtls/hmac_drbg.h
+++ b/include/mbedtls/hmac_drbg.h
@@ -195,13 +195,33 @@ 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 );
/**
+ * \brief HMAC_DRBG update state
+ *
+ * \warning This function cannot report errors. You should use
+ * mbedtls_hmac_drbg_update_ret() instead.
+ *
+ * \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.
+ */
+void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx,
+ const unsigned char *additional,
+ size_t add_len );
+
+/**
* \brief HMAC_DRBG reseeding (extracts data from entropy source)
*
* \param ctx HMAC_DRBG context
diff --git a/include/mbedtls/version.h b/include/mbedtls/version.h
index 492fde38..9ce09426 100644
--- a/include/mbedtls/version.h
+++ b/include/mbedtls/version.h
@@ -40,16 +40,16 @@
*/
#define MBEDTLS_VERSION_MAJOR 2
#define MBEDTLS_VERSION_MINOR 14
-#define MBEDTLS_VERSION_PATCH 0
+#define MBEDTLS_VERSION_PATCH 1
/**
* The single version number has the following structure:
* MMNNPP00
* Major version | Minor version | Patch version
*/
-#define MBEDTLS_VERSION_NUMBER 0x020E0000
-#define MBEDTLS_VERSION_STRING "2.14.0"
-#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.14.0"
+#define MBEDTLS_VERSION_NUMBER 0x020E0100
+#define MBEDTLS_VERSION_STRING "2.14.1"
+#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.14.1"
#if defined(MBEDTLS_VERSION_C)
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index ea513633..5e69d420 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -159,15 +159,15 @@ endif(USE_STATIC_MBEDTLS_LIBRARY)
if(USE_SHARED_MBEDTLS_LIBRARY)
add_library(mbedcrypto SHARED ${src_crypto})
- set_target_properties(mbedcrypto PROPERTIES VERSION 2.14.0 SOVERSION 3)
+ set_target_properties(mbedcrypto PROPERTIES VERSION 2.14.1 SOVERSION 3)
target_link_libraries(mbedcrypto ${libs})
add_library(mbedx509 SHARED ${src_x509})
- set_target_properties(mbedx509 PROPERTIES VERSION 2.14.0 SOVERSION 0)
+ set_target_properties(mbedx509 PROPERTIES VERSION 2.14.1 SOVERSION 0)
target_link_libraries(mbedx509 ${libs} mbedcrypto)
add_library(mbedtls SHARED ${src_tls})
- set_target_properties(mbedtls PROPERTIES VERSION 2.14.0 SOVERSION 12)
+ set_target_properties(mbedtls PROPERTIES VERSION 2.14.1 SOVERSION 12)
target_link_libraries(mbedtls ${libs} mbedx509)
install(TARGETS mbedtls mbedx509 mbedcrypto
diff --git a/library/bignum.c b/library/bignum.c
index ae5e7cfa..be4df2fe 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -321,6 +321,10 @@ int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos )
return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 );
}
+/* Get a specific byte, without range checks. */
+#define GET_BYTE( X, i ) \
+ ( ( ( X )->p[( i ) / ciL] >> ( ( ( i ) % ciL ) * 8 ) ) & 0xff )
+
/*
* Set a bit to a specific value of 0 or 1
*/
@@ -704,19 +708,40 @@ cleanup:
/*
* Export X into unsigned binary data, big endian
*/
-int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen )
+int mbedtls_mpi_write_binary( const mbedtls_mpi *X,
+ unsigned char *buf, size_t buflen )
{
- size_t i, j, n;
-
- n = mbedtls_mpi_size( X );
-
- if( buflen < n )
- return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
+ size_t stored_bytes = X->n * ciL;
+ size_t bytes_to_copy;
+ unsigned char *p;
+ size_t i;
- memset( buf, 0, buflen );
+ if( stored_bytes < buflen )
+ {
+ /* There is enough space in the output buffer. Write initial
+ * null bytes and record the position at which to start
+ * writing the significant bytes. In this case, the execution
+ * trace of this function does not depend on the value of the
+ * number. */
+ bytes_to_copy = stored_bytes;
+ p = buf + buflen - stored_bytes;
+ memset( buf, 0, buflen - stored_bytes );
+ }
+ else
+ {
+ /* The output buffer is smaller than the allocated size of X.
+ * However X may fit if its leading bytes are zero. */
+ bytes_to_copy = buflen;
+ p = buf;
+ for( i = bytes_to_copy; i < stored_bytes; i++ )
+ {
+ if( GET_BYTE( X, i ) != 0 )
+ return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
+ }
+ }
- for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- )
- buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) );
+ for( i = 0; i < bytes_to_copy; i++ )
+ p[bytes_to_copy - i - 1] = GET_BYTE( X, i );
return( 0 );
}
diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c
index fead18f7..0655e765 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 &sect;10.2.1.3.2)
@@ -333,21 +331,36 @@ static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx,
* 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 );
- }
+ 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 );
+}
+
+/* Deprecated function, kept for backward compatibility. */
+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 );
}
/* CTR_DRBG_Reseed with derivation function (SP 800-90A &sect;10.2.1.4.2)
@@ -399,20 +412,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 &sect;10.2.1.5.2)
@@ -467,13 +478,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 +496,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 +509,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 );
}
@@ -581,7 +587,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/library/hmac_drbg.c b/library/hmac_drbg.c
index dad55ff8..73c606b9 100644
--- a/library/hmac_drbg.c
+++ b/library/hmac_drbg.c
@@ -66,29 +66,56 @@ 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 );
+}
+
+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 );
}
/*
@@ -108,10 +135,13 @@ 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 ) );
- mbedtls_hmac_drbg_update( ctx, data, data_len );
+ if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, data, data_len ) ) != 0 )
+ return( ret );
return( 0 );
}
@@ -124,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 ||
@@ -135,7 +166,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;
@@ -148,13 +180,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 */
- return( 0 );
+ mbedtls_platform_zeroize( seed, seedlen );
+ return( ret );
}
/*
@@ -180,7 +215,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;
@@ -273,16 +309,24 @@ 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 )
{
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;
@@ -290,13 +334,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 );
}
/*
@@ -388,7 +435,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 );
diff --git a/library/rsa.c b/library/rsa.c
index 7615e1e5..0a533d42 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -1387,6 +1387,97 @@ cleanup:
#endif /* MBEDTLS_PKCS1_V21 */
#if defined(MBEDTLS_PKCS1_V15)
+/** Turn zero-or-nonzero into zero-or-all-bits-one, without branches.
+ *
+ * \param value The value to analyze.
+ * \return Zero if \p value is zero, otherwise all-bits-one.
+ */
+static unsigned all_or_nothing_int( unsigned value )
+{
+ /* MSVC has a warning about unary minus on unsigned, but this is
+ * well-defined and precisely what we want to do here */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+ return( - ( ( value | - value ) >> ( sizeof( value ) * 8 - 1 ) ) );
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+}
+
+/** Check whether a size is out of bounds, without branches.
+ *
+ * This is equivalent to `size > max`, but is likely to be compiled to
+ * to code using bitwise operation rather than a branch.
+ *
+ * \param size Size to check.
+ * \param max Maximum desired value for \p size.
+ * \return \c 0 if `size <= max`.
+ * \return \c 1 if `size > max`.
+ */
+static unsigned size_greater_than( size_t size, size_t max )
+{
+ /* Return the sign bit (1 for negative) of (max - size). */
+ return( ( max - size ) >> ( sizeof( size_t ) * 8 - 1 ) );
+}
+
+/** Choose between two integer values, without branches.
+ *
+ * This is equivalent to `cond ? if1 : if0`, but is likely to be compiled
+ * to code using bitwise operation rather than a branch.
+ *
+ * \param cond Condition to test.
+ * \param if1 Value to use if \p cond is nonzero.
+ * \param if0 Value to use if \p cond is zero.
+ * \return \c if1 if \p cond is nonzero, otherwise \c if0.
+ */
+static unsigned if_int( unsigned cond, unsigned if1, unsigned if0 )
+{
+ unsigned mask = all_or_nothing_int( cond );
+ return( ( mask & if1 ) | (~mask & if0 ) );
+}
+
+/** Shift some data towards the left inside a buffer without leaking
+ * the length of the data through side channels.
+ *
+ * `mem_move_to_left(start, total, offset)` is functionally equivalent to
+ * ```
+ * memmove(start, start + offset, total - offset);
+ * memset(start + offset, 0, total - offset);
+ * ```
+ * but it strives to use a memory access pattern (and thus total timing)
+ * that does not depend on \p offset. This timing independence comes at
+ * the expense of performance.
+ *
+ * \param start Pointer to the start of the buffer.
+ * \param total Total size of the buffer.
+ * \param offset Offset from which to copy \p total - \p offset bytes.
+ */
+static void mem_move_to_left( void *start,
+ size_t total,
+ size_t offset )
+{
+ volatile unsigned char *buf = start;
+ size_t i, n;
+ if( total == 0 )
+ return;
+ for( i = 0; i < total; i++ )
+ {
+ unsigned no_op = size_greater_than( total - offset, i );
+ /* The first `total - offset` passes are a no-op. The last
+ * `offset` passes shift the data one byte to the left and
+ * zero out the last byte. */
+ for( n = 0; n < total - 1; n++ )
+ {
+ unsigned char current = buf[n];
+ unsigned char next = buf[n+1];
+ buf[n] = if_int( no_op, current, next );
+ }
+ buf[total-1] = if_int( no_op, buf[total-1], 0 );
+ }
+}
+
/*
* Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function
*/
@@ -1396,18 +1487,34 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx,
int mode, size_t *olen,
const unsigned char *input,
unsigned char *output,
- size_t output_max_len)
+ size_t output_max_len )
{
int ret;
- size_t ilen, pad_count = 0, i;
- unsigned char *p, bad, pad_done = 0;
+ size_t ilen = ctx->len;
+ size_t i;
+ size_t plaintext_max_size = ( output_max_len > ilen - 11 ?
+ ilen - 11 :
+ output_max_len );
unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
+ /* The following variables take sensitive values: their value must
+ * not leak into the observable behavior of the function other than
+ * the designated outputs (output, olen, return value). Otherwise
+ * this would open the execution of the function to
+ * side-channel-based variants of the Bleichenbacher padding oracle
+ * attack. Potential side channels include overall timing, memory
+ * access patterns (especially visible to an adversary who has access
+ * to a shared memory cache), and branches (especially visible to
+ * an adversary who has access to a shared code cache or to a shared
+ * branch predictor). */
+ size_t pad_count = 0;
+ unsigned bad = 0;
+ unsigned char pad_done = 0;
+ size_t plaintext_size = 0;
+ unsigned output_too_large;
if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
- ilen = ctx->len;
-
if( ilen < 16 || ilen > sizeof( buf ) )
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
@@ -1418,63 +1525,109 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx,
if( ret != 0 )
goto cleanup;
- p = buf;
- bad = 0;
-
- /*
- * Check and get padding len in "constant-time"
- */
- bad |= *p++; /* First byte must be 0 */
+ /* Check and get padding length in constant time and constant
+ * memory trace. The first byte must be 0. */
+ bad |= buf[0];
- /* This test does not depend on secret data */
if( mode == MBEDTLS_RSA_PRIVATE )
{
- bad |= *p++ ^ MBEDTLS_RSA_CRYPT;
+ /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00
+ * where PS must be at least 8 nonzero bytes. */
+ bad |= buf[1] ^ MBEDTLS_RSA_CRYPT;
- /* Get padding len, but always read till end of buffer
- * (minus one, for the 00 byte) */
- for( i = 0; i < ilen - 3; i++ )
+ /* Read the whole buffer. Set pad_done to nonzero if we find
+ * the 0x00 byte and remember the padding length in pad_count. */
+ for( i = 2; i < ilen; i++ )
{
- pad_done |= ((p[i] | (unsigned char)-p[i]) >> 7) ^ 1;
+ pad_done |= ((buf[i] | (unsigned char)-buf[i]) >> 7) ^ 1;
pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1;
}
-
- p += pad_count;
- bad |= *p++; /* Must be zero */
}
else
{
- bad |= *p++ ^ MBEDTLS_RSA_SIGN;
+ /* Decode EMSA-PKCS1-v1_5 padding: 0x00 || 0x01 || PS || 0x00
+ * where PS must be at least 8 bytes with the value 0xFF. */
+ bad |= buf[1] ^ MBEDTLS_RSA_SIGN;
- /* Get padding len, but always read till end of buffer
- * (minus one, for the 00 byte) */
- for( i = 0; i < ilen - 3; i++ )
+ /* Read the whole buffer. Set pad_done to nonzero if we find
+ * the 0x00 byte and remember the padding length in pad_count.
+ * If there's a non-0xff byte in the padding, the padding is bad. */
+ for( i = 2; i < ilen; i++ )
{
- pad_done |= ( p[i] != 0xFF );
- pad_count += ( pad_done == 0 );
+ pad_done |= if_int( buf[i], 0, 1 );
+ pad_count += if_int( pad_done, 0, 1 );
+ bad |= if_int( pad_done, 0, buf[i] ^ 0xFF );
}
-
- p += pad_count;
- bad |= *p++; /* Must be zero */
}
- bad |= ( pad_count < 8 );
-
- if( bad )
- {
- ret = MBEDTLS_ERR_RSA_INVALID_PADDING;
- goto cleanup;
- }
-
- if( ilen - ( p - buf ) > output_max_len )
- {
- ret = MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE;
- goto cleanup;
- }
-
- *olen = ilen - (p - buf);
- memcpy( output, p, *olen );
- ret = 0;
+ /* If pad_done is still zero, there's no data, only unfinished padding. */
+ bad |= if_int( pad_done, 0, 1 );
+
+ /* There must be at least 8 bytes of padding. */
+ bad |= size_greater_than( 8, pad_count );
+
+ /* If the padding is valid, set plaintext_size to the number of
+ * remaining bytes after stripping the padding. If the padding
+ * is invalid, avoid leaking this fact through the size of the
+ * output: use the maximum message size that fits in the output
+ * buffer. Do it without branches to avoid leaking the padding
+ * validity through timing. RSA keys are small enough that all the
+ * size_t values involved fit in unsigned int. */
+ plaintext_size = if_int( bad,
+ (unsigned) plaintext_max_size,
+ (unsigned) ( ilen - pad_count - 3 ) );
+
+ /* Set output_too_large to 0 if the plaintext fits in the output
+ * buffer and to 1 otherwise. */
+ output_too_large = size_greater_than( plaintext_size,
+ plaintext_max_size );
+
+ /* Set ret without branches to avoid timing attacks. Return:
+ * - INVALID_PADDING if the padding is bad (bad != 0).
+ * - OUTPUT_TOO_LARGE if the padding is good but the decrypted
+ * plaintext does not fit in the output buffer.
+ * - 0 if the padding is correct. */
+ ret = - (int) if_int( bad, - MBEDTLS_ERR_RSA_INVALID_PADDING,
+ if_int( output_too_large, - MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE,
+ 0 ) );
+
+ /* If the padding is bad or the plaintext is too large, zero the
+ * data that we're about to copy to the output buffer.
+ * We need to copy the same amount of data
+ * from the same buffer whether the padding is good or not to
+ * avoid leaking the padding validity through overall timing or
+ * through memory or cache access patterns. */
+ bad = all_or_nothing_int( bad | output_too_large );
+ for( i = 11; i < ilen; i++ )
+ buf[i] &= ~bad;
+
+ /* If the plaintext is too large, truncate it to the buffer size.
+ * Copy anyway to avoid revealing the length through timing, because
+ * revealing the length is as bad as revealing the padding validity
+ * for a Bleichenbacher attack. */
+ plaintext_size = if_int( output_too_large,
+ (unsigned) plaintext_max_size,
+ (unsigned) plaintext_size );
+
+ /* Move the plaintext to the leftmost position where it can start in
+ * the working buffer, i.e. make it start plaintext_max_size from
+ * the end of the buffer. Do this with a memory access trace that
+ * does not depend on the plaintext size. After this move, the
+ * starting location of the plaintext is no longer sensitive
+ * information. */
+ mem_move_to_left( buf + ilen - plaintext_max_size,
+ plaintext_max_size,
+ plaintext_max_size - plaintext_size );
+
+ /* Finally copy the decrypted plaintext plus trailing zeros
+ * into the output buffer. */
+ memcpy( output, buf + ilen - plaintext_max_size, plaintext_max_size );
+
+ /* Report the amount of data we copied to the output buffer. In case
+ * of errors (bad padding or output too large), the value of *olen
+ * when this function returns is not specified. Making it equivalent
+ * to the good case limits the risks of leaking the padding validity. */
+ *olen = plaintext_size;
cleanup:
mbedtls_platform_zeroize( buf, sizeof( buf ) );
diff --git a/tests/suites/test_suite_ctr_drbg.function b/tests/suites/test_suite_ctr_drbg.function
index f10e98aa..4a97826f 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 );
diff --git a/tests/suites/test_suite_pkcs1_v15.data b/tests/suites/test_suite_pkcs1_v15.data
index 03094000..a4d6eb54 100644
--- a/tests/suites/test_suite_pkcs1_v15.data
+++ b/tests/suites/test_suite_pkcs1_v15.data
@@ -33,3 +33,93 @@ pkcs1_rsassa_v15_sign:1024:16:"d17f655bf27c8b16d35462c905cc04a26f37e2a67fa9c0ce0
RSASSA-V15 Verification Test Vector Int
pkcs1_rsassa_v15_verify:1024:16:"a2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5":16:"010001":MBEDTLS_MD_SHA1:MBEDTLS_MD_SHA1:"859eef2fd78aca00308bdc471193bf55bf9d78db8f8a672b484634f3c9c26e6478ae10260fe0dd8c082e53a5293af2173cd50c6d5d354febf78b26021c25c02712e78cd4694c9f469777e451e7f8e9e04cd3739c6bbfedae487fb55644e9ca74ff77a53cb729802f6ed4a5ffa8ba159890fc":"e3b5d5d002c1bce50c2b65ef88a188d83bce7e61":"2154f928615e5101fcdeb57bc08fc2f35c3d5996403861ae3efb1d0712f8bb05cc21f7f5f11f62e5b6ea9f0f2b62180e5cbe7ba535032d6ac8068fff7f362f73d2c3bf5eca6062a1723d7cfd5abb6dcf7e405f2dc560ffe6fc37d38bee4dc9e24fe2bece3e3b4a3f032701d3f0947b42930083dd4ad241b3309b514595482d42":0
+
+RSAES-V15 decoding: good, payload=max, tight output buffer
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0002505152535455565700":117:117:0
+
+RSAES-V15 decoding: good, payload=max, larger output buffer
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0002505152535455565700":117:128:0
+
+RSAES-V15 decoding: good, payload=max-1, tight output buffer
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"000250515253545556575800":116:116:0
+
+RSAES-V15 decoding: good, payload=max-1, larger output buffer
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"000250515253545556575800":116:117:0
+
+RSAES-V15 decoding: good, payload=1
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"00025050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505000":1:1:0
+
+RSAES-V15 decoding: good, empty payload
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0002505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505000":0:0:0
+
+RSAES-V15 decoding: payload=max, output too large
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0002505152535455565700":117:116:MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE
+
+RSAES-V15 decoding: payload=max-1, output too large
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"000250515253545556575800":116:115:MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE
+
+RSAES-V15 decoding: bad first byte
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0102505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+RSAES-V15 decoding: bad second byte (0 instead of 2)
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0000505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+RSAES-V15 decoding: bad second byte (1 instead of 2)
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0001505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+RSAES-V15 decoding: padding too short (0)
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"000200":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+RSAES-V15 decoding: padding too short (7)
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0002505050505050500000ffffffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+RSAES-V15 decoding: unfinished padding
+pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0002505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+EMSA-V15 decoding: good, payload=max, tight output buffer
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffff00":117:117:0
+
+EMSA-V15 decoding: good, payload=max, larger output buffer
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffff00":117:128:0
+
+EMSA-V15 decoding: good, payload=max-1, tight output buffer
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffffff00":116:116:0
+
+EMSA-V15 decoding: good, payload=max-1, larger output buffer
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffffff00":116:117:0
+
+EMSA-V15 decoding: good, payload=1
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00":1:1:0
+
+EMSA-V15 decoding: good, empty payload
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00":0:0:0
+
+EMSA-V15 decoding: bad first byte
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0101ffffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+EMSA-V15 decoding: bad second byte (0 instead of 1)
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0000ffffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+EMSA-V15 decoding: bad second byte (2 instead of 1)
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0002ffffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+EMSA-V15 decoding: padding too short (0)
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"000100":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+EMSA-V15 decoding: padding too short (7)
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffff0000ffffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+EMSA-V15 decoding: invalid padding at first byte
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001fffffffffffffffe00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+EMSA-V15 decoding: invalid padding at last byte
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001feffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+EMSA-V15 decoding: unfinished padding
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+EMSA-V15 decoding: unfinished padding with invalid first byte
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
+
+EMSA-V15 decoding: unfinished padding with invalid last byte
+pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING
diff --git a/tests/suites/test_suite_pkcs1_v15.function b/tests/suites/test_suite_pkcs1_v15.function
index 83f417ca..0723623a 100644
--- a/tests/suites/test_suite_pkcs1_v15.function
+++ b/tests/suites/test_suite_pkcs1_v15.function
@@ -94,6 +94,154 @@ exit:
/* END_CASE */
/* BEGIN_CASE */
+void pkcs1_v15_decode( int mode,
+ data_t *input,
+ int expected_plaintext_length_arg,
+ int output_size_arg,
+ int expected_result )
+{
+ size_t expected_plaintext_length = expected_plaintext_length_arg;
+ size_t output_size = output_size_arg;
+ rnd_pseudo_info rnd_info;
+ mbedtls_mpi Nmpi, Empi, Pmpi, Qmpi;
+ mbedtls_rsa_context ctx;
+ static unsigned char N[128] = {
+ 0xc4, 0x79, 0x4c, 0x6d, 0xb2, 0xe9, 0xdf, 0xc5,
+ 0xe5, 0xd7, 0x55, 0x4b, 0xfb, 0x6c, 0x2e, 0xec,
+ 0x84, 0xd0, 0x88, 0x12, 0xaf, 0xbf, 0xb4, 0xf5,
+ 0x47, 0x3c, 0x7e, 0x92, 0x4c, 0x58, 0xc8, 0x73,
+ 0xfe, 0x8f, 0x2b, 0x8f, 0x8e, 0xc8, 0x5c, 0xf5,
+ 0x05, 0xeb, 0xfb, 0x0d, 0x7b, 0x2a, 0x93, 0xde,
+ 0x15, 0x0d, 0xc8, 0x13, 0xcf, 0xd2, 0x6f, 0x0d,
+ 0x9d, 0xad, 0x30, 0xe5, 0x70, 0x20, 0x92, 0x9e,
+ 0xb3, 0x6b, 0xba, 0x5c, 0x50, 0x0f, 0xc3, 0xb2,
+ 0x7e, 0x64, 0x07, 0x94, 0x7e, 0xc9, 0x4e, 0xc1,
+ 0x65, 0x04, 0xaf, 0xb3, 0x9f, 0xde, 0xa8, 0x46,
+ 0xfa, 0x6c, 0xf3, 0x03, 0xaf, 0x1c, 0x1b, 0xec,
+ 0x75, 0x44, 0x66, 0x77, 0xc9, 0xde, 0x51, 0x33,
+ 0x64, 0x27, 0xb0, 0xd4, 0x8d, 0x31, 0x6a, 0x11,
+ 0x27, 0x3c, 0x99, 0xd4, 0x22, 0xc0, 0x9d, 0x12,
+ 0x01, 0xc7, 0x4a, 0x73, 0xac, 0xbf, 0xc2, 0xbb
+ };
+ static unsigned char E[1] = { 0x03 };
+ static unsigned char P[64] = {
+ 0xe5, 0x53, 0x1f, 0x88, 0x51, 0xee, 0x59, 0xf8,
+ 0xc1, 0xe4, 0xcc, 0x5b, 0xb3, 0x75, 0x8d, 0xc8,
+ 0xe8, 0x95, 0x2f, 0xd0, 0xef, 0x37, 0xb4, 0xcd,
+ 0xd3, 0x9e, 0x48, 0x8b, 0x81, 0x58, 0x60, 0xb9,
+ 0x27, 0x1d, 0xb6, 0x28, 0x92, 0x64, 0xa3, 0xa5,
+ 0x64, 0xbd, 0xcc, 0x53, 0x68, 0xdd, 0x3e, 0x55,
+ 0xea, 0x9d, 0x5e, 0xcd, 0x1f, 0x96, 0x87, 0xf1,
+ 0x29, 0x75, 0x92, 0x70, 0x8f, 0x28, 0xfb, 0x2b
+ };
+ static unsigned char Q[64] = {
+ 0xdb, 0x53, 0xef, 0x74, 0x61, 0xb4, 0x20, 0x3b,
+ 0x3b, 0x87, 0x76, 0x75, 0x81, 0x56, 0x11, 0x03,
+ 0x59, 0x31, 0xe3, 0x38, 0x4b, 0x8c, 0x7a, 0x9c,
+ 0x05, 0xd6, 0x7f, 0x1e, 0x5e, 0x60, 0xf0, 0x4e,
+ 0x0b, 0xdc, 0x34, 0x54, 0x1c, 0x2e, 0x90, 0x83,
+ 0x14, 0xef, 0xc0, 0x96, 0x5c, 0x30, 0x10, 0xcc,
+ 0xc1, 0xba, 0xa0, 0x54, 0x3f, 0x96, 0x24, 0xca,
+ 0xa3, 0xfb, 0x55, 0xbc, 0x71, 0x29, 0x4e, 0xb1
+ };
+ unsigned char original[128];
+ unsigned char intermediate[128];
+ static unsigned char default_content[128] = {
+ /* A randomly generated pattern. */
+ 0x4c, 0x27, 0x54, 0xa0, 0xce, 0x0d, 0x09, 0x4a,
+ 0x1c, 0x38, 0x8e, 0x2d, 0xa3, 0xc4, 0xe0, 0x19,
+ 0x4c, 0x99, 0xb2, 0xbf, 0xe6, 0x65, 0x7e, 0x58,
+ 0xd7, 0xb6, 0x8a, 0x05, 0x2f, 0xa5, 0xec, 0xa4,
+ 0x35, 0xad, 0x10, 0x36, 0xff, 0x0d, 0x08, 0x50,
+ 0x74, 0x47, 0xc9, 0x9c, 0x4a, 0xe7, 0xfd, 0xfa,
+ 0x83, 0x5f, 0x14, 0x5a, 0x1e, 0xe7, 0x35, 0x08,
+ 0xad, 0xf7, 0x0d, 0x86, 0xdf, 0xb8, 0xd4, 0xcf,
+ 0x32, 0xb9, 0x5c, 0xbe, 0xa3, 0xd2, 0x89, 0x70,
+ 0x7b, 0xc6, 0x48, 0x7e, 0x58, 0x4d, 0xf3, 0xef,
+ 0x34, 0xb7, 0x57, 0x54, 0x79, 0xc5, 0x8e, 0x0a,
+ 0xa3, 0xbf, 0x6d, 0x42, 0x83, 0x25, 0x13, 0xa2,
+ 0x95, 0xc0, 0x0d, 0x32, 0xec, 0x77, 0x91, 0x2b,
+ 0x68, 0xb6, 0x8c, 0x79, 0x15, 0xfb, 0x94, 0xde,
+ 0xb9, 0x2b, 0x94, 0xb3, 0x28, 0x23, 0x86, 0x3d,
+ 0x37, 0x00, 0xe6, 0xf1, 0x1f, 0x4e, 0xd4, 0x42
+ };
+ unsigned char final[128];
+ size_t output_length = 0x7EA0;
+
+ memset( &rnd_info, 0, sizeof( rnd_pseudo_info ) );
+ mbedtls_mpi_init( &Nmpi ); mbedtls_mpi_init( &Empi );
+ mbedtls_mpi_init( &Pmpi ); mbedtls_mpi_init( &Qmpi );
+ mbedtls_rsa_init( &ctx, MBEDTLS_RSA_PKCS_V15, 0 );
+
+ TEST_ASSERT( mbedtls_mpi_read_binary( &Nmpi, N, sizeof( N ) ) == 0 );
+ TEST_ASSERT( mbedtls_mpi_read_binary( &Empi, E, sizeof( E ) ) == 0 );
+ TEST_ASSERT( mbedtls_mpi_read_binary( &Pmpi, P, sizeof( P ) ) == 0 );
+ TEST_ASSERT( mbedtls_mpi_read_binary( &Qmpi, Q, sizeof( Q ) ) == 0 );
+
+ TEST_ASSERT( mbedtls_rsa_import( &ctx, &Nmpi, &Pmpi, &Qmpi,
+ NULL, &Empi ) == 0 );
+ TEST_ASSERT( mbedtls_rsa_complete( &ctx ) == 0 );
+
+ TEST_ASSERT( input->len <= sizeof( N ) );
+ memcpy( original, input->x, input->len );
+ memset( original + input->len, 'd', sizeof( original ) - input->len );
+ if( mode == MBEDTLS_RSA_PRIVATE )
+ TEST_ASSERT( mbedtls_rsa_public( &ctx, original, intermediate ) == 0 );
+ else
+ TEST_ASSERT( mbedtls_rsa_private( &ctx, &rnd_pseudo_rand, &rnd_info,
+ original, intermediate ) == 0 );
+
+ memcpy( final, default_content, sizeof( final ) );
+ TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx,
+ &rnd_pseudo_rand, &rnd_info,
+ mode,
+ &output_length,
+ intermediate,
+ final,
+ output_size ) == expected_result );
+ if( expected_result == 0 )
+ {
+ TEST_ASSERT( output_length == expected_plaintext_length );
+ TEST_ASSERT( memcmp( original + sizeof( N ) - output_length,
+ final,
+ output_length ) == 0 );
+ }
+ else if( expected_result == MBEDTLS_ERR_RSA_INVALID_PADDING ||
+ expected_result == MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE )
+ {
+ size_t max_payload_length =
+ output_size > sizeof( N ) - 11 ? sizeof( N ) - 11 : output_size;
+ size_t i;
+ size_t count = 0;
+
+#if !defined(MBEDTLS_RSA_ALT)
+ /* Check that the output in invalid cases is what the default
+ * implementation currently does. Alternative implementations
+ * may produce different output, so we only perform these precise
+ * checks when using the default implementation. */
+ TEST_ASSERT( output_length == max_payload_length );
+ for( i = 0; i < max_payload_length; i++ )
+ TEST_ASSERT( final[i] == 0 );
+#endif
+ /* Even in alternative implementations, the outputs must have
+ * changed, otherwise it indicates at least a timing vulnerability
+ * because no write to the outputs is performed in the bad case. */
+ TEST_ASSERT( output_length != 0x7EA0 );
+ for( i = 0; i < max_payload_length; i++ )
+ count += ( final[i] == default_content[i] );
+ /* If more than 16 bytes are unchanged in final, that's evidence
+ * that final wasn't overwritten. */
+ TEST_ASSERT( count < 16 );
+ }
+
+exit:
+ mbedtls_mpi_free( &Nmpi ); mbedtls_mpi_free( &Empi );
+ mbedtls_mpi_free( &Pmpi ); mbedtls_mpi_free( &Qmpi );
+ mbedtls_rsa_free( &ctx );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
void pkcs1_rsassa_v15_sign( int mod, int radix_P, char * input_P, int radix_Q,
char * input_Q, int radix_N, char * input_N,
int radix_E, char * input_E, int digest, int hash,
diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data
index 3fe549ab..6a57309b 100644
--- a/tests/suites/test_suite_version.data
+++ b/tests/suites/test_suite_version.data
@@ -1,8 +1,8 @@
Check compiletime library version
-check_compiletime_version:"2.14.0"
+check_compiletime_version:"2.14.1"
Check runtime library version
-check_runtime_version:"2.14.0"
+check_runtime_version:"2.14.1"
Check for MBEDTLS_VERSION_C
check_feature:"MBEDTLS_VERSION_C":0