mirror of
https://github.com/espressif/mbedtls.git
synced 2026-08-12 06:27:48 +00:00
Merge pull request #1497 from gilles-peskine-arm/psa-rng-reseed-3.6
Backport 3.6: API to reseed the PSA RNG
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
Features
|
||||
* 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.
|
||||
* Applications can call psa_random_set_prediction_resistance() to toggle
|
||||
prediction resistance in the PSA random generator.
|
||||
|
||||
Security
|
||||
* Applications running in environments where the application state is
|
||||
cloned (for example due to resuming a frozen system state multiple
|
||||
times, or due to cloning a virtual machine image) should arrange to
|
||||
reseed the random generator using one of the new functions
|
||||
psa_random_reseed() or psa_random_deplete(). CVE-2026-25835
|
||||
|
||||
@@ -48,6 +48,49 @@
|
||||
#endif
|
||||
#endif /* _MINGW32__ || (_MSC_VER && (_MSC_VER <= 1900)) */
|
||||
|
||||
/* The number of "true" entropy sources (excluding NV seed).
|
||||
* This must be consistent with mbedtls_entropy_init() in entropy.c.
|
||||
*/
|
||||
/* Define auxiliary macros, because in standard C, defined(xxx) is only
|
||||
* allowed directly on an #if or #elif line, not in recursive expansion. */
|
||||
#if defined(MBEDTLS_NO_PLATFORM_ENTROPY)
|
||||
#define MBEDTLS_PLATFORM_ENTROPY_ENABLED 0
|
||||
#else
|
||||
#define MBEDTLS_PLATFORM_ENTROPY_ENABLED 1
|
||||
#endif
|
||||
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
|
||||
#define MBEDTLS_ENTROPY_HARDWARE_ALT_DEFINED 1
|
||||
#else
|
||||
#define MBEDTLS_ENTROPY_HARDWARE_ALT_DEFINED 0
|
||||
#endif
|
||||
|
||||
#define MBEDTLS_ENTROPY_TRUE_SOURCES ( \
|
||||
MBEDTLS_ENTROPY_HARDWARE_ALT_DEFINED + \
|
||||
MBEDTLS_PLATFORM_ENTROPY_ENABLED + \
|
||||
0)
|
||||
|
||||
/* Whether there is at least one entropy source for the entropy module.
|
||||
*
|
||||
* Note that when MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled, the entropy
|
||||
* module is unused and the configuration will typically not include any
|
||||
* entropy source, so this macro will typically remain undefined.
|
||||
*/
|
||||
#if defined(MBEDTLS_ENTROPY_NV_SEED)
|
||||
#define MBEDTLS_ENTROPY_HAVE_SOURCES (MBEDTLS_ENTROPY_TRUE_SOURCES + 1)
|
||||
#elif MBEDTLS_ENTROPY_TRUE_SOURCES != 0
|
||||
#define MBEDTLS_ENTROPY_HAVE_SOURCES MBEDTLS_ENTROPY_TRUE_SOURCES
|
||||
#else
|
||||
#undef MBEDTLS_ENTROPY_HAVE_SOURCES
|
||||
#endif
|
||||
|
||||
/* Test function dependencies can only check with defined(),
|
||||
* not other preprocessor expressions. */
|
||||
#if MBEDTLS_ENTROPY_TRUE_SOURCES > 0
|
||||
#define MBEDTLS_ENTROPY_HAVE_TRUE_SOURCES
|
||||
#else
|
||||
#undef MBEDTLS_ENTROPY_HAVE_TRUE_SOURCES
|
||||
#endif
|
||||
|
||||
/* If MBEDTLS_PSA_CRYPTO_C is defined, make sure MBEDTLS_PSA_CRYPTO_CLIENT
|
||||
* is defined as well to include all PSA code.
|
||||
*/
|
||||
|
||||
@@ -186,8 +186,7 @@ typedef struct mbedtls_ctr_drbg_context {
|
||||
unsigned char MBEDTLS_PRIVATE(counter)[16]; /*!< The counter (V). */
|
||||
int MBEDTLS_PRIVATE(reseed_counter); /*!< The reseed counter.
|
||||
* This is the number of requests that have
|
||||
* been made since the last (re)seeding,
|
||||
* minus one.
|
||||
* been made since the last (re)seeding.
|
||||
* Before the initial seeding, this field
|
||||
* contains the amount of entropy in bytes
|
||||
* to use as a nonce for the initial seeding,
|
||||
|
||||
+150
-1
@@ -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,155 @@ psa_status_t mbedtls_psa_external_get_random(
|
||||
uint8_t *output, size_t output_size, size_t *output_length);
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
|
||||
/** Force an immediate 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
|
||||
* that uses randomness. (Note that any operation that uses a private or
|
||||
* secret key may use randomness internally even if the result is not
|
||||
* randomized, but hashing and signature verification are ok.) 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
|
||||
* child process should call this function before using the random
|
||||
* generator.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* \note If the entropy source fails, the random generator remains usable:
|
||||
* subsequent calls to generate random data will succeed until
|
||||
* the random generator itself decides to reseed. If you want to
|
||||
* force a reseed, either treat the failure as a fatal error,
|
||||
* or call psa_random_deplete() instead of this function (or in
|
||||
* addition).
|
||||
*
|
||||
* \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);
|
||||
|
||||
/** 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.
|
||||
* The advantage of this function is that it does not fail unless the
|
||||
* system is in 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.
|
||||
*
|
||||
* \note If prediction resistance is enabled (either explicitly, or because
|
||||
* the reseed interval is set to 1), calling this function is
|
||||
* unnecessary since the random generator will always reseed anyway.
|
||||
*
|
||||
* \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);
|
||||
|
||||
/** Enable or disable prediction resistance in the PSA random generator.
|
||||
*
|
||||
* When prediction resistance is enabled, the random generator
|
||||
* injects extra entropy before each request regardless of its size.
|
||||
* As a consequence, a temporary compromise of the random generator
|
||||
* state does not, by itself, compromise future steps.
|
||||
* Furthermore, duplicating the random generator state (because the
|
||||
* running application instance is cloned) is safe since it will
|
||||
* not lead to identical random generator outputs in the clones.
|
||||
*
|
||||
* When prediction resistance is disabled, the random generator injects
|
||||
* extra entropy periodically only as determined by
|
||||
* #MBEDTLS_CTR_DRBG_RESEED_INTERVAL if #MBEDTLS_CTR_DRBG_C
|
||||
* is enabled, or #MBEDTLS_HMAC_DRBG_RESEED_INTERVAL otherwise.
|
||||
*
|
||||
* Prediction resistance is disabled by default, although setting
|
||||
* #MBEDTLS_CTR_DRBG_RESEED_INTERVAL or #MBEDTLS_HMAC_DRBG_RESEED_INTERVAL
|
||||
* to \c 1 satisfies the prediction resistance property even when the
|
||||
* option is disabled.
|
||||
*
|
||||
* \note This function has no effect when #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
|
||||
* is enabled.
|
||||
*
|
||||
* \note Prediction resistance cannot be enabled when the only entropy source
|
||||
* is a nonvolatile seed, since prediction resistance is effectively
|
||||
* impossible to achieve without actual entropy.
|
||||
*
|
||||
* \param enabled \c 1 to enable prediction resistance.
|
||||
* \c 0 to disable prediction resistance.
|
||||
*
|
||||
* \retval #PSA_SUCCESS
|
||||
* The PSA random generator is active, and prediction resistance
|
||||
* has been changed to the desired option.
|
||||
* \retval #PSA_ERROR_BAD_STATE
|
||||
* The PSA random generator is not active.
|
||||
* \retval #PSA_ERROR_INVALID_ARGUMENT
|
||||
* \p enabled is not valid.
|
||||
* \retval #PSA_ERROR_NOT_SUPPORTED
|
||||
* PSA uses an external random generator because the compilation
|
||||
* option #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled.
|
||||
* Or, the random generator only has a nonvolatile seed but no entropy
|
||||
* source, and prediction resistance has been requested.
|
||||
*/
|
||||
psa_status_t psa_random_set_prediction_resistance(unsigned enabled);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** \defgroup psa_builtin_keys Built-in keys
|
||||
|
||||
@@ -76,6 +76,7 @@ set(src_crypto
|
||||
psa_crypto_mac.c
|
||||
psa_crypto_pake.c
|
||||
psa_crypto_rsa.c
|
||||
psa_crypto_random.c
|
||||
psa_crypto_se.c
|
||||
psa_crypto_slot_management.c
|
||||
psa_crypto_storage.c
|
||||
|
||||
@@ -167,6 +167,7 @@ OBJS_CRYPTO= \
|
||||
psa_crypto_hash.o \
|
||||
psa_crypto_mac.o \
|
||||
psa_crypto_pake.o \
|
||||
psa_crypto_random.o \
|
||||
psa_crypto_rsa.o \
|
||||
psa_crypto_se.o \
|
||||
psa_crypto_slot_management.o \
|
||||
|
||||
+2
-2
@@ -494,7 +494,7 @@ static int mbedtls_ctr_drbg_reseed_internal(mbedtls_ctr_drbg_context *ctx,
|
||||
if ((ret = ctr_drbg_update_internal(ctx, seed)) != 0) {
|
||||
goto exit;
|
||||
}
|
||||
ctx->reseed_counter = 1;
|
||||
ctx->reseed_counter = 0;
|
||||
|
||||
exit:
|
||||
mbedtls_platform_zeroize(seed, sizeof(seed));
|
||||
@@ -629,7 +629,7 @@ int mbedtls_ctr_drbg_random_with_add(void *p_rng,
|
||||
|
||||
memset(locals.add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN);
|
||||
|
||||
if (ctx->reseed_counter > ctx->reseed_interval ||
|
||||
if (ctx->reseed_counter >= ctx->reseed_interval ||
|
||||
ctx->prediction_resistance) {
|
||||
if ((ret = mbedtls_ctr_drbg_reseed(ctx, additional, add_len)) != 0) {
|
||||
return ret;
|
||||
|
||||
+2
-2
@@ -196,7 +196,7 @@ static int hmac_drbg_reseed_core(mbedtls_hmac_drbg_context *ctx,
|
||||
}
|
||||
|
||||
/* 3. Reset reseed_counter */
|
||||
ctx->reseed_counter = 1;
|
||||
ctx->reseed_counter = 0;
|
||||
|
||||
exit:
|
||||
/* 4. Done */
|
||||
@@ -326,7 +326,7 @@ int mbedtls_hmac_drbg_random_with_add(void *p_rng,
|
||||
/* 1. (aka VII and IX) Check reseed counter and PR */
|
||||
if (ctx->f_entropy != NULL && /* For no-reseeding instances */
|
||||
(ctx->prediction_resistance == MBEDTLS_HMAC_DRBG_PR_ON ||
|
||||
ctx->reseed_counter > ctx->reseed_interval)) {
|
||||
ctx->reseed_counter >= ctx->reseed_interval)) {
|
||||
if ((ret = mbedtls_hmac_drbg_reseed(ctx, additional, add_len)) != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
+82
-46
@@ -37,6 +37,7 @@
|
||||
* stored keys. */
|
||||
#include "psa_crypto_storage.h"
|
||||
|
||||
#include "psa_crypto_random.h"
|
||||
#include "psa_crypto_random_impl.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -4412,25 +4413,8 @@ static psa_status_t psa_generate_random_internal(uint8_t *output,
|
||||
return PSA_SUCCESS;
|
||||
|
||||
#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
|
||||
while (output_size > 0) {
|
||||
int ret = MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
|
||||
size_t request_size =
|
||||
(output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ?
|
||||
MBEDTLS_PSA_RANDOM_MAX_REQUEST :
|
||||
output_size);
|
||||
#if defined(MBEDTLS_CTR_DRBG_C)
|
||||
ret = mbedtls_ctr_drbg_random(&global_data.rng.drbg, output, request_size);
|
||||
#elif defined(MBEDTLS_HMAC_DRBG_C)
|
||||
ret = mbedtls_hmac_drbg_random(&global_data.rng.drbg, output, request_size);
|
||||
#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */
|
||||
if (ret != 0) {
|
||||
return mbedtls_to_psa_error(ret);
|
||||
}
|
||||
output_size -= request_size;
|
||||
output += request_size;
|
||||
}
|
||||
return PSA_SUCCESS;
|
||||
return psa_random_internal_generate(&global_data.rng,
|
||||
output, output_size);
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
}
|
||||
|
||||
@@ -7984,28 +7968,7 @@ static void mbedtls_psa_random_init(mbedtls_psa_random_context_t *rng)
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
|
||||
memset(rng, 0, sizeof(*rng));
|
||||
#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
|
||||
/* Set default configuration if
|
||||
* mbedtls_psa_crypto_configure_entropy_sources() hasn't been called. */
|
||||
if (rng->entropy_init == NULL) {
|
||||
rng->entropy_init = mbedtls_entropy_init;
|
||||
}
|
||||
if (rng->entropy_free == NULL) {
|
||||
rng->entropy_free = mbedtls_entropy_free;
|
||||
}
|
||||
|
||||
rng->entropy_init(&rng->entropy);
|
||||
#if defined(MBEDTLS_PSA_INJECT_ENTROPY) && \
|
||||
defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES)
|
||||
/* The PSA entropy injection feature depends on using NV seed as an entropy
|
||||
* source. Add NV seed as an entropy source for PSA entropy injection. */
|
||||
mbedtls_entropy_add_source(&rng->entropy,
|
||||
mbedtls_nv_seed_poll, NULL,
|
||||
MBEDTLS_ENTROPY_BLOCK_SIZE,
|
||||
MBEDTLS_ENTROPY_SOURCE_STRONG);
|
||||
#endif
|
||||
|
||||
mbedtls_psa_drbg_init(&rng->drbg);
|
||||
psa_random_internal_init(rng);
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
}
|
||||
|
||||
@@ -8019,8 +7982,7 @@ static void mbedtls_psa_random_free(mbedtls_psa_random_context_t *rng)
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
|
||||
memset(rng, 0, sizeof(*rng));
|
||||
#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
mbedtls_psa_drbg_free(&rng->drbg);
|
||||
rng->entropy_free(&rng->entropy);
|
||||
psa_random_internal_free(rng);
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
}
|
||||
|
||||
@@ -8033,13 +7995,87 @@ static psa_status_t mbedtls_psa_random_seed(mbedtls_psa_random_context_t *rng)
|
||||
(void) rng;
|
||||
return PSA_SUCCESS;
|
||||
#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
const unsigned char drbg_seed[] = "PSA";
|
||||
int ret = mbedtls_psa_drbg_seed(&rng->drbg, &rng->entropy,
|
||||
drbg_seed, sizeof(drbg_seed) - 1);
|
||||
return psa_random_internal_seed(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_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_random_set_prediction_resistance(unsigned enabled)
|
||||
{
|
||||
GUARD_MODULE_INITIALIZED;
|
||||
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
|
||||
(void) enabled;
|
||||
return PSA_ERROR_NOT_SUPPORTED;
|
||||
#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
|
||||
if (enabled != 0 && enabled != 1) {
|
||||
return PSA_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
#if MBEDTLS_ENTROPY_TRUE_SOURCES > 0
|
||||
#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_set_prediction_resistance(&global_data.rng.drbg, enabled);
|
||||
#if defined(MBEDTLS_THREADING_C)
|
||||
mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex);
|
||||
#endif /* defined(MBEDTLS_THREADING_C) */
|
||||
return PSA_SUCCESS;
|
||||
|
||||
#else /* MBEDTLS_ENTROPY_TRUE_SOURCES > 0 */
|
||||
if (enabled) {
|
||||
return PSA_ERROR_NOT_SUPPORTED;
|
||||
} else {
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* MBEDTLS_ENTROPY_TRUE_SOURCES > 0 */
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
}
|
||||
|
||||
psa_status_t psa_generate_random(uint8_t *output_external,
|
||||
size_t output_size)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* PSA crypto random generator.
|
||||
*/
|
||||
/*
|
||||
* Copyright The Mbed TLS Contributors
|
||||
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if defined(MBEDTLS_PSA_CRYPTO_C) && !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
|
||||
|
||||
#include "psa_crypto_core.h"
|
||||
#include "psa_crypto_random.h"
|
||||
#include "psa_crypto_random_impl.h"
|
||||
|
||||
#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
|
||||
#include "entropy_poll.h"
|
||||
#endif
|
||||
|
||||
void psa_random_internal_init(mbedtls_psa_random_context_t *rng)
|
||||
{
|
||||
/* Set default configuration if
|
||||
* mbedtls_psa_crypto_configure_entropy_sources() hasn't been called. */
|
||||
if (rng->entropy_init == NULL) {
|
||||
rng->entropy_init = mbedtls_entropy_init;
|
||||
}
|
||||
if (rng->entropy_free == NULL) {
|
||||
rng->entropy_free = mbedtls_entropy_free;
|
||||
}
|
||||
|
||||
rng->entropy_init(&rng->entropy);
|
||||
#if defined(MBEDTLS_PSA_INJECT_ENTROPY) && \
|
||||
defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES)
|
||||
/* The PSA entropy injection feature depends on using NV seed as an entropy
|
||||
* source. Add NV seed as an entropy source for PSA entropy injection. */
|
||||
mbedtls_entropy_add_source(&rng->entropy,
|
||||
mbedtls_nv_seed_poll, NULL,
|
||||
MBEDTLS_ENTROPY_BLOCK_SIZE,
|
||||
MBEDTLS_ENTROPY_SOURCE_STRONG);
|
||||
#endif
|
||||
|
||||
mbedtls_psa_drbg_init(&rng->drbg);
|
||||
}
|
||||
|
||||
void psa_random_internal_free(mbedtls_psa_random_context_t *rng)
|
||||
{
|
||||
mbedtls_psa_drbg_free(&rng->drbg);
|
||||
rng->entropy_free(&rng->entropy);
|
||||
}
|
||||
psa_status_t psa_random_internal_seed(mbedtls_psa_random_context_t *rng)
|
||||
{
|
||||
const unsigned char drbg_seed[] = "PSA";
|
||||
int ret = mbedtls_psa_drbg_seed(&rng->drbg, &rng->entropy,
|
||||
drbg_seed, sizeof(drbg_seed) - 1);
|
||||
return mbedtls_to_psa_error(ret);
|
||||
}
|
||||
|
||||
psa_status_t psa_random_internal_generate(
|
||||
mbedtls_psa_random_context_t *rng,
|
||||
uint8_t *output, size_t output_size)
|
||||
{
|
||||
while (output_size > 0) {
|
||||
size_t request_size =
|
||||
(output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ?
|
||||
MBEDTLS_PSA_RANDOM_MAX_REQUEST :
|
||||
output_size);
|
||||
#if defined(MBEDTLS_CTR_DRBG_C)
|
||||
int ret = mbedtls_ctr_drbg_random(&rng->drbg, output, request_size);
|
||||
#elif defined(MBEDTLS_HMAC_DRBG_C)
|
||||
int ret = mbedtls_hmac_drbg_random(&rng->drbg, output, request_size);
|
||||
#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */
|
||||
if (ret != 0) {
|
||||
return mbedtls_to_psa_error(ret);
|
||||
}
|
||||
output_size -= request_size;
|
||||
output += request_size;
|
||||
}
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_C && !MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* PSA crypto random generator internal functions.
|
||||
*/
|
||||
/*
|
||||
* Copyright The Mbed TLS Contributors
|
||||
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef PSA_CRYPTO_RANDOM_H
|
||||
#define PSA_CRYPTO_RANDOM_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
|
||||
|
||||
#include <psa/crypto.h>
|
||||
#include "psa_crypto_random_impl.h"
|
||||
|
||||
/** Initialize the PSA random generator.
|
||||
*
|
||||
* \param[out] rng The random generator context to initialize.
|
||||
*/
|
||||
void psa_random_internal_init(mbedtls_psa_random_context_t *rng);
|
||||
|
||||
/** Deinitialize the PSA random generator.
|
||||
*
|
||||
* \param[in,out] rng The random generator context to deinitialize.
|
||||
*/
|
||||
void psa_random_internal_free(mbedtls_psa_random_context_t *rng);
|
||||
|
||||
/** Seed the PSA random generator.
|
||||
*
|
||||
* \note This function is not thread-safe.
|
||||
*
|
||||
* \param[in,out] rng The random generator context to seed.
|
||||
*
|
||||
* \retval #PSA_SUCCESS
|
||||
* Success.
|
||||
* \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
* The entropy source failed.
|
||||
*/
|
||||
psa_status_t psa_random_internal_seed(mbedtls_psa_random_context_t *rng);
|
||||
|
||||
/**
|
||||
* \brief Generate random bytes. Like psa_generate_random(), but for use
|
||||
* inside the library.
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* \warning This function **can** fail! Callers MUST check the return status
|
||||
* and MUST NOT use the content of the output buffer if the return
|
||||
* status is not #PSA_SUCCESS.
|
||||
*
|
||||
* \param[in,out] rng The random generator context to seed.
|
||||
* \param[out] output Output buffer for the generated data.
|
||||
* \param output_size Number of bytes to generate and output.
|
||||
*
|
||||
* \retval #PSA_SUCCESS
|
||||
* Success.
|
||||
* \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
* The random generator needed to reseed, and the entropy
|
||||
* source failed.
|
||||
* \retval #PSA_ERROR_HARDWARE_FAILURE
|
||||
* A hardware accelerator failed.
|
||||
*/
|
||||
psa_status_t psa_random_internal_generate(
|
||||
mbedtls_psa_random_context_t *rng,
|
||||
uint8_t *output, size_t output_size);
|
||||
|
||||
#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
|
||||
|
||||
#endif /* PSA_CRYPTO_RANDOM_H */
|
||||
@@ -100,6 +100,8 @@ static inline void mbedtls_psa_drbg_free(mbedtls_psa_drbg_context_t *p_rng)
|
||||
|
||||
/** Seed the PSA DRBG.
|
||||
*
|
||||
* \param drbg_ctx The DRBG context to seed.
|
||||
* It must be initialized but not active.
|
||||
* \param entropy An entropy context to read the seed from.
|
||||
* \param custom The personalization string.
|
||||
* This can be \c NULL, in which case the personalization
|
||||
@@ -121,6 +123,61 @@ static inline int mbedtls_psa_drbg_seed(mbedtls_psa_drbg_context_t *drbg_ctx,
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Reseed the PSA DRBG.
|
||||
*
|
||||
* \param drbg_ctx The DRBG context to reseed.
|
||||
* It must be active.
|
||||
* \param additional Additional data to inject.
|
||||
* \param len The length of \p additional in bytes.
|
||||
* This can be 0 to simply reseed from the entropy source.
|
||||
*
|
||||
* \return \c 0 on success.
|
||||
* \return An Mbed TLS error code (\c MBEDTLS_ERR_xxx) on failure.
|
||||
*/
|
||||
static inline int mbedtls_psa_drbg_reseed(mbedtls_psa_drbg_context_t *drbg_ctx,
|
||||
const unsigned char *additional,
|
||||
size_t len)
|
||||
{
|
||||
#if defined(MBEDTLS_CTR_DRBG_C)
|
||||
return mbedtls_ctr_drbg_reseed(drbg_ctx, additional, len);
|
||||
#elif defined(MBEDTLS_HMAC_DRBG_C)
|
||||
return mbedtls_hmac_drbg_reseed(drbg_ctx, additional, len);
|
||||
#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;
|
||||
}
|
||||
|
||||
#if MBEDTLS_ENTROPY_TRUE_SOURCES > 0
|
||||
/** Set prediction resistance in the PSA DRBG.
|
||||
*
|
||||
* \note This function is not thread-safe.
|
||||
*
|
||||
* \param drbg_ctx The DRBG context to reconfigure.
|
||||
* It must be active.
|
||||
* \param enabled \c 1 to enable, or \c 0 to disable.
|
||||
*/
|
||||
static inline void mbedtls_psa_drbg_set_prediction_resistance(
|
||||
mbedtls_psa_drbg_context_t *drbg_ctx,
|
||||
unsigned enabled)
|
||||
{
|
||||
#if defined(MBEDTLS_CTR_DRBG_C)
|
||||
mbedtls_ctr_drbg_set_prediction_resistance(drbg_ctx, enabled);
|
||||
#elif defined(MBEDTLS_HMAC_DRBG_C)
|
||||
mbedtls_hmac_drbg_set_prediction_resistance(drbg_ctx, enabled);
|
||||
#endif
|
||||
}
|
||||
#endif /* MBEDTLS_ENTROPY_TRUE_SOURCES > 0 */
|
||||
|
||||
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
|
||||
#endif /* PSA_CRYPTO_RANDOM_IMPL_H */
|
||||
|
||||
@@ -91,7 +91,7 @@ component_check_test_dependencies () {
|
||||
grep 'depends_on' \
|
||||
tests/suites/test_suite_psa*.data tests/suites/test_suite_psa*.function |
|
||||
grep -Eo '!?MBEDTLS_[^: ]*' |
|
||||
grep -v -e MBEDTLS_PSA_ -e MBEDTLS_TEST_ |
|
||||
grep -v -e MBEDTLS_ENTROPY_HAVE_ -e MBEDTLS_PLATFORM -e MBEDTLS_PSA_ -e MBEDTLS_TEST_ |
|
||||
sort -u > $found
|
||||
|
||||
# Expected ones with justification - keep in sorted order by ASCII table!
|
||||
|
||||
@@ -4,6 +4,9 @@ entropy_init_free:0
|
||||
Entropy init-free-init-free
|
||||
entropy_init_free:1
|
||||
|
||||
Entropy: count default sources
|
||||
entropy_count_sources:
|
||||
|
||||
Create NV seed_file
|
||||
nv_seed_file_create:
|
||||
|
||||
|
||||
@@ -171,6 +171,29 @@ void entropy_init_free(int reinit)
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE */
|
||||
void entropy_count_sources()
|
||||
{
|
||||
mbedtls_entropy_context ctx;
|
||||
mbedtls_entropy_init(&ctx);
|
||||
|
||||
#if defined(MBEDTLS_ENTROPY_HAVE_SOURCES)
|
||||
TEST_EQUAL(MBEDTLS_ENTROPY_HAVE_SOURCES, ctx.source_count);
|
||||
#else
|
||||
TEST_EQUAL(0, ctx.source_count);
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_ENTROPY_NV_SEED)
|
||||
TEST_EQUAL(MBEDTLS_ENTROPY_TRUE_SOURCES + 1, ctx.source_count);
|
||||
#else
|
||||
TEST_EQUAL(MBEDTLS_ENTROPY_TRUE_SOURCES, ctx.source_count);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
mbedtls_entropy_free(&ctx);
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
|
||||
void entropy_seed_file(char *path, int ret)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,82 @@
|
||||
Create NV seed file
|
||||
create_nv_seed:
|
||||
|
||||
Custom entropy sources: all standard
|
||||
custom_entropy_sources:0x0000ffff:PSA_SUCCESS
|
||||
|
||||
# MBEDTLS_PSA_INJECT_ENTROPY means that a source of entropy (the seed file)
|
||||
# is effectively always available.
|
||||
Custom entropy sources: none
|
||||
depends_on:!MBEDTLS_PSA_INJECT_ENTROPY
|
||||
custom_entropy_sources:0:PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
|
||||
Fake entropy: never returns anything
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:0:0:0:PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
|
||||
Fake entropy: less than the block size
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:-1:PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
|
||||
Fake entropy: not enough for a nonce
|
||||
depends_on:ENTROPY_NONCE_LEN != 0
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:ENTROPY_NONCE_LEN - 1:-1:-1:-1:PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
|
||||
Fake entropy: one block eventually
|
||||
depends_on:ENTROPY_NONCE_LEN == 0
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:0:0:MBEDTLS_ENTROPY_BLOCK_SIZE:PSA_SUCCESS
|
||||
|
||||
Fake entropy: one block in two steps
|
||||
depends_on:ENTROPY_NONCE_LEN == 0
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:1:-1:-1:PSA_SUCCESS
|
||||
|
||||
Fake entropy: more than one block in two steps
|
||||
depends_on:ENTROPY_NONCE_LEN == 0
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:PSA_SUCCESS
|
||||
|
||||
Fake entropy: two blocks eventually
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:MBEDTLS_ENTROPY_BLOCK_SIZE:0:MBEDTLS_ENTROPY_BLOCK_SIZE:PSA_SUCCESS
|
||||
|
||||
NV seed only: less than minimum
|
||||
entropy_from_nv_seed:MBEDTLS_ENTROPY_MIN_PLATFORM - 1:PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
|
||||
NV seed only: less than one block
|
||||
entropy_from_nv_seed:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
|
||||
NV seed only: just enough
|
||||
entropy_from_nv_seed:ENTROPY_MIN_NV_SEED_SIZE:PSA_SUCCESS
|
||||
|
||||
Explicit reseed: basic tests
|
||||
reseed_basic:
|
||||
|
||||
Explicit reseed: entropy consumption
|
||||
reseed_consumption:
|
||||
|
||||
Deplete: entropy consumption
|
||||
deplete_consumption:
|
||||
|
||||
Prediction resistance: entropy consumption
|
||||
prediction_resistance_consumption:
|
||||
|
||||
Prediction resistance: bad state
|
||||
prediction_resistance_bad_state:
|
||||
|
||||
Prediction resistance: bad arguments
|
||||
prediction_resistance_bad_arguments:
|
||||
|
||||
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
|
||||
external_rng_failure_generate:
|
||||
|
||||
@@ -43,3 +122,5 @@ validate_entropy_seed_injection:MBEDTLS_ENTROPY_BLOCK_SIZE-1:PSA_ERROR_INVALID_A
|
||||
PSA validate entropy injection: before and after crypto_init
|
||||
run_entropy_inject_with_crypto_init:
|
||||
|
||||
Recreate NV seed file
|
||||
create_nv_seed:
|
||||
|
||||
@@ -4,9 +4,151 @@
|
||||
|
||||
#include <psa/crypto.h>
|
||||
|
||||
/* Some tests in this module configure entropy sources. */
|
||||
#include "psa_crypto_invasive.h"
|
||||
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "entropy_poll.h"
|
||||
|
||||
#define ENTROPY_MIN_NV_SEED_SIZE \
|
||||
MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE)
|
||||
|
||||
#include "psa_crypto_random_impl.h"
|
||||
#if defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE)
|
||||
/* PSA crypto uses the HMAC_DRBG module. It reads from the entropy source twice:
|
||||
* once for the initial entropy and once for a nonce. The nonce length is
|
||||
* half the entropy length. For SHA-256, SHA-384 or SHA-512, the
|
||||
* entropy length is 256 per the documentation of mbedtls_hmac_drbg_seed(),
|
||||
* and PSA crypto doesn't support other hashes for HMAC_DRBG. */
|
||||
#define ENTROPY_NONCE_LEN (256 / 2)
|
||||
#else
|
||||
/* PSA crypto uses the CTR_DRBG module. In some configurations, it needs
|
||||
* to read from the entropy source twice: once for the initial entropy
|
||||
* and once for a nonce. */
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#define ENTROPY_NONCE_LEN MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN
|
||||
#endif
|
||||
|
||||
#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
|
||||
|
||||
typedef struct {
|
||||
size_t threshold; /* Minimum bytes to make mbedtls_entropy_func happy */
|
||||
size_t max_steps;
|
||||
size_t *length_sequence;
|
||||
size_t step;
|
||||
} fake_entropy_state_t;
|
||||
|
||||
static int fake_entropy_source(void *state_arg,
|
||||
unsigned char *output, size_t len,
|
||||
size_t *olen)
|
||||
{
|
||||
fake_entropy_state_t *state = state_arg;
|
||||
size_t i;
|
||||
|
||||
if (state->step >= state->max_steps) {
|
||||
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
||||
}
|
||||
|
||||
*olen = MIN(len, state->length_sequence[state->step]);
|
||||
for (i = 0; i < *olen; i++) {
|
||||
output[i] = i;
|
||||
}
|
||||
++state->step;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ENTROPY_SOURCE_PLATFORM 0x00000001
|
||||
#define ENTROPY_SOURCE_TIMING 0x00000002
|
||||
#define ENTROPY_SOURCE_HARDWARE 0x00000004
|
||||
#define ENTROPY_SOURCE_NV_SEED 0x00000008
|
||||
#define ENTROPY_SOURCE_FAKE 0x40000000
|
||||
|
||||
static uint32_t custom_entropy_sources_mask;
|
||||
static fake_entropy_state_t fake_entropy_state;
|
||||
|
||||
/* This is a modified version of mbedtls_entropy_init() from entropy.c
|
||||
* which chooses entropy sources dynamically. */
|
||||
static void custom_entropy_init(mbedtls_entropy_context *ctx)
|
||||
{
|
||||
ctx->source_count = 0;
|
||||
memset(ctx->source, 0, sizeof(ctx->source));
|
||||
|
||||
#if defined(MBEDTLS_THREADING_C)
|
||||
mbedtls_mutex_init(&ctx->mutex);
|
||||
#endif
|
||||
|
||||
ctx->accumulator_started = 0;
|
||||
mbedtls_md_init(&ctx->accumulator);
|
||||
|
||||
#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
|
||||
if (custom_entropy_sources_mask & ENTROPY_SOURCE_PLATFORM) {
|
||||
mbedtls_entropy_add_source(ctx, mbedtls_platform_entropy_poll, NULL,
|
||||
MBEDTLS_ENTROPY_MIN_PLATFORM,
|
||||
MBEDTLS_ENTROPY_SOURCE_STRONG);
|
||||
}
|
||||
#endif
|
||||
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
|
||||
if (custom_entropy_sources_mask & ENTROPY_SOURCE_HARDWARE) {
|
||||
mbedtls_entropy_add_source(ctx, mbedtls_hardware_poll, NULL,
|
||||
MBEDTLS_ENTROPY_MIN_HARDWARE,
|
||||
MBEDTLS_ENTROPY_SOURCE_STRONG);
|
||||
}
|
||||
#endif
|
||||
#if defined(MBEDTLS_ENTROPY_NV_SEED)
|
||||
if (custom_entropy_sources_mask & ENTROPY_SOURCE_NV_SEED) {
|
||||
mbedtls_entropy_add_source(ctx, mbedtls_nv_seed_poll, NULL,
|
||||
MBEDTLS_ENTROPY_BLOCK_SIZE,
|
||||
MBEDTLS_ENTROPY_SOURCE_STRONG);
|
||||
ctx->initial_entropy_run = 0;
|
||||
} else {
|
||||
/* Skip the NV seed even though it's compiled in. */
|
||||
ctx->initial_entropy_run = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (custom_entropy_sources_mask & ENTROPY_SOURCE_FAKE) {
|
||||
mbedtls_entropy_add_source(ctx,
|
||||
fake_entropy_source, &fake_entropy_state,
|
||||
fake_entropy_state.threshold,
|
||||
MBEDTLS_ENTROPY_SOURCE_STRONG);
|
||||
}
|
||||
}
|
||||
|
||||
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) */
|
||||
|
||||
/* Calculating the minimum allowed entropy size in bytes */
|
||||
#define MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, \
|
||||
MBEDTLS_ENTROPY_BLOCK_SIZE)
|
||||
@@ -68,6 +210,375 @@ psa_status_t remove_seed_file(void)
|
||||
|
||||
/* END_HEADER */
|
||||
|
||||
/* BEGIN_DEPENDENCIES
|
||||
* depends_on:MBEDTLS_PSA_CRYPTO_C
|
||||
* END_DEPENDENCIES
|
||||
*/
|
||||
|
||||
/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
void create_nv_seed()
|
||||
{
|
||||
static unsigned char seed[ENTROPY_MIN_NV_SEED_SIZE];
|
||||
TEST_ASSERT(mbedtls_nv_seed_write(seed, sizeof(seed)) >= 0);
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
void custom_entropy_sources(int sources_arg, int expected_init_status_arg)
|
||||
{
|
||||
psa_status_t expected_init_status = expected_init_status_arg;
|
||||
uint8_t random[10] = { 0 };
|
||||
|
||||
custom_entropy_sources_mask = sources_arg;
|
||||
PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
|
||||
custom_entropy_init, mbedtls_entropy_free));
|
||||
|
||||
TEST_EQUAL(psa_crypto_init(), expected_init_status);
|
||||
if (expected_init_status != PSA_SUCCESS) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||
|
||||
exit:
|
||||
PSA_DONE();
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
void fake_entropy_source(int threshold,
|
||||
int amount1,
|
||||
int amount2,
|
||||
int amount3,
|
||||
int amount4,
|
||||
int expected_init_status_arg)
|
||||
{
|
||||
psa_status_t expected_init_status = expected_init_status_arg;
|
||||
uint8_t random[10] = { 0 };
|
||||
size_t lengths[4];
|
||||
|
||||
fake_entropy_state.threshold = threshold;
|
||||
fake_entropy_state.step = 0;
|
||||
fake_entropy_state.max_steps = 0;
|
||||
if (amount1 >= 0) {
|
||||
lengths[fake_entropy_state.max_steps++] = amount1;
|
||||
}
|
||||
if (amount2 >= 0) {
|
||||
lengths[fake_entropy_state.max_steps++] = amount2;
|
||||
}
|
||||
if (amount3 >= 0) {
|
||||
lengths[fake_entropy_state.max_steps++] = amount3;
|
||||
}
|
||||
if (amount4 >= 0) {
|
||||
lengths[fake_entropy_state.max_steps++] = amount4;
|
||||
}
|
||||
fake_entropy_state.length_sequence = lengths;
|
||||
|
||||
custom_entropy_sources_mask = ENTROPY_SOURCE_FAKE;
|
||||
PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
|
||||
custom_entropy_init, mbedtls_entropy_free));
|
||||
|
||||
TEST_EQUAL(psa_crypto_init(), expected_init_status);
|
||||
if (expected_init_status != PSA_SUCCESS) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||
|
||||
exit:
|
||||
PSA_DONE();
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
void entropy_from_nv_seed(int seed_size_arg,
|
||||
int expected_init_status_arg)
|
||||
{
|
||||
psa_status_t expected_init_status = expected_init_status_arg;
|
||||
uint8_t random[10] = { 0 };
|
||||
uint8_t *seed = NULL;
|
||||
size_t seed_size = seed_size_arg;
|
||||
|
||||
TEST_CALLOC(seed, seed_size);
|
||||
TEST_ASSERT(mbedtls_nv_seed_write(seed, seed_size) >= 0);
|
||||
|
||||
custom_entropy_sources_mask = ENTROPY_SOURCE_NV_SEED;
|
||||
PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
|
||||
custom_entropy_init, mbedtls_entropy_free));
|
||||
|
||||
TEST_EQUAL(psa_crypto_init(), expected_init_status);
|
||||
if (expected_init_status != PSA_SUCCESS) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||
|
||||
exit:
|
||||
mbedtls_free(seed);
|
||||
PSA_DONE();
|
||||
}
|
||||
/* 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_random_deplete(), 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)));
|
||||
|
||||
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:
|
||||
PSA_DONE();
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
void prediction_resistance_bad_state()
|
||||
{
|
||||
uint8_t random[10];
|
||||
|
||||
/* RNG inactive before initialization */
|
||||
TEST_EQUAL(psa_random_set_prediction_resistance(0), PSA_ERROR_BAD_STATE);
|
||||
TEST_EQUAL(psa_random_set_prediction_resistance(1), PSA_ERROR_BAD_STATE);
|
||||
TEST_EQUAL(psa_generate_random(random, sizeof(random)), PSA_ERROR_BAD_STATE);
|
||||
|
||||
PSA_INIT();
|
||||
|
||||
/* Good cases, as controls */
|
||||
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||
PSA_ASSERT(psa_random_set_prediction_resistance(0));
|
||||
#if MBEDTLS_ENTROPY_TRUE_SOURCES > 0
|
||||
PSA_ASSERT(psa_random_set_prediction_resistance(1));
|
||||
#endif
|
||||
|
||||
/* RNG inactive after shutdown */
|
||||
mbedtls_psa_crypto_free();
|
||||
TEST_EQUAL(psa_random_set_prediction_resistance(0), PSA_ERROR_BAD_STATE);
|
||||
TEST_EQUAL(psa_random_set_prediction_resistance(1), 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 */
|
||||
void prediction_resistance_bad_arguments()
|
||||
{
|
||||
uint8_t random[10];
|
||||
|
||||
PSA_INIT();
|
||||
|
||||
TEST_EQUAL(psa_random_set_prediction_resistance(2), PSA_ERROR_INVALID_ARGUMENT);
|
||||
TEST_EQUAL(psa_random_set_prediction_resistance(-1), PSA_ERROR_INVALID_ARGUMENT);
|
||||
|
||||
/* Good cases, as controls */
|
||||
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||
PSA_ASSERT(psa_random_set_prediction_resistance(0));
|
||||
#if MBEDTLS_ENTROPY_TRUE_SOURCES > 0
|
||||
PSA_ASSERT(psa_random_set_prediction_resistance(1));
|
||||
#else
|
||||
TEST_EQUAL(psa_random_set_prediction_resistance(1), PSA_ERROR_NOT_SUPPORTED);
|
||||
#endif
|
||||
|
||||
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 };
|
||||
const size_t max_get_entropy = 4;
|
||||
|
||||
if (!psa_init_deterministic(max_get_entropy)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Depending on the DRBG parameters, the initial seeding may
|
||||
* consume entropy once or twice. Zero would be deeply unsettling
|
||||
* (how can you initialize the RNG without entropy?). More than 2 would
|
||||
* be ok, but the test code would need to be adapted. */
|
||||
TEST_LE_U(1, fake_entropy_state.step);
|
||||
TEST_LE_U(fake_entropy_state.step, 2);
|
||||
/* Arrange to have exactly 2 entropy blocks remaining. */
|
||||
fake_entropy_state.step = max_get_entropy - 2;
|
||||
|
||||
/* 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 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:MBEDTLS_ENTROPY_HAVE_TRUE_SOURCES */
|
||||
void prediction_resistance_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;
|
||||
|
||||
/* Default: no prediction resistance */
|
||||
/* (Note, we assume that prediction resistance is not effectively enabled
|
||||
* at compile time by setting a very low reseed interval.) */
|
||||
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||
TEST_EQUAL(fake_entropy_state.step, 1);
|
||||
|
||||
/* Explicitly enable prediction resistance */
|
||||
PSA_ASSERT(psa_random_set_prediction_resistance(1));
|
||||
TEST_EQUAL(fake_entropy_state.step, 1);
|
||||
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||
TEST_EQUAL(fake_entropy_state.step, 2);
|
||||
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||
TEST_EQUAL(fake_entropy_state.step, 3);
|
||||
|
||||
/* Explicitly disable prediction resistance */
|
||||
PSA_ASSERT(psa_random_set_prediction_resistance(0));
|
||||
TEST_EQUAL(fake_entropy_state.step, 3);
|
||||
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||
TEST_EQUAL(fake_entropy_state.step, 3);
|
||||
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||
TEST_EQUAL(fake_entropy_state.step, 3);
|
||||
|
||||
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 };
|
||||
/* Enough for 2 initial seeding + 2 reseed + 2 getrandom with
|
||||
* prediction resistance */
|
||||
size_t max_entropy_queries = 6;
|
||||
|
||||
/* Reference: no reseed */
|
||||
if (!psa_init_deterministic(max_entropy_queries)) {
|
||||
goto exit;
|
||||
}
|
||||
PSA_ASSERT(psa_generate_random(random0, sizeof(random0)));
|
||||
mbedtls_psa_crypto_free();
|
||||
|
||||
/* Reference: no reseed, again */
|
||||
if (!psa_init_deterministic(max_entropy_queries)) {
|
||||
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(max_entropy_queries)) {
|
||||
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(max_entropy_queries)) {
|
||||
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(max_entropy_queries)) {
|
||||
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 */
|
||||
void external_rng_failure_generate()
|
||||
{
|
||||
@@ -83,6 +594,11 @@ void external_rng_failure_generate()
|
||||
PSA_ASSERT(psa_generate_key(&attributes, &key));
|
||||
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);
|
||||
TEST_EQUAL(psa_random_set_prediction_resistance(0), PSA_ERROR_NOT_SUPPORTED);
|
||||
TEST_EQUAL(psa_random_set_prediction_resistance(1), PSA_ERROR_NOT_SUPPORTED);
|
||||
|
||||
mbedtls_test_disable_insecure_external_rng();
|
||||
TEST_EQUAL(PSA_ERROR_INSUFFICIENT_ENTROPY,
|
||||
psa_generate_random(output, sizeof(output)));
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
Create NV seed file
|
||||
create_nv_seed:
|
||||
|
||||
PSA init/deinit
|
||||
init_deinit:2
|
||||
|
||||
@@ -24,49 +21,3 @@ validate_module_init_generate_random:1
|
||||
|
||||
No key slot access after deinit
|
||||
validate_module_init_key_based:1
|
||||
|
||||
Custom entropy sources: all standard
|
||||
custom_entropy_sources:0x0000ffff:PSA_SUCCESS
|
||||
|
||||
# MBEDTLS_PSA_INJECT_ENTROPY means that a source of entropy (the seed file)
|
||||
# is effectively always available.
|
||||
Custom entropy sources: none
|
||||
depends_on:!MBEDTLS_PSA_INJECT_ENTROPY
|
||||
custom_entropy_sources:0:PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
|
||||
Fake entropy: never returns anything
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:0:0:0:PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
|
||||
Fake entropy: less than the block size
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:-1:PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
|
||||
Fake entropy: not enough for a nonce
|
||||
depends_on:ENTROPY_NONCE_LEN != 0
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:ENTROPY_NONCE_LEN - 1:-1:-1:-1:PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
|
||||
Fake entropy: one block eventually
|
||||
depends_on:ENTROPY_NONCE_LEN == 0
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:0:0:MBEDTLS_ENTROPY_BLOCK_SIZE:PSA_SUCCESS
|
||||
|
||||
Fake entropy: one block in two steps
|
||||
depends_on:ENTROPY_NONCE_LEN == 0
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:1:-1:-1:PSA_SUCCESS
|
||||
|
||||
Fake entropy: more than one block in two steps
|
||||
depends_on:ENTROPY_NONCE_LEN == 0
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:PSA_SUCCESS
|
||||
|
||||
Fake entropy: two blocks eventually
|
||||
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:MBEDTLS_ENTROPY_BLOCK_SIZE:0:MBEDTLS_ENTROPY_BLOCK_SIZE:PSA_SUCCESS
|
||||
|
||||
NV seed only: less than minimum
|
||||
entropy_from_nv_seed:MBEDTLS_ENTROPY_MIN_PLATFORM - 1:PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
|
||||
NV seed only: less than one block
|
||||
entropy_from_nv_seed:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:PSA_ERROR_INSUFFICIENT_ENTROPY
|
||||
|
||||
NV seed only: just enough
|
||||
entropy_from_nv_seed:ENTROPY_MIN_NV_SEED_SIZE:PSA_SUCCESS
|
||||
|
||||
Recreate NV seed file
|
||||
create_nv_seed:
|
||||
|
||||
@@ -2,12 +2,9 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "psa_crypto_core.h"
|
||||
/* Some tests in this module configure entropy sources. */
|
||||
/* For mbedtls_psa_crypto_configure_entropy_sources() */
|
||||
#include "psa_crypto_invasive.h"
|
||||
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "entropy_poll.h"
|
||||
|
||||
static int check_stats(void)
|
||||
{
|
||||
mbedtls_psa_stats_t stats;
|
||||
@@ -25,111 +22,6 @@ exit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ENTROPY_MIN_NV_SEED_SIZE \
|
||||
MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE)
|
||||
|
||||
#include "psa_crypto_random_impl.h"
|
||||
#if defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE)
|
||||
/* PSA crypto uses the HMAC_DRBG module. It reads from the entropy source twice:
|
||||
* once for the initial entropy and once for a nonce. The nonce length is
|
||||
* half the entropy length. For SHA-256, SHA-384 or SHA-512, the
|
||||
* entropy length is 256 per the documentation of mbedtls_hmac_drbg_seed(),
|
||||
* and PSA crypto doesn't support other hashes for HMAC_DRBG. */
|
||||
#define ENTROPY_NONCE_LEN (256 / 2)
|
||||
#else
|
||||
/* PSA crypto uses the CTR_DRBG module. In some configurations, it needs
|
||||
* to read from the entropy source twice: once for the initial entropy
|
||||
* and once for a nonce. */
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#define ENTROPY_NONCE_LEN MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN
|
||||
#endif
|
||||
|
||||
#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
|
||||
|
||||
typedef struct {
|
||||
size_t threshold; /* Minimum bytes to make mbedtls_entropy_func happy */
|
||||
size_t max_steps;
|
||||
size_t *length_sequence;
|
||||
size_t step;
|
||||
} fake_entropy_state_t;
|
||||
static int fake_entropy_source(void *state_arg,
|
||||
unsigned char *output, size_t len,
|
||||
size_t *olen)
|
||||
{
|
||||
fake_entropy_state_t *state = state_arg;
|
||||
size_t i;
|
||||
|
||||
if (state->step >= state->max_steps) {
|
||||
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
||||
}
|
||||
|
||||
*olen = MIN(len, state->length_sequence[state->step]);
|
||||
for (i = 0; i < *olen; i++) {
|
||||
output[i] = i;
|
||||
}
|
||||
++state->step;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ENTROPY_SOURCE_PLATFORM 0x00000001
|
||||
#define ENTROPY_SOURCE_TIMING 0x00000002
|
||||
#define ENTROPY_SOURCE_HARDWARE 0x00000004
|
||||
#define ENTROPY_SOURCE_NV_SEED 0x00000008
|
||||
#define ENTROPY_SOURCE_FAKE 0x40000000
|
||||
|
||||
static uint32_t custom_entropy_sources_mask;
|
||||
static fake_entropy_state_t fake_entropy_state;
|
||||
|
||||
/* This is a modified version of mbedtls_entropy_init() from entropy.c
|
||||
* which chooses entropy sources dynamically. */
|
||||
static void custom_entropy_init(mbedtls_entropy_context *ctx)
|
||||
{
|
||||
ctx->source_count = 0;
|
||||
memset(ctx->source, 0, sizeof(ctx->source));
|
||||
|
||||
#if defined(MBEDTLS_THREADING_C)
|
||||
mbedtls_mutex_init(&ctx->mutex);
|
||||
#endif
|
||||
|
||||
ctx->accumulator_started = 0;
|
||||
mbedtls_md_init(&ctx->accumulator);
|
||||
|
||||
#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
|
||||
if (custom_entropy_sources_mask & ENTROPY_SOURCE_PLATFORM) {
|
||||
mbedtls_entropy_add_source(ctx, mbedtls_platform_entropy_poll, NULL,
|
||||
MBEDTLS_ENTROPY_MIN_PLATFORM,
|
||||
MBEDTLS_ENTROPY_SOURCE_STRONG);
|
||||
}
|
||||
#endif
|
||||
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
|
||||
if (custom_entropy_sources_mask & ENTROPY_SOURCE_HARDWARE) {
|
||||
mbedtls_entropy_add_source(ctx, mbedtls_hardware_poll, NULL,
|
||||
MBEDTLS_ENTROPY_MIN_HARDWARE,
|
||||
MBEDTLS_ENTROPY_SOURCE_STRONG);
|
||||
}
|
||||
#endif
|
||||
#if defined(MBEDTLS_ENTROPY_NV_SEED)
|
||||
if (custom_entropy_sources_mask & ENTROPY_SOURCE_NV_SEED) {
|
||||
mbedtls_entropy_add_source(ctx, mbedtls_nv_seed_poll, NULL,
|
||||
MBEDTLS_ENTROPY_BLOCK_SIZE,
|
||||
MBEDTLS_ENTROPY_SOURCE_STRONG);
|
||||
ctx->initial_entropy_run = 0;
|
||||
} else {
|
||||
/* Skip the NV seed even though it's compiled in. */
|
||||
ctx->initial_entropy_run = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (custom_entropy_sources_mask & ENTROPY_SOURCE_FAKE) {
|
||||
mbedtls_entropy_add_source(ctx,
|
||||
fake_entropy_source, &fake_entropy_state,
|
||||
fake_entropy_state.threshold,
|
||||
MBEDTLS_ENTROPY_SOURCE_STRONG);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
|
||||
|
||||
#if defined MBEDTLS_THREADING_PTHREAD
|
||||
|
||||
typedef struct {
|
||||
@@ -190,14 +82,6 @@ exit:
|
||||
* END_DEPENDENCIES
|
||||
*/
|
||||
|
||||
/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
void create_nv_seed()
|
||||
{
|
||||
static unsigned char seed[ENTROPY_MIN_NV_SEED_SIZE];
|
||||
TEST_ASSERT(mbedtls_nv_seed_write(seed, sizeof(seed)) >= 0);
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE */
|
||||
void init_deinit(int count)
|
||||
{
|
||||
@@ -333,99 +217,3 @@ void validate_module_init_key_based(int count)
|
||||
TEST_ASSERT(mbedtls_svc_key_id_is_null(key));
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
void custom_entropy_sources(int sources_arg, int expected_init_status_arg)
|
||||
{
|
||||
psa_status_t expected_init_status = expected_init_status_arg;
|
||||
uint8_t random[10] = { 0 };
|
||||
|
||||
custom_entropy_sources_mask = sources_arg;
|
||||
PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
|
||||
custom_entropy_init, mbedtls_entropy_free));
|
||||
|
||||
TEST_EQUAL(psa_crypto_init(), expected_init_status);
|
||||
if (expected_init_status != PSA_SUCCESS) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||
|
||||
exit:
|
||||
PSA_DONE();
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
void fake_entropy_source(int threshold,
|
||||
int amount1,
|
||||
int amount2,
|
||||
int amount3,
|
||||
int amount4,
|
||||
int expected_init_status_arg)
|
||||
{
|
||||
psa_status_t expected_init_status = expected_init_status_arg;
|
||||
uint8_t random[10] = { 0 };
|
||||
size_t lengths[4];
|
||||
|
||||
fake_entropy_state.threshold = threshold;
|
||||
fake_entropy_state.step = 0;
|
||||
fake_entropy_state.max_steps = 0;
|
||||
if (amount1 >= 0) {
|
||||
lengths[fake_entropy_state.max_steps++] = amount1;
|
||||
}
|
||||
if (amount2 >= 0) {
|
||||
lengths[fake_entropy_state.max_steps++] = amount2;
|
||||
}
|
||||
if (amount3 >= 0) {
|
||||
lengths[fake_entropy_state.max_steps++] = amount3;
|
||||
}
|
||||
if (amount4 >= 0) {
|
||||
lengths[fake_entropy_state.max_steps++] = amount4;
|
||||
}
|
||||
fake_entropy_state.length_sequence = lengths;
|
||||
|
||||
custom_entropy_sources_mask = ENTROPY_SOURCE_FAKE;
|
||||
PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
|
||||
custom_entropy_init, mbedtls_entropy_free));
|
||||
|
||||
TEST_EQUAL(psa_crypto_init(), expected_init_status);
|
||||
if (expected_init_status != PSA_SUCCESS) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||
|
||||
exit:
|
||||
PSA_DONE();
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
|
||||
void entropy_from_nv_seed(int seed_size_arg,
|
||||
int expected_init_status_arg)
|
||||
{
|
||||
psa_status_t expected_init_status = expected_init_status_arg;
|
||||
uint8_t random[10] = { 0 };
|
||||
uint8_t *seed = NULL;
|
||||
size_t seed_size = seed_size_arg;
|
||||
|
||||
TEST_CALLOC(seed, seed_size);
|
||||
TEST_ASSERT(mbedtls_nv_seed_write(seed, seed_size) >= 0);
|
||||
|
||||
custom_entropy_sources_mask = ENTROPY_SOURCE_NV_SEED;
|
||||
PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
|
||||
custom_entropy_init, mbedtls_entropy_free));
|
||||
|
||||
TEST_EQUAL(psa_crypto_init(), expected_init_status);
|
||||
if (expected_init_status != PSA_SUCCESS) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
PSA_ASSERT(psa_generate_random(random, sizeof(random)));
|
||||
|
||||
exit:
|
||||
mbedtls_free(seed);
|
||||
PSA_DONE();
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
Reference in New Issue
Block a user