Skip to content

Commit

Permalink
Merge pull request #7965 from gilles-peskine-arm/psa_inject_entropy-f…
Browse files Browse the repository at this point in the history
…ile-stability-2.28

Backport 2.28: Fix and test MBEDTLS_PSA_INJECT_ENTROPY
  • Loading branch information
gilles-peskine-arm authored Jul 21, 2023
2 parents 668323c + 1fc7116 commit b98d39c
Show file tree
Hide file tree
Showing 14 changed files with 229 additions and 28 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Random seed file created by test scripts and sample programs
seedfile
# MBEDTLS_PSA_INJECT_ENTROPY seed file created by the test framework
00000000ffffff52.psa_its

# CMake build artifacts:
CMakeCache.txt
Expand Down
2 changes: 2 additions & 0 deletions ChangeLog.d/inject-entropy.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Bugfix
* Fix the build with MBEDTLS_PSA_INJECT_ENTROPY. Fixes #7516.
6 changes: 4 additions & 2 deletions library/psa_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -5066,6 +5066,10 @@ psa_status_t psa_raw_key_agreement(psa_algorithm_t alg,
/* Random generation */
/****************************************************************/

#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
#include "mbedtls/entropy_poll.h"
#endif

/** Initialize the PSA random generator.
*/
static void mbedtls_psa_random_init(mbedtls_psa_random_context_t *rng)
Expand Down Expand Up @@ -5200,8 +5204,6 @@ int mbedtls_psa_get_random(void *p_rng,
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */

#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
#include "mbedtls/entropy_poll.h"

psa_status_t mbedtls_psa_inject_entropy(const uint8_t *seed,
size_t seed_size)
{
Expand Down
2 changes: 1 addition & 1 deletion scripts/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def realfull_adapter(_name, active, section):
'MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG', # behavior change + build dependency
'MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER', # incompatible with USE_PSA_CRYPTO
'MBEDTLS_PSA_CRYPTO_SPM', # platform dependency (PSA SPM)
'MBEDTLS_PSA_INJECT_ENTROPY', # build dependency (hook functions)
'MBEDTLS_PSA_INJECT_ENTROPY', # conflicts with platform entropy sources
'MBEDTLS_REMOVE_3DES_CIPHERSUITES', # removes a feature
'MBEDTLS_REMOVE_ARC4_CIPHERSUITES', # removes a feature
'MBEDTLS_RSA_NO_CRT', # influences the use of RSA in X.509 and TLS
Expand Down
20 changes: 20 additions & 0 deletions tests/configs/user-config-for-test.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,23 @@
#define MBEDTLS_PSA_ACCEL_ALG_HMAC

#endif /* PSA_CRYPTO_DRIVER_TEST_ALL */



#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
/* The #MBEDTLS_PSA_INJECT_ENTROPY feature requires two extra platform
* functions, which must be configured as #MBEDTLS_PLATFORM_NV_SEED_READ_MACRO
* and #MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO. The job of these functions
* is to read and write from the entropy seed file, which is located
* in the PSA ITS file whose uid is #PSA_CRYPTO_ITS_RANDOM_SEED_UID.
* (These could have been provided as library functions, but for historical
* reasons, they weren't, and so each integrator has to provide a copy
* of these functions.)
*
* Provide implementations of these functions for testing. */
#include <stddef.h>
int mbedtls_test_inject_entropy_seed_read(unsigned char *buf, size_t len);
int mbedtls_test_inject_entropy_seed_write(unsigned char *buf, size_t len);
#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO mbedtls_test_inject_entropy_seed_read
#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO mbedtls_test_inject_entropy_seed_write
#endif /* MBEDTLS_PSA_INJECT_ENTROPY */
35 changes: 35 additions & 0 deletions tests/include/test/psa_crypto_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,41 @@ psa_key_usage_t mbedtls_test_update_key_usage_flags(psa_key_usage_t usage_flags)
*/
int mbedtls_test_fail_if_psa_leaking(int line_no, const char *filename);



#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
/* The #MBEDTLS_PSA_INJECT_ENTROPY feature requires two extra platform
* functions, which must be configured as #MBEDTLS_PLATFORM_NV_SEED_READ_MACRO
* and #MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO. The job of these functions
* is to read and write from the entropy seed file, which is located
* in the PSA ITS file whose uid is #PSA_CRYPTO_ITS_RANDOM_SEED_UID.
* (These could have been provided as library functions, but for historical
* reasons, they weren't, and so each integrator has to provide a copy
* of these functions.)
*
* Provide implementations of these functions for testing. */
int mbedtls_test_inject_entropy_seed_read(unsigned char *buf, size_t len);
int mbedtls_test_inject_entropy_seed_write(unsigned char *buf, size_t len);


/** Make sure that the injected entropy is present.
*
* When MBEDTLS_PSA_INJECT_ENTROPY is enabled, psa_crypto_init()
* will fail if the PSA entropy seed is not present.
* This function must be called at least once in a test suite or other
* program before any call to psa_crypto_init().
* It does not need to be called in each test case.
*
* The test framework calls this function before running any test case.
*
* The few tests that might remove the entropy file must call this function
* in their cleanup.
*/
int mbedtls_test_inject_entropy_restore(void);
#endif /* MBEDTLS_PSA_INJECT_ENTROPY */



/** Skip a test case if the given key is a 192 bits AES key and the AES
* implementation is at least partially provided by an accelerator or
* alternative implementation.
Expand Down
15 changes: 15 additions & 0 deletions tests/scripts/all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,21 @@ component_test_psa_external_rng_use_psa_crypto () {
tests/ssl-opt.sh -f 'Default\|opaque'
}

component_test_psa_inject_entropy () {
msg "build: full + MBEDTLS_PSA_INJECT_ENTROPY"
scripts/config.py full
scripts/config.py set MBEDTLS_PSA_INJECT_ENTROPY
scripts/config.py set MBEDTLS_ENTROPY_NV_SEED
scripts/config.py set MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT
scripts/config.py unset MBEDTLS_PLATFORM_STD_NV_SEED_READ
scripts/config.py unset MBEDTLS_PLATFORM_STD_NV_SEED_WRITE
make CFLAGS="$ASAN_CFLAGS '-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/user-config-for-test.h\"'" LDFLAGS="$ASAN_CFLAGS"

msg "test: full + MBEDTLS_PSA_INJECT_ENTROPY"
make test
}

component_test_ecp_no_internal_rng () {
msg "build: Default plus ECP_NO_INTERNAL_RNG minus DRBG modules"
scripts/config.py set MBEDTLS_ECP_NO_INTERNAL_RNG
Expand Down
18 changes: 18 additions & 0 deletions tests/src/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
#include <setjmp.h>
#endif

#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
#include <psa/crypto.h>
#include <test/psa_crypto_helpers.h>
#endif

/*----------------------------------------------------------------------------*/
/* Static global variables */

Expand Down Expand Up @@ -52,9 +57,22 @@ mbedtls_test_info_t mbedtls_test_info;
int mbedtls_test_platform_setup(void)
{
int ret = 0;

#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
/* Make sure that injected entropy is present. Otherwise
* psa_crypto_init() will fail. This is not necessary for test suites
* that don't use PSA, but it's harmless (except for leaving a file
* behind). */
ret = mbedtls_test_inject_entropy_restore();
if (ret != 0) {
return ret;
}
#endif

#if defined(MBEDTLS_PLATFORM_C)
ret = mbedtls_platform_setup(&platform_ctx);
#endif /* MBEDTLS_PLATFORM_C */

return ret;
}

Expand Down
45 changes: 45 additions & 0 deletions tests/src/psa_crypto_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,49 @@ int mbedtls_test_fail_if_psa_leaking(int line_no, const char *filename)
}
}

#if defined(MBEDTLS_PSA_INJECT_ENTROPY)

#include <mbedtls/entropy.h>
#include <psa_crypto_its.h>

int mbedtls_test_inject_entropy_seed_read(unsigned char *buf, size_t len)
{
size_t actual_len = 0;
psa_status_t status = psa_its_get(PSA_CRYPTO_ITS_RANDOM_SEED_UID,
0, len, buf, &actual_len);
if (status != 0) {
return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
}
if (actual_len != len) {
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
}
return 0;
}

int mbedtls_test_inject_entropy_seed_write(unsigned char *buf, size_t len)
{
psa_status_t status = psa_its_set(PSA_CRYPTO_ITS_RANDOM_SEED_UID,
len, buf, 0);
if (status != 0) {
return MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
}
return 0;
}

int mbedtls_test_inject_entropy_restore(void)
{
unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
for (size_t i = 0; i < sizeof(buf); i++) {
buf[i] = (unsigned char) i;
}
psa_status_t status = mbedtls_psa_inject_entropy(buf, sizeof(buf));
/* It's ok if the file was just created, or if it already exists. */
if (status != PSA_SUCCESS && status != PSA_ERROR_NOT_PERMITTED) {
return status;
}
return PSA_SUCCESS;
}

#endif /* MBEDTLS_PSA_INJECT_ENTROPY */

#endif /* MBEDTLS_PSA_CRYPTO_C */
2 changes: 1 addition & 1 deletion tests/suites/test_suite_entropy.function
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ int read_nv_seed(unsigned char *buf, size_t buf_len)
/* END_HEADER */

/* BEGIN_DEPENDENCIES
* depends_on:MBEDTLS_ENTROPY_C
* depends_on:MBEDTLS_ENTROPY_C:!MBEDTLS_PSA_INJECT_ENTROPY
* END_DEPENDENCIES
*/

Expand Down
97 changes: 78 additions & 19 deletions tests/suites/test_suite_psa_crypto_entropy.function
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,56 @@
MBEDTLS_ENTROPY_BLOCK_SIZE)

