Expose mbedtls_psa_get_random()
Expose whatever RNG the PSA subsystem uses to applications using the
mbedtls_xxx API.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/ChangeLog.d/mbedtls_psa_get_random.txt b/ChangeLog.d/mbedtls_psa_get_random.txt
new file mode 100644
index 0000000..9abbfff
--- /dev/null
+++ b/ChangeLog.d/mbedtls_psa_get_random.txt
@@ -0,0 +1,8 @@
+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 documentatio of mbedtls_psa_external_get_random() for details.
+ * Applications using PSA crypto can now use its random generator in the
+ mbedtls_xxx API. 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 d8a32c5..b481401 100644
--- a/include/mbedtls/psa_util.h
+++ b/include/mbedtls/psa_util.h
@@ -419,4 +419,88 @@
#endif /* MBEDTLS_USE_PSA_CRYPTO */
+/* Expose whatever RNG the PSA subsystem uses to applications using the
+ * mbedtls_xxx API. The declarations here need to be consistent with the
+ * implementation in library/psa_crypto_random_impl.h. */
+#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. It must be used in combination
+ * with the random generator state #MBEDTLS_PSA_RANDOM_STATE.
+ *
+ * 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_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/psa_crypto_random_impl.h b/library/psa_crypto_random_impl.h
index 1232186..4fa54a9 100644
--- a/library/psa_crypto_random_impl.h
+++ b/library/psa_crypto_random_impl.h
@@ -1,6 +1,9 @@
/** \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.
*/
/*
* Copyright The Mbed TLS Contributors
diff --git a/tests/suites/test_suite_random.data b/tests/suites/test_suite_random.data
index 47f2ec7..d781f2b 100644
--- a/tests/suites/test_suite_random.data
+++ b/tests/suites/test_suite_random.data
@@ -13,5 +13,39 @@
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
+
+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
index 744daf5..c532c8a 100644
--- a/tests/suites/test_suite_random.function
+++ b/tests/suites/test_suite_random.function
@@ -2,9 +2,12 @@
/* 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.
@@ -95,6 +98,32 @@
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:!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_PSA_CRYPTO_EXTERNAL_RNG */
void random_twice_with_psa_from_psa( )
{
unsigned char output1[OUTPUT_SIZE];
@@ -117,3 +146,57 @@
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 */