Merge pull request #782 from chris-jones-arm/mbedtls-2.16-restricted
[Backport 2.16] Fix Diffie-Hellman large key size DoS
diff --git a/ChangeLog.d/mpi_fill_random-rng_failure.txt b/ChangeLog.d/mpi_fill_random-rng_failure.txt
new file mode 100644
index 0000000..8addf18
--- /dev/null
+++ b/ChangeLog.d/mpi_fill_random-rng_failure.txt
@@ -0,0 +1,8 @@
+Security
+ * A failure of the random generator was ignored in mbedtls_mpi_fill_random(),
+ which is how most uses of randomization in asymmetric cryptography
+ (including key generation, intermediate value randomization and blinding)
+ are implemented. This could cause failures or the silent use of non-random
+ values. A random generator can fail if it needs reseeding and cannot not
+ obtain entropy, or due to an internal failure (which, for Mbed TLS's own
+ CTR_DRBG or HMAC_DRBG, can only happen due to a misconfiguration).
diff --git a/ChangeLog.d/x509-add-tag-check-to-algorithm-params b/ChangeLog.d/x509-add-tag-check-to-algorithm-params
new file mode 100644
index 0000000..f2c72b0
--- /dev/null
+++ b/ChangeLog.d/x509-add-tag-check-to-algorithm-params
@@ -0,0 +1,11 @@
+Security
+ * Fix a compliance issue whereby we were not checking the tag on the
+ algorithm parameters (only the size) when comparing the signature in the
+ description part of the cert to the real signature. This meant that a
+ NULL algorithm parameters entry would look identical to an array of REAL
+ (size zero) to the library and thus the certificate would be considered
+ valid. However, if the parameters do not match in *any* way then the
+ certificate should be considered invalid, and indeed OpenSSL marks these
+ certs as invalid when mbedtls did not.
+ Many thanks to guidovranken who found this issue via differential fuzzing
+ and reported it in #3629.
diff --git a/library/bignum.c b/library/bignum.c
index a9d5194..55d9482 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -2338,7 +2338,7 @@
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
Xp = (unsigned char*) X->p;
- f_rng( p_rng, Xp + overhead, size );
+ MBEDTLS_MPI_CHK( f_rng( p_rng, Xp + overhead, size ) );
mpi_bigendian_to_host( X->p, limbs );
diff --git a/library/x509_crt.c b/library/x509_crt.c
index d519a3f..fd89135 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -1088,6 +1088,7 @@
if( crt->sig_oid.len != sig_oid2.len ||
memcmp( crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len ) != 0 ||
+ sig_params1.tag != sig_params2.tag ||
sig_params1.len != sig_params2.len ||
( sig_params1.len != 0 &&
memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) )
diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile
index 0429bdd..6c9e245 100644
--- a/tests/data_files/Makefile
+++ b/tests/data_files/Makefile
@@ -155,7 +155,11 @@
$(OPENSSL) x509 -in $< -out $@ -inform PEM -outform DER
all_final += cli-rsa-sha256.crt.der
- cli-rsa.key.der: $(cli_crt_key_file_rsa)
+cli-rsa-sha256-badalg.crt.der: cli-rsa-sha256.crt.der
+ hexdump -ve '1/1 "%.2X"' $< | sed "s/06092A864886F70D01010B0500/06092A864886F70D01010B0900/2" | xxd -r -p > $@
+all_final += cli-rsa-sha256-badalg.crt.der
+
+cli-rsa.key.der: $(cli_crt_key_file_rsa)
$(OPENSSL) pkey -in $< -out $@ -inform PEM -outform DER
all_final += cli-rsa.key.der
diff --git a/tests/data_files/cli-rsa-sha256-badalg.crt.der b/tests/data_files/cli-rsa-sha256-badalg.crt.der
new file mode 100644
index 0000000..c40ba2a
--- /dev/null
+++ b/tests/data_files/cli-rsa-sha256-badalg.crt.der
Binary files differ
diff --git a/tests/suites/test_suite_mpi.data b/tests/suites/test_suite_mpi.data
index e5ec777..1298689 100644
--- a/tests/suites/test_suite_mpi.data
+++ b/tests/suites/test_suite_mpi.data
@@ -949,6 +949,48 @@
Test bit set (Invalid bit value)
mbedtls_mpi_set_bit:16:"00":5:2:16:"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+Fill random: 0 bytes
+mpi_fill_random:0:0:0
+
+Fill random: 1 byte, good
+mpi_fill_random:1:1:0
+
+Fill random: 2 bytes, good, no leading zero
+mpi_fill_random:2:2:0
+
+Fill random: 2 bytes, good, 1 leading zero
+mpi_fill_random:2:256:0
+
+Fill random: MAX_SIZE - 7, good
+mpi_fill_random:MBEDTLS_MPI_MAX_SIZE - 7:MBEDTLS_MPI_MAX_SIZE - 7:0
+
+Fill random: MAX_SIZE, good
+mpi_fill_random:MBEDTLS_MPI_MAX_SIZE:MBEDTLS_MPI_MAX_SIZE:0
+
+Fill random: 1 byte, RNG failure
+mpi_fill_random:1:0:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: 2 bytes, RNG failure after 1 byte
+mpi_fill_random:2:1:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: 4 bytes, RNG failure after 3 bytes
+mpi_fill_random:4:3:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: 8 bytes, RNG failure after 7 bytes
+mpi_fill_random:8:7:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: 16 bytes, RNG failure after 1 bytes
+mpi_fill_random:16:1:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: 16 bytes, RNG failure after 8 bytes
+mpi_fill_random:16:8:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: 16 bytes, RNG failure after 15 bytes
+mpi_fill_random:16:15:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: MAX_SIZE bytes, RNG failure after MAX_SIZE-1 bytes
+mpi_fill_random:MBEDTLS_MPI_MAX_SIZE:MBEDTLS_MPI_MAX_SIZE-1:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
MPI Selftest
depends_on:MBEDTLS_SELF_TEST
mpi_selftest:
diff --git a/tests/suites/test_suite_mpi.function b/tests/suites/test_suite_mpi.function
index 0335538..ffda605 100644
--- a/tests/suites/test_suite_mpi.function
+++ b/tests/suites/test_suite_mpi.function
@@ -1,5 +1,6 @@
/* BEGIN_HEADER */
#include "mbedtls/bignum.h"
+#include "mbedtls/entropy.h"
#if MBEDTLS_MPI_MAX_BITS > 792
#define MPI_MAX_BITS_LARGER_THAN_792
@@ -47,6 +48,22 @@
return( 0 );
}
+
+/* Random generator that is told how many bytes to return. */
+static int f_rng_bytes_left( void *state, unsigned char *buf, size_t len )
+{
+ size_t *bytes_left = state;
+ size_t i;
+ for( i = 0; i < len; i++ )
+ {
+ if( *bytes_left == 0 )
+ return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
+ buf[i] = *bytes_left & 0xff;
+ --( *bytes_left );
+ }
+ return( 0 );
+}
+
/* END_HEADER */
/* BEGIN_DEPENDENCIES
@@ -1289,6 +1306,37 @@
}
/* END_CASE */
+/* BEGIN_CASE */
+void mpi_fill_random( int wanted_bytes, int rng_bytes, int expected_ret )
+{
+ mbedtls_mpi X;
+ int ret;
+ size_t bytes_left = rng_bytes;
+ mbedtls_mpi_init( &X );
+
+ ret = mbedtls_mpi_fill_random( &X, wanted_bytes,
+ f_rng_bytes_left, &bytes_left );
+ TEST_ASSERT( ret == expected_ret );
+
+ if( expected_ret == 0 )
+ {
+ /* mbedtls_mpi_fill_random is documented to use bytes from the RNG
+ * as a big-endian representation of the number. We know when
+ * our RNG function returns null bytes, so we know how many
+ * leading zero bytes the number has. */
+ size_t leading_zeros = 0;
+ if( wanted_bytes > 0 && rng_bytes % 256 == 0 )
+ leading_zeros = 1;
+ TEST_ASSERT( mbedtls_mpi_size( &X ) + leading_zeros ==
+ (size_t) wanted_bytes );
+ TEST_ASSERT( (int) bytes_left == rng_bytes - wanted_bytes );
+ }
+
+exit:
+ mbedtls_mpi_free( &X );
+}
+/* END_CASE */
+
/* BEGIN_CASE depends_on:MBEDTLS_SELF_TEST */
void mpi_selftest( )
{
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 28ba79b..14ba0de 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -1876,6 +1876,10 @@
depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
x509parse_crt_file:"data_files/server7_trailing_space.crt":0
+X509 File parse (Algorithm Params Tag mismatch)
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+x509parse_crt_file:"data_files/cli-rsa-sha256-badalg.crt.der":MBEDTLS_ERR_X509_SIG_MISMATCH
+
X509 Get time (UTC no issues)
depends_on:MBEDTLS_X509_USE_C
x509_get_time:MBEDTLS_ASN1_UTC_TIME:"500101000000Z":0:1950:1:1:0:0:0