diff --git a/ChangeLog.d/rng-cloning.txt b/ChangeLog.d/rng-cloning.txt index 3c2d63db1a..1539b50889 100644 --- a/ChangeLog.d/rng-cloning.txt +++ b/ChangeLog.d/rng-cloning.txt @@ -1,3 +1,4 @@ Features - * Applications can use the new function psa_random_reseed() to - request an immediate reseed of the PSA random generator. + * Applications can use the new functions psa_random_reseed() to + request an immediate reseed of the PSA random generator, or + psa_random_deplete() to force a reseed on the next random generator call. diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index 7d0b01ca4f..ec8b126d32 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -581,6 +581,34 @@ psa_status_t mbedtls_psa_external_get_random( */ psa_status_t psa_random_reseed(const uint8_t *perso, size_t perso_size); +/** Force a reseed of the PSA random generator the next time it is used. + * + * The entropy source(s) are the ones configured at compile time. + * + * The random generator is always seeded automatically before use, and + * it is reseeded as needed based on the configured policy, so most + * applications do not need to call this function. + * + * This function has a similar purpose as psa_random_reseed(), + * but the reseed will happen the next time the random generator is used. + * This advantage of this function is that it does not fail unless the + * system is an unintended state, so it can be used in contexts where + * propagating errors is difficult. + * + * \note This function has no effect when #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + * is enabled. + * + * \retval #PSA_SUCCESS + * The reseed succeeded. + * \retval #PSA_ERROR_BAD_STATE + * The PSA random generator is not active. + * \retval #PSA_ERROR_NOT_SUPPORTED + * PSA uses an external random generator because the compilation + * option #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled. This + * configuration does not support explicit reseeding. + */ +psa_status_t psa_random_deplete(void); + /**@}*/ /** \defgroup psa_builtin_keys Built-in keys diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 7951268186..cae7a2bd7d 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -8023,6 +8023,25 @@ psa_status_t psa_random_reseed(const uint8_t *perso, size_t perso_size) #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ } +psa_status_t psa_random_deplete(void) +{ + GUARD_MODULE_INITIALIZED; +#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + return PSA_ERROR_NOT_SUPPORTED; +#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +#if defined(MBEDTLS_THREADING_C) + if (mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex) != 0) { + return PSA_ERROR_SERVICE_FAILURE; + } +#endif /* defined(MBEDTLS_THREADING_C) */ + mbedtls_psa_drbg_deplete(&global_data.rng.drbg); +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex); +#endif /* defined(MBEDTLS_THREADING_C) */ + return PSA_SUCCESS; +#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +} + psa_status_t psa_generate_random(uint8_t *output_external, size_t output_size) { diff --git a/library/psa_crypto_random_impl.h b/library/psa_crypto_random_impl.h index f342845e46..0078df7453 100644 --- a/library/psa_crypto_random_impl.h +++ b/library/psa_crypto_random_impl.h @@ -145,6 +145,18 @@ static inline int mbedtls_psa_drbg_reseed(mbedtls_psa_drbg_context_t *drbg_ctx, #endif } +/** Deplete the PSA DRBG, i.e. cause it to reseed the next time it is used. + * + * \note This function is not thread-safe. + * + * \param drbg_ctx The DRBG context to deplete. + * It must be active. + */ +static inline void mbedtls_psa_drbg_deplete(mbedtls_psa_drbg_context_t *drbg_ctx) +{ + drbg_ctx->reseed_counter = drbg_ctx->reseed_interval; +} + #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ #endif /* PSA_CRYPTO_RANDOM_IMPL_H */ diff --git a/tests/suites/test_suite_psa_crypto_entropy.data b/tests/suites/test_suite_psa_crypto_entropy.data index e5f7243388..3f71f4490e 100644 --- a/tests/suites/test_suite_psa_crypto_entropy.data +++ b/tests/suites/test_suite_psa_crypto_entropy.data @@ -50,6 +50,9 @@ reseed_basic: Explicit reseed: entropy consumption reseed_consumption: +Deplete: entropy consumption +deplete_consumption: + Explicit reseed: uniqueness tests (0 = 0) reseed_uniqueness:"":"" diff --git a/tests/suites/test_suite_psa_crypto_entropy.function b/tests/suites/test_suite_psa_crypto_entropy.function index 696ee0b7de..71c6e90d2f 100644 --- a/tests/suites/test_suite_psa_crypto_entropy.function +++ b/tests/suites/test_suite_psa_crypto_entropy.function @@ -326,6 +326,7 @@ void reseed_basic() const uint8_t perso[5] = { 'p', 'e', 'r', 's', 'o' }; TEST_EQUAL(psa_random_reseed(NULL, 0), PSA_ERROR_BAD_STATE); + TEST_EQUAL(psa_random_deplete(), PSA_ERROR_BAD_STATE); TEST_EQUAL(psa_generate_random(random, sizeof(random)), PSA_ERROR_BAD_STATE); PSA_INIT(); @@ -334,9 +335,13 @@ void reseed_basic() PSA_ASSERT(psa_random_reseed(perso, sizeof(perso))); PSA_ASSERT(psa_generate_random(random, sizeof(random))); + PSA_ASSERT(psa_random_deplete()); + PSA_ASSERT(psa_generate_random(random, sizeof(random))); + mbedtls_psa_crypto_free(); TEST_EQUAL(psa_random_reseed(NULL, 0), PSA_ERROR_BAD_STATE); + TEST_EQUAL(psa_random_deplete(), PSA_ERROR_BAD_STATE); TEST_EQUAL(psa_generate_random(random, sizeof(random)), PSA_ERROR_BAD_STATE); exit: @@ -389,6 +394,30 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ +void deplete_consumption() +{ + uint8_t random[10] = { 0 }; + + if (!psa_init_deterministic(4)) { + goto exit; + } + + /* Depending on the DRBG parameters, the initial seeding may + * consume entropy once or twice. Reset to 1 to keep things simple. */ + fake_entropy_state.step = 1; + + PSA_ASSERT(psa_random_deplete()); + TEST_EQUAL(fake_entropy_state.step, 1); + + PSA_ASSERT(psa_generate_random(random, sizeof(random))); + TEST_LE_U(2, fake_entropy_state.step); + +exit: + PSA_DONE(); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */ void reseed_uniqueness(data_t *perso1, data_t *perso2) { @@ -472,6 +501,7 @@ void external_rng_failure_generate() PSA_ASSERT(psa_destroy_key(key)); TEST_EQUAL(psa_random_reseed(NULL, 0), PSA_ERROR_NOT_SUPPORTED); + TEST_EQUAL(psa_random_deplete(), PSA_ERROR_NOT_SUPPORTED); mbedtls_test_disable_insecure_external_rng(); TEST_EQUAL(PSA_ERROR_INSUFFICIENT_ENTROPY,