Merge pull request #4110 from gilles-peskine-arm/psa-external-random-in-mbedtls
Expose the PSA RNG in mbedtls
diff --git a/ChangeLog.d/mbedtls_psa_get_random.txt b/ChangeLog.d/mbedtls_psa_get_random.txt
new file mode 100644
index 0000000..f6e6b09
--- /dev/null
+++ b/ChangeLog.d/mbedtls_psa_get_random.txt
@@ -0,0 +1,9 @@
+Features
+ * Partial implementation of the PSA crypto driver interface: Mbed TLS can
+ now use an external random generator instead of the library's own
+ entropy collection and DRBG code. Enable MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+ and see the documentation of mbedtls_psa_external_get_random() for details.
+ * Applications using both mbedtls_xxx and psa_xxx functions (for example,
+ applications using TLS and MBEDTLS_USE_PSA_CRYPTO) can now use the PSA
+ random generator with mbedtls_xxx functions. See the documentation of
+ mbedtls_psa_get_random() for details.
diff --git a/include/mbedtls/psa_util.h b/include/mbedtls/psa_util.h
index 0b8a216..f18857c 100644
--- a/include/mbedtls/psa_util.h
+++ b/include/mbedtls/psa_util.h
@@ -419,4 +419,90 @@
#endif /* MBEDTLS_USE_PSA_CRYPTO */
+/* Expose whatever RNG the PSA subsystem uses to applications using the
+ * mbedtls_xxx API. The declarations and definitions here need to be
+ * consistent with the implementation in library/psa_crypto_random_impl.h.
+ * See that file for implementation documentation. */
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+
+/* The type of a `f_rng` random generator function that many library functions
+ * take.
+ *
+ * This type name is not part of the Mbed TLS stable API. It may be renamed
+ * or moved without warning.
+ */
+typedef int mbedtls_f_rng_t( void *p_rng, unsigned char *output, size_t output_size );
+
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+
+/** The random generator function for the PSA subsystem.
+ *
+ * This function is suitable as the `f_rng` random generator function
+ * parameter of many `mbedtls_xxx` functions. Use #MBEDTLS_PSA_RANDOM_STATE
+ * to obtain the \p p_rng parameter.
+ *
+ * The implementation of this function depends on the configuration of the
+ * library.
+ *
+ * \note Depending on the configuration, this may be a function or
+ * a pointer to a function.
+ *
+ * \note This function may only be used if the PSA crypto subsystem is active.
+ * This means that you must call psa_crypto_init() before any call to
+ * this function, and you must not call this function after calling
+ * mbedtls_psa_crypto_free().
+ *
+ * \param p_rng The random generator context. This must be
+ * #MBEDTLS_PSA_RANDOM_STATE. No other state is
+ * supported.
+ * \param output The buffer to fill. It must have room for
+ * \c output_size bytes.
+ * \param output_size The number of bytes to write to \p output.
+ * This function may fail if \p output_size is too
+ * large. It is guaranteed to accept any output size
+ * requested by Mbed TLS library functions. The
+ * maximum request size depends on the library
+ * configuration.
+ *
+ * \return \c 0 on success.
+ * \return An `MBEDTLS_ERR_ENTROPY_xxx`,
+ * `MBEDTLS_ERR_PLATFORM_xxx,
+ * `MBEDTLS_ERR_CTR_DRBG_xxx` or
+ * `MBEDTLS_ERR_HMAC_DRBG_xxx` on error.
+ */
+int mbedtls_psa_get_random( void *p_rng,
+ unsigned char *output,
+ size_t output_size );
+
+/** The random generator state for the PSA subsystem.
+ *
+ * This macro expands to an expression which is suitable as the `p_rng`
+ * random generator state parameter of many `mbedtls_xxx` functions.
+ * It must be used in combination with the random generator function
+ * mbedtls_psa_get_random().
+ *
+ * The implementation of this macro depends on the configuration of the
+ * library. Do not make any assumption on its nature.
+ */
+#define MBEDTLS_PSA_RANDOM_STATE NULL
+
+#else /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
+
+#if defined(MBEDTLS_CTR_DRBG_C)
+#include "mbedtls/ctr_drbg.h"
+typedef mbedtls_ctr_drbg_context mbedtls_psa_drbg_context_t;
+static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_ctr_drbg_random;
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+#include "mbedtls/hmac_drbg.h"
+typedef mbedtls_hmac_drbg_context mbedtls_psa_drbg_context_t;
+static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_hmac_drbg_random;
+#endif
+extern mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state;
+
+#define MBEDTLS_PSA_RANDOM_STATE mbedtls_psa_random_state
+
+#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
+
+#endif /* MBEDTLS_PSA_CRYPTO_C */
+
#endif /* MBEDTLS_PSA_UTIL_H */
diff --git a/library/entropy_poll.c b/library/entropy_poll.c
index 84b70fe..2c1e093 100644
--- a/library/entropy_poll.c
+++ b/library/entropy_poll.c
@@ -220,13 +220,13 @@
{
((void) data);
((void) output);
- *olen = 0;
+ *olen = 0;
if( len < sizeof(unsigned char) )
return( 0 );
+ output[0] = 0;
*olen = sizeof(unsigned char);
-
return( 0 );
}
#endif
diff --git a/library/psa_crypto_random_impl.h b/library/psa_crypto_random_impl.h
index 1232186..3c4c09a 100644
--- a/library/psa_crypto_random_impl.h
+++ b/library/psa_crypto_random_impl.h
@@ -1,6 +1,14 @@
/** \file psa_crypto_random_impl.h
*
* \brief PSA crypto random generator implementation abstraction.
+ *
+ * The definitions here need to be consistent with the declarations
+ * in include/mbedtls/psa_util.h. This file contains some redundant
+ * declarations to increase the chance that a compiler will detect
+ * inconsistencies if one file is changed without updating the other,
+ * but not all potential inconsistencies can be enforced, so make sure
+ * to check the public declarations and contracts in
+ * include/mbedtls/psa_util.h if you modify this file.
*/
/*
* Copyright The Mbed TLS Contributors
@@ -22,6 +30,8 @@
#ifndef PSA_CRYPTO_RANDOM_IMPL_H
#define PSA_CRYPTO_RANDOM_IMPL_H
+#include <mbedtls/psa_util.h>
+
#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
#include <string.h>
@@ -75,14 +85,6 @@
#include "mbedtls/entropy.h"
-/** The type of the PSA DRBG context.
- */
-#if defined(MBEDTLS_CTR_DRBG_C)
-typedef mbedtls_ctr_drbg_context mbedtls_psa_drbg_context_t;
-#elif defined(MBEDTLS_HMAC_DRBG_C)
-typedef mbedtls_hmac_drbg_context mbedtls_psa_drbg_context_t;
-#endif
-
/** Initialize the PSA DRBG.
*
* \param p_rng Pointer to the Mbed TLS DRBG state.
@@ -122,33 +124,18 @@
mbedtls_psa_drbg_context_t drbg;
} mbedtls_psa_random_context_t;
-/* The type of an Mbed TLS random generator function. This should be
- * part of the public API instead of repeating the type everywhere.
- * For the time being, declare it here. Declaring a type is necessary
- * to define mbedtls_psa_get_random as a variable of a function pointer
- * type without incurring the wrath of check-names.sh. */
-typedef int mbedtls_f_rng_t( void *p_rng, unsigned char *output, size_t output_size );
-
-/** Return random data.
- *
- * This function is suitable as the \p f_rng parameter to Mbed TLS functions
- * that require a random generator. Use #MBEDTLS_PSA_RANDOM_STATE to
- * obtain the \p p_rng parameter.
- *
- * \param p_rng The DRBG context. This must be
- * #MBEDTLS_PSA_RANDOM_STATE.
- * \param output The buffer to fill.
- * \param output_len The length of the buffer in bytes.
- * It must be at most #MBEDTLS_PSA_RANDOM_MAX_REQUEST.
- *
- * \retval \c 0 on success.
- * \return \c MBEDTLS_ERR_xxx_DRBG_xxx or
- * \c MBEDTLS_ERR_PLATFORM_xxx on failure.
+/* Defined in include/mbedtls/psa_util.h so that it's visible to
+ * application code. The declaration here is redundant, but included
+ * as a safety net to make it more likely that a future change that
+ * accidentally causes the implementation to diverge from the interface
+ * will be noticed. */
+/* Do not include the declaration under MSVC because it doesn't accept it
+ * ("error C2370: 'mbedtls_psa_get_random' : redefinition; different storage class").
+ * Observed with Visual Studio 2013. A known bug apparently:
+ * https://stackoverflow.com/questions/8146541/duplicate-external-static-declarations-not-allowed-in-visual-studio
*/
-#if defined(MBEDTLS_CTR_DRBG_C)
-static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_ctr_drbg_random;
-#elif defined(MBEDTLS_HMAC_DRBG_C)
-static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_hmac_drbg_random;
+#if !defined(_MSC_VER)
+static mbedtls_f_rng_t *const mbedtls_psa_get_random;
#endif
/** The maximum number of bytes that mbedtls_psa_get_random() is expected to
@@ -167,6 +154,9 @@
*/
/* psa_crypto.c sets this variable to a pointer to the DRBG state in the
* global PSA crypto state. */
+/* The type `mbedtls_psa_drbg_context_t` is defined in
+ * include/mbedtls/psa_util.h so that `mbedtls_psa_random_state` can be
+ * declared there and be visible to application code. */
extern mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state;
/** A pointer to the PSA DRBG state.
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 876555d..4875b78 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -703,7 +703,7 @@
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_key_id_t key_slot = 0; /* invalid key slot */
#endif
-#endif
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
char *p, *q;
const int *list;
#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
@@ -760,10 +760,10 @@
ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
goto exit;
}
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
mbedtls_test_enable_insecure_external_rng( );
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
if( argc == 0 )
{
@@ -1536,7 +1536,8 @@
mbedtls_printf( "\n . Seeding the random number generator..." );
fflush( stdout );
- if( rng_seed( &rng, opt.reproducible, pers ) != 0 )
+ ret = rng_seed( &rng, opt.reproducible, pers );
+ if( ret != 0 )
goto exit;
mbedtls_printf( " ok\n" );
@@ -1881,7 +1882,7 @@
#else
fprintf( stderr, "Warning: reproducible option used without constant time\n" );
#endif
-#endif
+#endif /* MBEDTLS_HAVE_TIME */
}
mbedtls_ssl_conf_rng( &conf, rng_get, &rng );
mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
@@ -1927,7 +1928,7 @@
goto exit;
}
}
-#endif
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
#if defined(MBEDTLS_ECP_C)
if( opt.curves != NULL &&
@@ -2999,19 +3000,7 @@
#if defined(MBEDTLS_USE_PSA_CRYPTO)
psa_destroy_key( key_slot );
#endif
-#endif
- mbedtls_ssl_session_free( &saved_session );
- mbedtls_ssl_free( &ssl );
- mbedtls_ssl_config_free( &conf );
- rng_free( &rng );
- if( session_data != NULL )
- mbedtls_platform_zeroize( session_data, session_data_len );
- mbedtls_free( session_data );
-#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
- if( context_buf != NULL )
- mbedtls_platform_zeroize( context_buf, context_buf_len );
- mbedtls_free( context_buf );
-#endif
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) && \
defined(MBEDTLS_USE_PSA_CRYPTO)
@@ -3034,12 +3023,25 @@
#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED &&
MBEDTLS_USE_PSA_CRYPTO */
+ mbedtls_ssl_session_free( &saved_session );
+ mbedtls_ssl_free( &ssl );
+ mbedtls_ssl_config_free( &conf );
+ rng_free( &rng );
+ if( session_data != NULL )
+ mbedtls_platform_zeroize( session_data, session_data_len );
+ mbedtls_free( session_data );
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+ if( context_buf != NULL )
+ mbedtls_platform_zeroize( context_buf, context_buf_len );
+ mbedtls_free( context_buf );
+#endif
+
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_memory_buffer_alloc_status();
#endif
mbedtls_memory_buffer_alloc_free();
-#endif
+#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
#if defined(_WIN32)
if( opt.query_config_mode == DFL_QUERY_CONFIG_MODE )
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 57c053c..08317b5 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -1412,10 +1412,10 @@
ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
goto exit;
}
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
mbedtls_test_enable_insecure_external_rng( );
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
#if !defined(_WIN32)
/* Abort cleanly on SIGTERM and SIGINT */
@@ -2295,7 +2295,8 @@
mbedtls_printf( "\n . Seeding the random number generator..." );
fflush( stdout );
- if( rng_seed( &rng, opt.reproducible, pers ) != 0 )
+ ret = rng_seed( &rng, opt.reproducible, pers );
+ if( ret != 0 )
goto exit;
mbedtls_printf( " ok\n" );
@@ -2683,7 +2684,7 @@
#else
fprintf( stderr, "Warning: reproducible option used without constant time\n" );
#endif
-#endif
+#endif /* MBEDTLS_HAVE_TIME */
}
mbedtls_ssl_conf_rng( &conf, rng_get, &rng );
mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
@@ -4002,7 +4003,7 @@
mbedtls_memory_buffer_alloc_status();
#endif
mbedtls_memory_buffer_alloc_free();
-#endif
+#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
if( opt.query_config_mode == DFL_QUERY_CONFIG_MODE )
{
diff --git a/programs/ssl/ssl_test_lib.c b/programs/ssl/ssl_test_lib.c
index 46cea14..6636e9e 100644
--- a/programs/ssl/ssl_test_lib.c
+++ b/programs/ssl/ssl_test_lib.c
@@ -46,6 +46,7 @@
return 0x5af2a056;
}
+#if !defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
static int dummy_entropy( void *data, unsigned char *output, size_t len )
{
size_t i;
@@ -60,9 +61,15 @@
}
return( ret );
}
+#endif
void rng_init( rng_context_t *rng )
{
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+ (void) rng;
+ psa_crypto_init( );
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+
#if defined(MBEDTLS_CTR_DRBG_C)
mbedtls_ctr_drbg_init( &rng->drbg );
#elif defined(MBEDTLS_HMAC_DRBG_C)
@@ -72,10 +79,31 @@
#endif
mbedtls_entropy_init( &rng->entropy );
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
}
int rng_seed( rng_context_t *rng, int reproducible, const char *pers )
{
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ if( reproducible )
+ {
+ mbedtls_fprintf( stderr,
+ "MBEDTLS_USE_PSA_CRYPTO does not support reproducible mode.\n" );
+ return( -1 );
+ }
+#endif
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+ /* The PSA crypto RNG does its own seeding. */
+ (void) rng;
+ (void) pers;
+ if( reproducible )
+ {
+ mbedtls_fprintf( stderr,
+ "The PSA RNG does not support reproducible mode.\n" );
+ return( -1 );
+ }
+ return( 0 );
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
int ( *f_entropy )( void *, unsigned char *, size_t ) =
( reproducible ? dummy_entropy : mbedtls_entropy_func );
@@ -100,9 +128,9 @@
f_entropy, &rng->entropy,
(const unsigned char *) pers,
strlen( pers ) );
-#else
+#else /* !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_HMAC_DRBG_C) */
#error "No DRBG available"
-#endif
+#endif /* !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_HMAC_DRBG_C) */
if( ret != 0 )
{
@@ -110,12 +138,21 @@
(unsigned int) -ret );
return( ret );
}
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
return( 0 );
}
void rng_free( rng_context_t *rng )
{
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+ (void) rng;
+ /* Deinitialize the PSA crypto subsystem. This deactivates all PSA APIs.
+ * This is ok because none of our applications try to do any crypto after
+ * deinitializing the RNG. */
+ mbedtls_psa_crypto_free( );
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+
#if defined(MBEDTLS_CTR_DRBG_C)
mbedtls_ctr_drbg_free( &rng->drbg );
#elif defined(MBEDTLS_HMAC_DRBG_C)
@@ -125,11 +162,18 @@
#endif
mbedtls_entropy_free( &rng->entropy );
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
}
int rng_get( void *p_rng, unsigned char *output, size_t output_len )
{
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+ (void) p_rng;
+ return( mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+ output, output_len ) );
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
rng_context_t *rng = p_rng;
+
#if defined(MBEDTLS_CTR_DRBG_C)
return( mbedtls_ctr_drbg_random( &rng->drbg, output, output_len ) );
#elif defined(MBEDTLS_HMAC_DRBG_C)
@@ -137,6 +181,8 @@
#else
#error "No DRBG available"
#endif
+
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
}
#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
diff --git a/programs/ssl/ssl_test_lib.h b/programs/ssl/ssl_test_lib.h
index 861e82a..04ba158 100644
--- a/programs/ssl/ssl_test_lib.h
+++ b/programs/ssl/ssl_test_lib.h
@@ -43,23 +43,33 @@
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
#endif
-#if !defined(MBEDTLS_ENTROPY_C) || \
- !defined(MBEDTLS_NET_C) || \
+#undef HAVE_RNG
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) && \
+ ( defined(MBEDTLS_USE_PSA_CRYPTO) || \
+ defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG) )
+#define HAVE_RNG
+#elif defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C)
+#define HAVE_RNG
+#elif defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_HMAC_DRBG_C) && \
+ ( defined(MBEDTLS_SHA256_C) || defined(MBEDTLS_SHA512_C) )
+#define HAVE_RNG
+#endif
+
+#if !defined(MBEDTLS_NET_C) || \
!defined(MBEDTLS_SSL_TLS_C) || \
defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER)
#define MBEDTLS_SSL_TEST_IMPOSSIBLE \
- "MBEDTLS_ENTROPY_C and/or " \
"MBEDTLS_NET_C and/or " \
"MBEDTLS_SSL_TLS_C not defined, " \
"and/or MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER defined.\n"
-#elif !( defined(MBEDTLS_CTR_DRBG_C) || \
- defined(MBEDTLS_HMAC_DRBG_C) && ( defined(MBEDTLS_SHA256_C) || \
- defined(MBEDTLS_SHA512_C) ) )
-#define MBEDTLS_SSL_TEST_IMPOSSIBLE \
- "Neither MBEDTLS_CTR_DRBG_C, nor MBEDTLS_HMAC_DRBG_C and a supported hash defined.\n"
+#elif !defined(HAVE_RNG)
+#define MBEDTLS_SSL_TEST_IMPOSSIBLE \
+ "No random generator is available.\n"
#else
#undef MBEDTLS_SSL_TEST_IMPOSSIBLE
+#undef HAVE_RNG
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -76,7 +86,7 @@
#include "mbedtls/timing.h"
#include "mbedtls/base64.h"
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
#include "psa/crypto.h"
#include "mbedtls/psa_util.h"
#endif
@@ -130,10 +140,38 @@
mbedtls_time_t dummy_constant_time( mbedtls_time_t* time );
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+/* If MBEDTLS_TEST_USE_PSA_CRYPTO_RNG is defined, the SSL test programs will use
+ * mbedtls_psa_get_random() rather than entropy+DRBG as a random generator.
+ *
+ * The constraints are:
+ * - Without the entropy module, the PSA RNG is the only option.
+ * - Without at least one of the DRBG modules, the PSA RNG is the only option.
+ * - The PSA RNG does not support explicit seeding, so it is incompatible with
+ * the reproducible mode used by test programs.
+ * - For good overall test coverage, there should be at least one configuration
+ * where the test programs use the PSA RNG while the PSA RNG is itself based
+ * on entropy+DRBG, and at least one configuration where the test programs
+ * do not use the PSA RNG even though it's there.
+ *
+ * A simple choice that meets the constraints is to use the PSA RNG whenever
+ * MBEDTLS_USE_PSA_CRYPTO is enabled. There's no real technical reason the
+ * choice to use the PSA RNG in the test programs and the choice to use
+ * PSA crypto when TLS code needs crypto have to be tied together, but it
+ * happens to be a good match. It's also a good match from an application
+ * perspective: either PSA is preferred for TLS (both for crypto and for
+ * random generation) or it isn't.
+ */
+#define MBEDTLS_TEST_USE_PSA_CRYPTO_RNG
+#endif
+
/** A context for random number generation (RNG).
*/
typedef struct
{
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+ unsigned char dummy;
+#else /* MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
mbedtls_entropy_context entropy;
#if defined(MBEDTLS_CTR_DRBG_C)
mbedtls_ctr_drbg_context drbg;
@@ -142,6 +180,7 @@
#else
#error "No DRBG available"
#endif
+#endif /* MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
} rng_context_t;
/** Initialize the RNG.
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 13f0593..cefc5c9 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -153,6 +153,7 @@
add_test_suite(psa_crypto_se_driver_hal_mocks)
add_test_suite(psa_crypto_slot_management)
add_test_suite(psa_its)
+add_test_suite(random)
add_test_suite(rsa)
add_test_suite(shax)
add_test_suite(ssl)
diff --git a/tests/include/test/helpers.h b/tests/include/test/helpers.h
index 8b56d3a..928c636 100644
--- a/tests/include/test/helpers.h
+++ b/tests/include/test/helpers.h
@@ -256,7 +256,7 @@
void mbedtls_test_param_failed_reset_state( void );
#endif /* MBEDTLS_CHECK_PARAMS */
-#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
#include "test/fake_external_rng_for_test.h"
#endif
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 1036a7c..43742fd 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -922,37 +922,61 @@
if_build_succeeded tests/context-info.sh
}
-component_test_no_ctr_drbg () {
- msg "build: Full minus CTR_DRBG"
+component_test_no_ctr_drbg_classic () {
+ msg "build: Full minus CTR_DRBG, classic crypto in TLS"
scripts/config.py full
scripts/config.py unset MBEDTLS_CTR_DRBG_C
+ scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
make
- msg "test: Full minus CTR_DRBG - main suites"
+ msg "test: Full minus CTR_DRBG, classic crypto - main suites"
make test
# In this configuration, the TLS test programs use HMAC_DRBG.
# The SSL tests are slow, so run a small subset, just enough to get
# confidence that the SSL code copes with HMAC_DRBG.
- msg "test: Full minus CTR_DRBG - ssl-opt.sh (subset)"
+ msg "test: Full minus CTR_DRBG, classic crypto - ssl-opt.sh (subset)"
if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private.*delay=\|tickets enabled on server'
- msg "test: Full minus CTR_DRBG - compat.sh (subset)"
+ msg "test: Full minus CTR_DRBG, classic crypto - compat.sh (subset)"
if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA PSK' -V NO -p OpenSSL
}
-component_test_no_hmac_drbg () {
- msg "build: Full minus HMAC_DRBG"
+component_test_no_ctr_drbg_use_psa () {
+ msg "build: Full minus CTR_DRBG, PSA crypto in TLS"
scripts/config.py full
- scripts/config.py unset MBEDTLS_HMAC_DRBG_C
- scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
+ scripts/config.py unset MBEDTLS_CTR_DRBG_C
+ scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
make
- msg "test: Full minus HMAC_DRBG - main suites"
+ msg "test: Full minus CTR_DRBG, USE_PSA_CRYPTO - main suites"
+ make test
+
+ # In this configuration, the TLS test programs use HMAC_DRBG.
+ # The SSL tests are slow, so run a small subset, just enough to get
+ # confidence that the SSL code copes with HMAC_DRBG.
+ msg "test: Full minus CTR_DRBG, USE_PSA_CRYPTO - ssl-opt.sh (subset)"
+ if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private.*delay=\|tickets enabled on server'
+
+ msg "test: Full minus CTR_DRBG, USE_PSA_CRYPTO - compat.sh (subset)"
+ if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA PSK' -V NO -p OpenSSL
+}
+
+component_test_no_hmac_drbg_classic () {
+ msg "build: Full minus HMAC_DRBG, classic crypto in TLS"
+ scripts/config.py full
+ scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+ scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
+ scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
+
+ CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+ make
+
+ msg "test: Full minus HMAC_DRBG, classic crypto - main suites"
make test
# Normally our ECDSA implementation uses deterministic ECDSA. But since
@@ -960,29 +984,84 @@
# instead.
# Test SSL with non-deterministic ECDSA. Only test features that
# might be affected by how ECDSA signature is performed.
- msg "test: Full minus HMAC_DRBG - ssl-opt.sh (subset)"
+ msg "test: Full minus HMAC_DRBG, classic crypto - ssl-opt.sh (subset)"
if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private: sign'
# To save time, only test one protocol version, since this part of
# the protocol is identical in (D)TLS up to 1.2.
- msg "test: Full minus HMAC_DRBG - compat.sh (ECDSA)"
+ msg "test: Full minus HMAC_DRBG, classic crypto - compat.sh (ECDSA)"
if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA'
}
-component_test_psa_external_rng_no_drbg () {
- msg "build: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG"
+component_test_no_hmac_drbg_use_psa () {
+ msg "build: Full minus HMAC_DRBG, PSA crypto in TLS"
+ scripts/config.py full
+ scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+ scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
+ scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
+
+ CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+ make
+
+ msg "test: Full minus HMAC_DRBG, USE_PSA_CRYPTO - main suites"
+ make test
+
+ # Normally our ECDSA implementation uses deterministic ECDSA. But since
+ # HMAC_DRBG is disabled in this configuration, randomized ECDSA is used
+ # instead.
+ # Test SSL with non-deterministic ECDSA. Only test features that
+ # might be affected by how ECDSA signature is performed.
+ msg "test: Full minus HMAC_DRBG, USE_PSA_CRYPTO - ssl-opt.sh (subset)"
+ if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private: sign'
+
+ # To save time, only test one protocol version, since this part of
+ # the protocol is identical in (D)TLS up to 1.2.
+ msg "test: Full minus HMAC_DRBG, USE_PSA_CRYPTO - compat.sh (ECDSA)"
+ if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA'
+}
+
+component_test_psa_external_rng_no_drbg_classic () {
+ msg "build: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, classic crypto in TLS"
+ scripts/config.py full
+ scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
+ scripts/config.py set MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+ scripts/config.py unset MBEDTLS_ENTROPY_C
+ scripts/config.py unset MBEDTLS_ENTROPY_NV_SEED
+ scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT
+ scripts/config.py unset MBEDTLS_CTR_DRBG_C
+ scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+ scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
+ scripts/config.py set MBEDTLS_ECP_NO_INTERNAL_RNG
+ # When MBEDTLS_USE_PSA_CRYPTO is disabled and there is no DRBG,
+ # the SSL test programs don't have an RNG and can't work. Explicitly
+ # make them use the PSA RNG with -DMBEDTLS_TEST_USE_PSA_CRYPTO_RNG.
+ make CFLAGS="$ASAN_CFLAGS -O2 -DMBEDTLS_TEST_USE_PSA_CRYPTO_RNG" LDFLAGS="$ASAN_CFLAGS"
+
+ msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, classic crypto - main suites"
+ make test
+
+ msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, classic crypto - ssl-opt.sh (subset)"
+ if_build_succeeded tests/ssl-opt.sh -f 'Default'
+}
+
+component_test_psa_external_rng_no_drbg_use_psa () {
+ msg "build: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, PSA crypto in TLS"
scripts/config.py full
scripts/config.py set MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+ scripts/config.py unset MBEDTLS_ENTROPY_C
+ scripts/config.py unset MBEDTLS_ENTROPY_NV_SEED
+ scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT
scripts/config.py unset MBEDTLS_CTR_DRBG_C
scripts/config.py unset MBEDTLS_HMAC_DRBG_C
scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
scripts/config.py set MBEDTLS_ECP_NO_INTERNAL_RNG
make CFLAGS="$ASAN_CFLAGS -O2" LDFLAGS="$ASAN_CFLAGS"
- msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG"
+ msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, PSA crypto - main suites"
make test
- # no SSL tests as they all depend on having a DRBG
+ msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, PSA crypto - ssl-opt.sh (subset)"
+ if_build_succeeded tests/ssl-opt.sh -f 'Default\|opaque'
}
component_test_psa_external_rng_use_psa_crypto () {
diff --git a/tests/suites/test_suite_random.data b/tests/suites/test_suite_random.data
new file mode 100644
index 0000000..c23d922
--- /dev/null
+++ b/tests/suites/test_suite_random.data
@@ -0,0 +1,55 @@
+Generate random twice with CTR_DRBG
+random_twice_with_ctr_drbg:
+
+Generate random twice with HMAC_DRBG(SHA-1)
+depends_on:MBEDTLS_SHA1_C
+random_twice_with_hmac_drbg:MBEDTLS_MD_SHA1
+
+Generate random twice with HMAC_DRBG(SHA-256)
+depends_on:MBEDTLS_SHA256_C
+random_twice_with_hmac_drbg:MBEDTLS_MD_SHA256
+
+Generate random twice with HMAC_DRBG(SHA-512)
+depends_on:MBEDTLS_SHA512_C
+random_twice_with_hmac_drbg:MBEDTLS_MD_SHA512
+
+Generate random twice with PSA classic wrapper
+random_twice_with_psa_from_classic:
+
+Generate random twice with PSA API
+random_twice_with_psa_from_psa:
+
+# This bad-usage test case currently crashes in the default configuration
+# because CTR_DRBG crashes when given an unseeded context. This is arguably
+# a good thing because it prevents misuse of mbedtls_psa_get_random().
+#PSA classic wrapper: PSA not active
+#mbedtls_psa_get_random_no_init:
+
+PSA classic wrapper: 0 bytes
+mbedtls_psa_get_random_length:0
+
+PSA classic wrapper: 1 byte
+mbedtls_psa_get_random_length:1
+
+PSA classic wrapper: 256 bytes
+mbedtls_psa_get_random_length:256
+
+# An external RNG is supposed to handle arbitrary request lengths. Test it
+# with something larger than any RNG call made by Mbed TLS itself expects.
+# CTR_DRBG and HMAC_DRBG have their own maximum request lengths which may
+# be lower than the value chosen here and are tested separately.
+PSA classic wrapper: external RNG large
+depends_on:MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+mbedtls_psa_get_random_length:1024
+
+PSA classic wrapper: CTR_DRBG max
+depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG:MBEDTLS_CTR_DRBG_C
+mbedtls_psa_get_random_length:MBEDTLS_CTR_DRBG_MAX_REQUEST
+
+PSA classic wrapper: HMAC_DRBG max
+depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG:!MBEDTLS_CTR_DRBG_C:MBEDTLS_HMAC_DRBG_C
+mbedtls_psa_get_random_length:MBEDTLS_HMAC_DRBG_MAX_REQUEST
+
+PSA classic wrapper: ECDSA signature (SECP256R1)
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+mbedtls_psa_get_random_ecdsa_sign:MBEDTLS_ECP_DP_SECP256R1
diff --git a/tests/suites/test_suite_random.function b/tests/suites/test_suite_random.function
new file mode 100644
index 0000000..37fa36e
--- /dev/null
+++ b/tests/suites/test_suite_random.function
@@ -0,0 +1,202 @@
+/* BEGIN_HEADER */
+
+/* Test random generation as a whole. */
+
+#include "mbedtls/bignum.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/ecdsa.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/hmac_drbg.h"
+#include "mbedtls/psa_util.h"
+#include "psa/crypto.h"
+
+/* How many bytes to generate in each test case for repeated generation.
+ * This must be high enough that the probability of generating the same
+ * output twice is infinitesimal, but low enough that random generators
+ * are willing to deliver that much. */
+#define OUTPUT_SIZE 32
+
+/* END_HEADER */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_C:!MBEDTLS_TEST_NULL_ENTROPY:MBEDTLS_CTR_DRBG_C */
+void random_twice_with_ctr_drbg( )
+{
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context drbg;
+ unsigned char output1[OUTPUT_SIZE];
+ unsigned char output2[OUTPUT_SIZE];
+
+ /* First round */
+ mbedtls_entropy_init( &entropy );
+ mbedtls_ctr_drbg_init( &drbg );
+ TEST_EQUAL( 0, mbedtls_ctr_drbg_seed( &drbg,
+ mbedtls_entropy_func, &entropy,
+ NULL, 0 ) );
+ TEST_EQUAL( 0, mbedtls_ctr_drbg_random( &drbg,
+ output1, sizeof( output1 ) ) );
+ mbedtls_ctr_drbg_free( &drbg );
+ mbedtls_entropy_free( &entropy );
+
+ /* Second round */
+ mbedtls_entropy_init( &entropy );
+ mbedtls_ctr_drbg_init( &drbg );
+ TEST_EQUAL( 0, mbedtls_ctr_drbg_seed( &drbg,
+ mbedtls_entropy_func, &entropy,
+ NULL, 0 ) );
+ TEST_EQUAL( 0, mbedtls_ctr_drbg_random( &drbg,
+ output2, sizeof( output2 ) ) );
+ mbedtls_ctr_drbg_free( &drbg );
+ mbedtls_entropy_free( &entropy );
+
+ /* The two rounds must generate different random data. */
+ TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 );
+
+exit:
+ mbedtls_ctr_drbg_free( &drbg );
+ mbedtls_entropy_free( &entropy );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_C:!MBEDTLS_TEST_NULL_ENTROPY:MBEDTLS_HMAC_DRBG_C */
+void random_twice_with_hmac_drbg( int md_type )
+{
+ mbedtls_entropy_context entropy;
+ mbedtls_hmac_drbg_context drbg;
+ unsigned char output1[OUTPUT_SIZE];
+ unsigned char output2[OUTPUT_SIZE];
+ const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_type );
+
+ /* First round */
+ mbedtls_entropy_init( &entropy );
+ mbedtls_hmac_drbg_init( &drbg );
+ TEST_EQUAL( 0, mbedtls_hmac_drbg_seed( &drbg, md_info,
+ mbedtls_entropy_func, &entropy,
+ NULL, 0 ) );
+ TEST_EQUAL( 0, mbedtls_hmac_drbg_random( &drbg,
+ output1, sizeof( output1 ) ) );
+ mbedtls_hmac_drbg_free( &drbg );
+ mbedtls_entropy_free( &entropy );
+
+ /* Second round */
+ mbedtls_entropy_init( &entropy );
+ mbedtls_hmac_drbg_init( &drbg );
+ TEST_EQUAL( 0, mbedtls_hmac_drbg_seed( &drbg, md_info,
+ mbedtls_entropy_func, &entropy,
+ NULL, 0 ) );
+ TEST_EQUAL( 0, mbedtls_hmac_drbg_random( &drbg,
+ output2, sizeof( output2 ) ) );
+ mbedtls_hmac_drbg_free( &drbg );
+ mbedtls_entropy_free( &entropy );
+
+ /* The two rounds must generate different random data. */
+ TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 );
+
+exit:
+ mbedtls_hmac_drbg_free( &drbg );
+ mbedtls_entropy_free( &entropy );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:!MBEDTLS_TEST_NULL_ENTROPY:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void random_twice_with_psa_from_classic( )
+{
+ unsigned char output1[OUTPUT_SIZE];
+ unsigned char output2[OUTPUT_SIZE];
+
+ /* First round */
+ PSA_ASSERT( psa_crypto_init( ) );
+ TEST_EQUAL( 0, mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+ output1, sizeof( output1 ) ) );
+ PSA_DONE( );
+
+ /* Second round */
+ PSA_ASSERT( psa_crypto_init( ) );
+ TEST_EQUAL( 0, mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+ output2, sizeof( output2 ) ) );
+ PSA_DONE( );
+
+ /* The two rounds must generate different random data. */
+ TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 );
+
+exit:
+ PSA_DONE( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:!MBEDTLS_TEST_NULL_ENTROPY:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void random_twice_with_psa_from_psa( )
+{
+ unsigned char output1[OUTPUT_SIZE];
+ unsigned char output2[OUTPUT_SIZE];
+
+ /* First round */
+ PSA_ASSERT( psa_crypto_init( ) );
+ PSA_ASSERT( psa_generate_random( output1, sizeof( output1 ) ) );
+ PSA_DONE( );
+
+ /* Second round */
+ PSA_ASSERT( psa_crypto_init( ) );
+ PSA_ASSERT( psa_generate_random( output2, sizeof( output2 ) ) );
+ PSA_DONE( );
+
+ /* The two rounds must generate different random data. */
+ TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 );
+
+exit:
+ PSA_DONE( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C */
+void mbedtls_psa_get_random_no_init( )
+{
+ unsigned char output[1];
+
+ TEST_ASSERT( mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+ output, sizeof( output ) ) != 0 );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C */
+void mbedtls_psa_get_random_length( int n )
+{
+ unsigned char *output = NULL;
+
+ PSA_ASSERT( psa_crypto_init( ) );
+ ASSERT_ALLOC( output, n );
+
+ TEST_EQUAL( 0, mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+ output, n ) );
+exit:
+ mbedtls_free( output );
+ PSA_DONE( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_ECDSA_C */
+void mbedtls_psa_get_random_ecdsa_sign( int curve )
+{
+ mbedtls_ecp_group grp;
+ mbedtls_mpi d, r, s;
+ unsigned char buf[] = "This is not a hash.";
+
+ mbedtls_ecp_group_init( &grp );
+ mbedtls_mpi_init( &d );
+ mbedtls_mpi_init( &r );
+ mbedtls_mpi_init( &s );
+
+ TEST_EQUAL( 0, mbedtls_mpi_lset( &d, 123456789 ) );
+ TEST_EQUAL( 0, mbedtls_ecp_group_load( &grp, curve ) );
+ PSA_ASSERT( psa_crypto_init( ) );
+ TEST_EQUAL( 0, mbedtls_ecdsa_sign( &grp, &r, &s, &d,
+ buf, sizeof( buf ),
+ mbedtls_psa_get_random,
+ MBEDTLS_PSA_RANDOM_STATE ) );
+exit:
+ mbedtls_mpi_free( &d );
+ mbedtls_mpi_free( &r );
+ mbedtls_mpi_free( &s );
+ mbedtls_ecp_group_free( &grp );
+ PSA_DONE( );
+}
+/* END_CASE */