diff options
Diffstat (limited to 'tests/src/psa_crypto_helpers.c')
-rw-r--r-- | tests/src/psa_crypto_helpers.c | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/tests/src/psa_crypto_helpers.c b/tests/src/psa_crypto_helpers.c new file mode 100644 index 00000000000..e1ea2b5c818 --- /dev/null +++ b/tests/src/psa_crypto_helpers.c @@ -0,0 +1,207 @@ +/** \file psa_crypto_helpers.c + * + * \brief Helper functions to test PSA crypto functionality. + */ + +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#include <test/helpers.h> +#include <test/macros.h> +#include <psa_crypto_slot_management.h> +#include <test/psa_crypto_helpers.h> + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include <psa/crypto.h> + +#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) + +#include <psa_crypto_storage.h> + +static mbedtls_svc_key_id_t key_ids_used_in_test[9]; +static size_t num_key_ids_used; + +int mbedtls_test_uses_key_id(mbedtls_svc_key_id_t key_id) +{ + size_t i; + if (MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key_id) > + PSA_MAX_PERSISTENT_KEY_IDENTIFIER) { + /* Don't touch key id values that designate non-key files. */ + return 1; + } + for (i = 0; i < num_key_ids_used; i++) { + if (mbedtls_svc_key_id_equal(key_id, key_ids_used_in_test[i])) { + return 1; + } + } + if (num_key_ids_used == ARRAY_LENGTH(key_ids_used_in_test)) { + return 0; + } + key_ids_used_in_test[num_key_ids_used] = key_id; + ++num_key_ids_used; + return 1; +} + +void mbedtls_test_psa_purge_key_storage(void) +{ + size_t i; + for (i = 0; i < num_key_ids_used; i++) { + psa_destroy_persistent_key(key_ids_used_in_test[i]); + } + num_key_ids_used = 0; +} + +void mbedtls_test_psa_purge_key_cache(void) +{ + size_t i; + for (i = 0; i < num_key_ids_used; i++) { + psa_purge_key(key_ids_used_in_test[i]); + } +} + +#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */ + +const char *mbedtls_test_helper_is_psa_leaking(void) +{ + mbedtls_psa_stats_t stats; + + mbedtls_psa_get_stats(&stats); + +#if defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_AES_C) && \ + !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) + /* When AES_C is not defined and PSA does not have an external RNG, + * then CTR_DRBG uses PSA to perform AES-ECB. In this scenario 1 key + * slot is used internally from PSA to hold the AES key and it should + * not be taken into account when evaluating remaining open slots. */ + if (stats.volatile_slots > 1) { + return "A volatile slot has not been closed properly."; + } +#else + if (stats.volatile_slots != 0) { + return "A volatile slot has not been closed properly."; + } +#endif + if (stats.persistent_slots != 0) { + return "A persistent slot has not been closed properly."; + } + if (stats.external_slots != 0) { + return "An external slot has not been closed properly."; + } + if (stats.half_filled_slots != 0) { + return "A half-filled slot has not been cleared properly."; + } + if (stats.locked_slots != 0) { + return "Some slots are still marked as locked."; + } + + return NULL; +} + +#if defined(RECORD_PSA_STATUS_COVERAGE_LOG) +/** Name of the file where return statuses are logged by #RECORD_STATUS. */ +#define STATUS_LOG_FILE_NAME "statuses.log" + +psa_status_t mbedtls_test_record_status(psa_status_t status, + const char *func, + const char *file, int line, + const char *expr) +{ + /* We open the log file on first use. + * We never close the log file, so the record_status feature is not + * compatible with resource leak detectors such as Asan. + */ + static FILE *log; + if (log == NULL) { + log = fopen(STATUS_LOG_FILE_NAME, "a"); + } + fprintf(log, "%d:%s:%s:%d:%s\n", (int) status, func, file, line, expr); + return status; +} +#endif /* defined(RECORD_PSA_STATUS_COVERAGE_LOG) */ + +psa_key_usage_t mbedtls_test_update_key_usage_flags(psa_key_usage_t usage_flags) +{ + psa_key_usage_t updated_usage = usage_flags; + + if (usage_flags & PSA_KEY_USAGE_SIGN_HASH) { + updated_usage |= PSA_KEY_USAGE_SIGN_MESSAGE; + } + + if (usage_flags & PSA_KEY_USAGE_VERIFY_HASH) { + updated_usage |= PSA_KEY_USAGE_VERIFY_MESSAGE; + } + + return updated_usage; +} + +int mbedtls_test_fail_if_psa_leaking(int line_no, const char *filename) +{ + const char *msg = mbedtls_test_helper_is_psa_leaking(); + if (msg == NULL) { + return 0; + } else { + mbedtls_test_fail(msg, line_no, filename); + return 1; + } +} + +uint64_t mbedtls_test_parse_binary_string(data_t *bin_string) +{ + uint64_t result = 0; + TEST_LE_U(bin_string->len, 8); + for (size_t i = 0; i < bin_string->len; i++) { + result = result << 8 | bin_string->x[i]; + } +exit: + return result; /* returns 0 if len > 8 */ +} + +#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 */ |