#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
#include <psa_crypto_its.h>

/* Check the entropy seed file.
*
* \param expected_size Expected size in bytes.
* If 0, the file must not exist.
*
* \retval 1 Either \p expected_size is nonzero and
* the entropy seed file exists and has exactly this size,
* or \p expected_size is zero and the file does not exist.
* \retval 0 Either \p expected_size is nonzero but
* the entropy seed file does not exist or has a different size,
* or \p expected_size is zero but the file exists.
* In this case, the test case is marked as failed.
*
* \note We enforce that the seed is in a specific ITS file.
* This must not change, otherwise we break backward compatibility if
* the library is upgraded on a device with an existing seed.
*/
int check_random_seed_file(size_t expected_size)
{
/* The value of the random seed UID must not change. Otherwise that would
* break upgrades of the library on devices that already contain a seed
* file. If this test assertion fails, you've presumably broken backward
* compatibility! */
TEST_EQUAL(PSA_CRYPTO_ITS_RANDOM_SEED_UID, 0xFFFFFF52);

struct psa_storage_info_t info = { 0, 0 };
psa_status_t status = psa_its_get_info(PSA_CRYPTO_ITS_RANDOM_SEED_UID,
&info);

if (expected_size == 0) {
TEST_EQUAL(status, PSA_ERROR_DOES_NOT_EXIST);
} else {
TEST_EQUAL(status, PSA_SUCCESS);
TEST_EQUAL(info.size, expected_size);
}
return 1;

#if defined(MBEDTLS_PSA_ITS_FILE_C)
#include <stdio.h>
#else
#include <psa/internal_trusted_storage.h>
#endif
exit:
return 0;
}

