mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2026-09-15 22:59:56 +00:00
New function psa_random_reseed()
Explicit reseed of the PSA random generator. Signed-off-by: Gilles Peskine <[email protected]>
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
Features
|
||||||
|
* Applications can use the new function psa_random_reseed() to
|
||||||
|
request an immediate reseed of the PSA random generator.
|
||||||
@@ -453,7 +453,7 @@ psa_status_t mbedtls_psa_inject_entropy(const uint8_t *seed,
|
|||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
|
|
||||||
/** \defgroup psa_external_rng External random generator
|
/** \defgroup psa_rng Random generator
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -502,6 +502,85 @@ psa_status_t mbedtls_psa_external_get_random(
|
|||||||
uint8_t *output, size_t output_size, size_t *output_length);
|
uint8_t *output, size_t output_size, size_t *output_length);
|
||||||
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||||
|
|
||||||
|
/** Force a reseed of the PSA random generator.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* The main reason to call this function is in scenarios where the process
|
||||||
|
* state is cloned (i.e. duplicated) while the random generator is active.
|
||||||
|
* In such scenarios, you must call this function in every clone of
|
||||||
|
* the original process before performing any cryptographic operation
|
||||||
|
* other than ones that do not use randomness (e.g. hash calculation,
|
||||||
|
* signature verification). For example:
|
||||||
|
*
|
||||||
|
* - If the process is part of a live virtual machine that is cloned,
|
||||||
|
* call this function after cloning so that the new instance has a
|
||||||
|
* distinct random generator state.
|
||||||
|
* - If the process is part of a hibernated image that may be resumed
|
||||||
|
* multiple times, call this function after resuming so that each
|
||||||
|
* resumed instance has a distinct random generator state.
|
||||||
|
* - If the process is cloned through the fork() system call, the
|
||||||
|
* library will detect it in most circumstances, so you generally do
|
||||||
|
* not need to call this function. This detection is based on a
|
||||||
|
* process ID (PID) change. You need to call this function in at least
|
||||||
|
* the parent or the child process in cases where the library might not
|
||||||
|
* observe a process ID change, such as:
|
||||||
|
* - If the child forks another process before invoking the random
|
||||||
|
* generator, but after the original process has died. In this case,
|
||||||
|
* it is rare but possible for the grandchild to have the same PID
|
||||||
|
* as the original process.
|
||||||
|
* - When using the Linux clone() system call with the `CLONE_NEWPID`
|
||||||
|
* flag to put the child process in its own PID namespace, and the
|
||||||
|
* original process has PID 1.
|
||||||
|
* - When the child is moved to a new or existing PID namespace before
|
||||||
|
* any call to the PSA random generator, and the PID in the child's
|
||||||
|
* namespace might match the PID of the original process.
|
||||||
|
* - When using the Linux clone3() system call with a `set_tid` array
|
||||||
|
* to force the PID of the new process.
|
||||||
|
*
|
||||||
|
* An additional consideration applies in configurations where there is no
|
||||||
|
* actual entropy source, only a nonvolatile seed (i.e.
|
||||||
|
* #MBEDTLS_ENTROPY_NV_SEED is enabled, #MBEDTLS_NO_PLATFORM_ENTROPY is
|
||||||
|
* enabled and #MBEDTLS_ENTROPY_HARDWARE_ALT is disabled).
|
||||||
|
* In such configurations, simply calling psa_random_reseed() in multiple
|
||||||
|
* cloned processes would result in the same random generator state in
|
||||||
|
* all the clones. To avoid this, in such configurations, you must pass
|
||||||
|
* a unique \p perso string in every clone.
|
||||||
|
*
|
||||||
|
* \note This function has no effect when the compilation option
|
||||||
|
* #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled.
|
||||||
|
*
|
||||||
|
* \note In client-server builds, this function may not be available
|
||||||
|
* from clients, since the decision to reseed is generally based
|
||||||
|
* on the server state.
|
||||||
|
*
|
||||||
|
* \param[in] perso A personalization string, i.e. a byte string to
|
||||||
|
* inject into the random generator state in addition
|
||||||
|
* to entropy obtained from the normal source(s).
|
||||||
|
* In most cases, it is fine for \c perso to be
|
||||||
|
* empty. The main use case for a personalization
|
||||||
|
* string is when the random generator state is cloned,
|
||||||
|
* as described above, and there is no actual entropy
|
||||||
|
* source.
|
||||||
|
* \param perso_size Length of \c perso in bytes.
|
||||||
|
*
|
||||||
|
* \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.
|
||||||
|
* \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||||
|
* The entropy source failed.
|
||||||
|
*/
|
||||||
|
psa_status_t psa_random_reseed(const uint8_t *perso, size_t perso_size);
|
||||||
|
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
/** \defgroup psa_builtin_keys Built-in keys
|
/** \defgroup psa_builtin_keys Built-in keys
|
||||||
|
|||||||
@@ -8001,6 +8001,28 @@ static psa_status_t mbedtls_psa_random_seed(mbedtls_psa_random_context_t *rng)
|
|||||||
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
psa_status_t psa_random_reseed(const uint8_t *perso, size_t perso_size)
|
||||||
|
{
|
||||||
|
GUARD_MODULE_INITIALIZED;
|
||||||
|
#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
|
||||||
|
(void) perso;
|
||||||
|
(void) perso_size;
|
||||||
|
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) */
|
||||||
|
int ret = mbedtls_psa_drbg_reseed(&global_data.rng.drbg,
|
||||||
|
perso, perso_size);
|
||||||
|
#if defined(MBEDTLS_THREADING_C)
|
||||||
|
mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex);
|
||||||
|
#endif /* defined(MBEDTLS_THREADING_C) */
|
||||||
|
return mbedtls_to_psa_error(ret);
|
||||||
|
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||||
|
}
|
||||||
|
|
||||||
psa_status_t psa_generate_random(uint8_t *output_external,
|
psa_status_t psa_generate_random(uint8_t *output_external,
|
||||||
size_t output_size)
|
size_t output_size)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -44,6 +44,27 @@ entropy_from_nv_seed:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:PSA_ERROR_INSUFFICIENT_ENTRO
|
|||||||
NV seed only: just enough
|
NV seed only: just enough
|
||||||
entropy_from_nv_seed:ENTROPY_MIN_NV_SEED_SIZE:PSA_SUCCESS
|
entropy_from_nv_seed:ENTROPY_MIN_NV_SEED_SIZE:PSA_SUCCESS
|
||||||
|
|
||||||
|
Explicit reseed: basic tests
|
||||||
|
reseed_basic:
|
||||||
|
|
||||||
|
Explicit reseed: entropy consumption
|
||||||
|
reseed_consumption:
|
||||||
|
|
||||||
|
Explicit reseed: uniqueness tests (0 = 0)
|
||||||
|
reseed_uniqueness:"":""
|
||||||
|
|
||||||
|
Explicit reseed: uniqueness tests (0 != 5)
|
||||||
|
reseed_uniqueness:"":"706572736f"
|
||||||
|
|
||||||
|
Explicit reseed: uniqueness tests (5 = 5)
|
||||||
|
reseed_uniqueness:"706572736f":"706572736f"
|
||||||
|
|
||||||
|
Explicit reseed: uniqueness tests (5 != 5)
|
||||||
|
reseed_uniqueness:"706572736f":"706572736e"
|
||||||
|
|
||||||
|
Explicit reseed: uniqueness tests (5 != 10)
|
||||||
|
reseed_uniqueness:"706572736f":"706572736f706572736f"
|
||||||
|
|
||||||
PSA external RNG failure: generate random and key
|
PSA external RNG failure: generate random and key
|
||||||
external_rng_failure_generate:
|
external_rng_failure_generate:
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ typedef struct {
|
|||||||
size_t *length_sequence;
|
size_t *length_sequence;
|
||||||
size_t step;
|
size_t step;
|
||||||
} fake_entropy_state_t;
|
} fake_entropy_state_t;
|
||||||
|
|
||||||
static int fake_entropy_source(void *state_arg,
|
static int fake_entropy_source(void *state_arg,
|
||||||
unsigned char *output, size_t len,
|
unsigned char *output, size_t len,
|
||||||
size_t *olen)
|
size_t *olen)
|
||||||
@@ -113,6 +114,39 @@ static void custom_entropy_init(mbedtls_entropy_context *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t fake_entropy_lengths[] = {
|
||||||
|
MBEDTLS_ENTROPY_BLOCK_SIZE,
|
||||||
|
MBEDTLS_ENTROPY_BLOCK_SIZE,
|
||||||
|
MBEDTLS_ENTROPY_BLOCK_SIZE,
|
||||||
|
MBEDTLS_ENTROPY_BLOCK_SIZE,
|
||||||
|
MBEDTLS_ENTROPY_BLOCK_SIZE,
|
||||||
|
MBEDTLS_ENTROPY_BLOCK_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Initialize PSA with a deterministic RNG seed.
|
||||||
|
*
|
||||||
|
* \param max_entropy_queries Maximum number of queries to the entropy source.
|
||||||
|
* Once this number has been reached, the
|
||||||
|
* entropy source will fail.
|
||||||
|
*/
|
||||||
|
static int psa_init_deterministic(size_t max_entropy_queries)
|
||||||
|
{
|
||||||
|
TEST_LE_U(max_entropy_queries, ARRAY_LENGTH(fake_entropy_lengths));
|
||||||
|
|
||||||
|
fake_entropy_state.threshold = MBEDTLS_ENTROPY_BLOCK_SIZE;
|
||||||
|
fake_entropy_state.step = 0;
|
||||||
|
fake_entropy_state.max_steps = max_entropy_queries;
|
||||||
|
fake_entropy_state.length_sequence = fake_entropy_lengths;
|
||||||
|
|
||||||
|
custom_entropy_sources_mask = ENTROPY_SOURCE_FAKE;
|
||||||
|
PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
|
||||||
|
custom_entropy_init, mbedtls_entropy_free));
|
||||||
|
PSA_INIT();
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
|
#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
|
||||||
|
|
||||||
/* Calculating the minimum allowed entropy size in bytes */
|
/* Calculating the minimum allowed entropy size in bytes */
|
||||||
@@ -285,6 +319,130 @@ exit:
|
|||||||
}
|
}
|
||||||
/* END_CASE */
|
/* END_CASE */
|
||||||
|
|
||||||
|
/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||||
|
void reseed_basic()
|
||||||
|
{
|
||||||
|
uint8_t random[10];
|
||||||
|
const uint8_t perso[5] = { 'p', 'e', 'r', 's', 'o' };
|
||||||
|
|
||||||
|
TEST_EQUAL(psa_random_reseed(NULL, 0), PSA_ERROR_BAD_STATE);
|
||||||
|
TEST_EQUAL(psa_generate_random(random, sizeof(random)), PSA_ERROR_BAD_STATE);
|
||||||
|
|
||||||
|
PSA_INIT();
|
||||||
|
|
||||||
|
PSA_ASSERT(psa_random_reseed(NULL, 0));
|
||||||
|
PSA_ASSERT(psa_random_reseed(perso, sizeof(perso)));
|
||||||
|
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_generate_random(random, sizeof(random)), PSA_ERROR_BAD_STATE);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
PSA_DONE();
|
||||||
|
}
|
||||||
|
/* END_CASE */
|
||||||
|
|
||||||
|
/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||||
|
/* Check that reseeding consumes entropy.
|
||||||
|
*
|
||||||
|
* For simplicity, this test function assumes that the DRBG has prediction
|
||||||
|
* resistance turned off, so the few RNG queries in this function don't
|
||||||
|
* trigger a reseed.
|
||||||
|
*/
|
||||||
|
void reseed_consumption()
|
||||||
|
{
|
||||||
|
uint8_t random[10] = { 0 };
|
||||||
|
|
||||||
|
if (!psa_init_deterministic(3)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Explicit reseed, consumes 1 entropy block, 1 remaining */
|
||||||
|
PSA_ASSERT(psa_random_reseed(NULL, 0));
|
||||||
|
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||||
|
|
||||||
|
/* Explicit reseed, consumes 1 entropy block, 0 remaining */
|
||||||
|
PSA_ASSERT(psa_random_reseed(NULL, 0));
|
||||||
|
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||||
|
|
||||||
|
/* All entropy blocks are now consumed */
|
||||||
|
TEST_EQUAL(psa_random_reseed(NULL, 0), PSA_ERROR_INSUFFICIENT_ENTROPY);
|
||||||
|
|
||||||
|
/* The random generator is still fine after failing to reseed
|
||||||
|
* explicitly. Should it be? */
|
||||||
|
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||||
|
|
||||||
|
exit:
|
||||||
|
PSA_DONE();
|
||||||
|
}
|
||||||
|
/* END_CASE */
|
||||||
|
|
||||||
|
/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||||
|
void reseed_uniqueness(data_t *perso1, data_t *perso2)
|
||||||
|
{
|
||||||
|
uint8_t random0[10] = { 0 };
|
||||||
|
uint8_t random1[10] = { 0 };
|
||||||
|
uint8_t random2[10] = { 0 };
|
||||||
|
uint8_t random_again[10] = { 0 };
|
||||||
|
|
||||||
|
/* Reference: no reseed */
|
||||||
|
if (!psa_init_deterministic(3)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
PSA_ASSERT(psa_generate_random(random0, sizeof(random0)));
|
||||||
|
mbedtls_psa_crypto_free();
|
||||||
|
|
||||||
|
/* Reference: no reseed, again */
|
||||||
|
if (!psa_init_deterministic(3)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
PSA_ASSERT(psa_generate_random(random_again, sizeof(random_again)));
|
||||||
|
mbedtls_psa_crypto_free();
|
||||||
|
TEST_MEMORY_COMPARE(random0, sizeof(random0),
|
||||||
|
random_again, sizeof(random_again));
|
||||||
|
|
||||||
|
/* Reseed with a personalization string */
|
||||||
|
if (!psa_init_deterministic(3)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
PSA_ASSERT(psa_random_reseed(perso1->x, perso1->len));
|
||||||
|
PSA_ASSERT(psa_generate_random(random1, sizeof(random1)));
|
||||||
|
mbedtls_psa_crypto_free();
|
||||||
|
TEST_ASSERT(memcmp(random0, random1, sizeof(random1)) != 0);
|
||||||
|
|
||||||
|
/* Reseed with a personalization string (same or different) */
|
||||||
|
if (!psa_init_deterministic(3)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
PSA_ASSERT(psa_random_reseed(perso2->x, perso2->len));
|
||||||
|
PSA_ASSERT(psa_generate_random(random2, sizeof(random2)));
|
||||||
|
mbedtls_psa_crypto_free();
|
||||||
|
if (perso1->len == perso2->len &&
|
||||||
|
memcmp(perso1->x, perso2->x, perso1->len) == 0) {
|
||||||
|
TEST_MEMORY_COMPARE(random1, sizeof(random1),
|
||||||
|
random2, sizeof(random2));
|
||||||
|
} else {
|
||||||
|
TEST_ASSERT(memcmp(random1, random2, sizeof(random2)) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reseed twice */
|
||||||
|
if (!psa_init_deterministic(3)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
PSA_ASSERT(psa_random_reseed(perso1->x, perso1->len));
|
||||||
|
PSA_ASSERT(psa_random_reseed(perso1->x, perso1->len));
|
||||||
|
PSA_ASSERT(psa_generate_random(random2, sizeof(random2)));
|
||||||
|
mbedtls_psa_crypto_free();
|
||||||
|
TEST_ASSERT(memcmp(random0, random2, sizeof(random2)) != 0);
|
||||||
|
TEST_ASSERT(memcmp(random1, random2, sizeof(random2)) != 0);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
PSA_DONE();
|
||||||
|
}
|
||||||
|
/* END_CASE */
|
||||||
|
|
||||||
/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||||
void external_rng_failure_generate()
|
void external_rng_failure_generate()
|
||||||
{
|
{
|
||||||
@@ -300,6 +458,8 @@ void external_rng_failure_generate()
|
|||||||
PSA_ASSERT(psa_generate_key(&attributes, &key));
|
PSA_ASSERT(psa_generate_key(&attributes, &key));
|
||||||
PSA_ASSERT(psa_destroy_key(key));
|
PSA_ASSERT(psa_destroy_key(key));
|
||||||
|
|
||||||
|
TEST_EQUAL(psa_random_reseed(NULL, 0), PSA_ERROR_NOT_SUPPORTED);
|
||||||
|
|
||||||
mbedtls_test_disable_insecure_external_rng();
|
mbedtls_test_disable_insecure_external_rng();
|
||||||
TEST_EQUAL(PSA_ERROR_INSUFFICIENT_ENTROPY,
|
TEST_EQUAL(PSA_ERROR_INSUFFICIENT_ENTROPY,
|
||||||
psa_generate_random(output, sizeof(output)));
|
psa_generate_random(output, sizeof(output)));
|
||||||
|
|||||||
Reference in New Issue
Block a user