diff --git a/ChangeLog.d/mbedtls_psa_get_random.txt b/ChangeLog.d/mbedtls_psa_get_random.txt new file mode 100644 index 000000000..9abbfff78 --- /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 d8a32c59e..b4814012e 100644 --- a/include/mbedtls/psa_util.h +++ b/include/mbedtls/psa_util.h @@ -419,4 +419,88 @@ static inline int mbedtls_psa_tls_ecpoint_to_psa_ec( unsigned char const *src, #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 1232186c9..4fa54a9fa 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 47f2ec7eb..d781f2ba5 100644 --- a/tests/suites/test_suite_random.data +++ b/tests/suites/test_suite_random.data @@ -13,5 +13,39 @@ 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 + +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 744daf59c..c532c8a3b 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. @@ -94,6 +97,32 @@ exit: } /* 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( ) { @@ -117,3 +146,57 @@ 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 */