/* Remove the entropy seed file. Since the library does not expose a way
* to do this (it would be a security risk if such a function was ever
* accessible in production), implement this functionality in a white-box
* manner. */
/* Remove the entropy seed file.
*
* See check_random_seed_file() regarding abstraction boundaries.
*/
psa_status_t remove_seed_file(void)
{
#if defined(MBEDTLS_PSA_ITS_FILE_C)
if (remove("00000000ffffff52.psa_its") == 0) {
return PSA_SUCCESS;
} else {
return PSA_ERROR_DOES_NOT_EXIST;
}
#else
return psa_its_remove(PSA_CRYPTO_ITS_RANDOM_SEED_UID);
#endif
}

#endif /* MBEDTLS_PSA_INJECT_ENTROPY */
Expand Down Expand Up @@ -143,18 +171,34 @@ void validate_entropy_seed_injection(int seed_length_a,
status = remove_seed_file();
TEST_ASSERT((status == PSA_SUCCESS) ||
(status == PSA_ERROR_DOES_NOT_EXIST));
if (!check_random_seed_file(0)) {
goto exit;
}

status = mbedtls_psa_inject_entropy(seed, seed_length_a);
TEST_EQUAL(status, expected_status_a);
if (!check_random_seed_file(expected_status_a == PSA_SUCCESS ? seed_length_a :
0)) {
goto exit;
}

status = mbedtls_psa_inject_entropy(seed, seed_length_b);
TEST_EQUAL(status, expected_status_b);
if (!check_random_seed_file(expected_status_a == PSA_SUCCESS ? seed_length_a :
expected_status_b == PSA_SUCCESS ? seed_length_b :
0)) {
goto exit;
}

PSA_ASSERT(psa_crypto_init());
PSA_ASSERT(psa_generate_random(output,
sizeof(output)));
TEST_ASSERT(memcmp(output, zeros, sizeof(output)) != 0);

exit:
mbedtls_free(seed);
remove_seed_file();
PSA_DONE();
mbedtls_test_inject_entropy_restore();
}
/* END_CASE */

Expand All @@ -168,25 +212,40 @@ void run_entropy_inject_with_crypto_init()
for (i = 0; i < sizeof(seed); ++i) {
seed[i] = i;
}

status = remove_seed_file();
TEST_ASSERT((status == PSA_SUCCESS) ||
(status == PSA_ERROR_DOES_NOT_EXIST));
if (!check_random_seed_file(0)) {
goto exit;
}
status = mbedtls_psa_inject_entropy(seed, sizeof(seed));
PSA_ASSERT(status);
TEST_ASSERT(check_random_seed_file(sizeof(seed)));
status = remove_seed_file();
TEST_EQUAL(status, PSA_SUCCESS);
if (!check_random_seed_file(0)) {
goto exit;
}

status = psa_crypto_init();
TEST_EQUAL(status, PSA_ERROR_INSUFFICIENT_ENTROPY);
status = mbedtls_psa_inject_entropy(seed, sizeof(seed));
PSA_ASSERT(status);
if (!check_random_seed_file(sizeof(seed))) {
goto exit;
}

status = psa_crypto_init();
PSA_ASSERT(status);
PSA_DONE();

/* The seed is written by nv_seed callback functions therefore the injection will fail */
status = mbedtls_psa_inject_entropy(seed, sizeof(seed));
TEST_EQUAL(status, PSA_ERROR_NOT_PERMITTED);

exit:
remove_seed_file();
PSA_DONE();
mbedtls_test_inject_entropy_restore();
}
/* END_CASE */
3 changes: 3 additions & 0 deletions tests/suites/test_suite_psa_crypto_init.data
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ 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
Expand Down
Loading

0 comments on commit b98d39c

Please sign in to comment.