diff --git a/modules/mbedtls/CMakeLists.txt b/modules/mbedtls/CMakeLists.txt index 61c7400017da0..7fc5c1135c11d 100644 --- a/modules/mbedtls/CMakeLists.txt +++ b/modules/mbedtls/CMakeLists.txt @@ -253,4 +253,8 @@ else() # included the required directories for mbedtls in their projects. endif() + if(CONFIG_MBEDTLS_PSA_ITS_BACKEND_MBEDTLS_FILE) + zephyr_include_directories(psa/include) + endif() + endif() diff --git a/modules/mbedtls/Kconfig b/modules/mbedtls/Kconfig index cb178fb3c273e..4aa8392e6307e 100644 --- a/modules/mbedtls/Kconfig +++ b/modules/mbedtls/Kconfig @@ -243,3 +243,27 @@ config APP_LINK_WITH_MBEDTLS issues for 'app'. endif # MBEDTLS + +choice MBEDTLS_PSA_ITS_BACKEND + prompt "PSA Internal-Trusted-Storage backend implementation" + +config MBEDTLS_PSA_ITS_BACKEND_TFM + bool "Trusted-Firmware-M" + depends on BUILD_WITH_TFM + +config MBEDTLS_PSA_ITS_BACKEND_SECURE_STORAGE + bool "Zephyr Secure Storage" + depends on !BUILD_WITH_TFM + +config MBEDTLS_PSA_ITS_BACKEND_MBEDTLS_FILE + bool "MbedTLS builtin file" + depends on !BUILD_WITH_TFM + depends on ARCH_POSIX + select MBEDTLS + select MBEDTLS_PSA_CRYPTO_C + help + Native filesystem based implementation of PSA ITS. Note that multiple + instances of the sample application running at the same time will all + share the same backed. + +endchoice diff --git a/modules/mbedtls/configs/config-tls-generic.h b/modules/mbedtls/configs/config-tls-generic.h index 087246327cfab..b2b5f04974141 100644 --- a/modules/mbedtls/configs/config-tls-generic.h +++ b/modules/mbedtls/configs/config-tls-generic.h @@ -486,6 +486,12 @@ #define MBEDTLS_PSA_CRYPTO_STORAGE_C #endif +#if defined(CONFIG_MBEDTLS_PSA_ITS_BACKEND_MBEDTLS_FILE) +#define MBEDTLS_PSA_CRYPTO_STORAGE_C +#define MBEDTLS_PSA_ITS_FILE_C +#define MBEDTLS_FS_IO +#endif + #endif /* CONFIG_MBEDTLS_PSA_CRYPTO_C */ #if defined(CONFIG_MBEDTLS_PSA_STATIC_KEY_SLOTS) diff --git a/modules/mbedtls/psa/include/psa/error.h b/modules/mbedtls/psa/include/psa/error.h new file mode 100644 index 0000000000000..f93c464115a07 --- /dev/null +++ b/modules/mbedtls/psa/include/psa/error.h @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 Embeint Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/modules/mbedtls/psa/include/psa/internal_trusted_storage.h b/modules/mbedtls/psa/include/psa/internal_trusted_storage.h new file mode 100644 index 0000000000000..53b522b28a687 --- /dev/null +++ b/modules/mbedtls/psa/include/psa/internal_trusted_storage.h @@ -0,0 +1,153 @@ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Copy of `mbedtls/library/psa_crypto_its.h` until it is available at the same + * include path as TF-M (`psa/internal_trusted_storage.h`). + */ + +#ifndef PSA_CRYPTO_ITS_H +#define PSA_CRYPTO_ITS_H + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \brief Flags used when creating a data entry + */ +typedef uint32_t psa_storage_create_flags_t; + +/** \brief A type for UIDs used for identifying data + */ +typedef uint64_t psa_storage_uid_t; + +/** No flags to pass */ +#define PSA_STORAGE_FLAG_NONE 0 +/** + * The data associated with the uid will not be able to be modified or deleted. + * Intended to be used to set bits in `psa_storage_create_flags_t` + */ +#define PSA_STORAGE_FLAG_WRITE_ONCE (1 << 0) + +/** + * \brief A container for metadata associated with a specific uid + */ +struct psa_storage_info_t { + uint32_t size; /**< The size of the data associated with a uid **/ + psa_storage_create_flags_t flags; /**< The flags set when the uid was created **/ +}; + +/** Flag indicating that \ref psa_storage_create and \ref psa_storage_set_extended are supported */ +#define PSA_STORAGE_SUPPORT_SET_EXTENDED (1 << 0) + +#define PSA_ITS_API_VERSION_MAJOR 1 +#define PSA_ITS_API_VERSION_MINOR 1 + +/** + * \brief create a new or modify an existing uid/value pair + * + * \param[in] uid the identifier for the data + * \param[in] data_length The size in bytes of the data in `p_data` + * \param[in] p_data A buffer containing the data + * \param[in] create_flags The flags that the data will be stored with + * + * \return A status indicating the success/failure of the operation + * + * \retval #PSA_SUCCESS The operation completed successfully + * \retval #PSA_ERROR_NOT_PERMITTED The operation failed because the provided `uid` value + * was already created with PSA_STORAGE_FLAG_WRITE_ONCE + * \retval #PSA_ERROR_NOT_SUPPORTED The operation failed because one or more of the flags + * provided in `create_flags` is not supported or is not + * valid + * \retval #PSA_ERROR_INSUFFICIENT_STORAGE The operation failed because there was insufficient + * space on the storage medium + * \retval #PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has + * failed (Fatal error) + * \retval #PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided + * pointers(`p_data`) is invalid, for example is `NULL` + * or references memory the caller cannot access + */ +psa_status_t psa_its_set(psa_storage_uid_t uid, + uint32_t data_length, + const void *p_data, + psa_storage_create_flags_t create_flags); + +/** + * \brief Retrieve the value associated with a provided uid + * + * \param[in] uid The uid value + * \param[in] data_offset The starting offset of the data requested + * \param[in] data_length the amount of data requested (and the minimum allocated size of the + * `p_data` buffer) + * \param[out] p_data The buffer where the data will be placed upon successful completion + * \param[out] p_data_length The amount of data returned in the p_data buffer + * + * + * \return A status indicating the success/failure of the operation + * + * \retval #PSA_SUCCESS The operation completed successfully + * \retval #PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided `uid` value was + * not found in the storage + * \retval #PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has + * failed (Fatal error) + * \retval #PSA_ERROR_DATA_CORRUPT The operation failed because stored data has been corrupted + * \retval #PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided + * pointers(`p_data`, `p_data_length`) is invalid. For example + * is `NULL` or references memory the caller cannot access. In + * addition, this can also happen if an invalid offset was + * provided. + */ +psa_status_t psa_its_get(psa_storage_uid_t uid, + uint32_t data_offset, + uint32_t data_length, + void *p_data, + size_t *p_data_length); + +/** + * \brief Retrieve the metadata about the provided uid + * + * \param[in] uid The uid value + * \param[out] p_info A pointer to the `psa_storage_info_t` struct that will be populated + * with the metadata + * + * \return A status indicating the success/failure of the operation + * + * \retval #PSA_SUCCESS The operation completed successfully + * \retval #PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided uid value was + * not found in the storage + * \retval #PSA_ERROR_DATA_CORRUPT The operation failed because stored data has been corrupted + * \retval #PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided + * pointers(`p_info`) is invalid, for example is `NULL` or + * references memory the caller cannot access + */ +psa_status_t psa_its_get_info(psa_storage_uid_t uid, + struct psa_storage_info_t *p_info); + +/** + * \brief Remove the provided key and its associated data from the storage + * + * \param[in] uid The uid value + * + * \return A status indicating the success/failure of the operation + * + * \retval #PSA_SUCCESS The operation completed successfully + * \retval #PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided key value was + * not found in the storage + * \retval #PSA_ERROR_NOT_PERMITTED The operation failed because the provided key value was + * created with PSA_STORAGE_FLAG_WRITE_ONCE + * \retval #PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has + * failed (Fatal error) + */ +psa_status_t psa_its_remove(psa_storage_uid_t uid); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_ITS_H */ diff --git a/subsys/secure_storage/Kconfig b/subsys/secure_storage/Kconfig index 11e78a7dbd2ce..d229f10a2d579 100644 --- a/subsys/secure_storage/Kconfig +++ b/subsys/secure_storage/Kconfig @@ -3,7 +3,7 @@ menuconfig SECURE_STORAGE bool "Secure storage subsystem" - depends on !BUILD_WITH_TFM + depends on MBEDTLS_PSA_ITS_BACKEND_SECURE_STORAGE select EXPERIMENTAL help The secure storage subsystem provides an implementation of the PSA Secure Storage API diff --git a/tests/subsys/secure_storage/psa/its/src/main.c b/tests/subsys/secure_storage/psa/its/src/main.c index 1fb1b522133eb..0884778c94731 100644 --- a/tests/subsys/secure_storage/psa/its/src/main.c +++ b/tests/subsys/secure_storage/psa/its/src/main.c @@ -7,8 +7,11 @@ /* The flash must be erased after this test suite is run for the write-once entry test to pass. */ ZTEST_SUITE(secure_storage_psa_its, NULL, NULL, NULL, NULL, NULL); -#ifdef CONFIG_SECURE_STORAGE +#if defined(CONFIG_SECURE_STORAGE) #define MAX_DATA_SIZE CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE +#elif defined(CONFIG_MBEDTLS_PSA_ITS_BACKEND_MBEDTLS_FILE) +/* The backend supports arbitrarily large files, limit the value here for array sizes */ +#define MAX_DATA_SIZE 256 #else #define MAX_DATA_SIZE CONFIG_TFM_ITS_MAX_ASSET_SIZE #endif @@ -32,7 +35,7 @@ ZTEST(secure_storage_psa_its, test_all_sizes) fill_data_buffer(written_data); - for (unsigned int i = 0; i <= sizeof(written_data); ++i) { + for (unsigned int i = 1; i <= sizeof(written_data); ++i) { ret = psa_its_set(UID, i, written_data, PSA_STORAGE_FLAG_NONE); zassert_equal(ret, PSA_SUCCESS); @@ -41,9 +44,11 @@ ZTEST(secure_storage_psa_its, test_all_sizes) zassert_equal(ret, PSA_SUCCESS); zassert_equal(info.flags, PSA_STORAGE_FLAG_NONE); zassert_equal(info.size, i); +#ifndef CONFIG_MBEDTLS_PSA_ITS_BACKEND_MBEDTLS_FILE zassert_equal(info.capacity, i); +#endif - ret = psa_its_get(UID, 0, sizeof(read_data), read_data, &data_length); + ret = psa_its_get(UID, 0, i, read_data, &data_length); zassert_equal(ret, PSA_SUCCESS); zassert_equal(data_length, i); zassert_mem_equal(read_data, written_data, data_length); @@ -78,6 +83,14 @@ ZTEST(secure_storage_psa_its, test_all_offsets) ZTEST(secure_storage_psa_its, test_max_num_entries) { + if (IS_ENABLED(CONFIG_MBEDTLS_PSA_ITS_BACKEND_MBEDTLS_FILE)) { + /* The mbedtls file backend will happily fill your hard drive + * with as many entries as you have space. Skip this test. + */ + ztest_test_skip(); + return; + } + psa_status_t ret = PSA_SUCCESS; unsigned int i; struct psa_storage_info_t info; @@ -118,6 +131,12 @@ ZTEST(secure_storage_psa_its, test_write_once_flag) const uint8_t data[MAX_DATA_SIZE] = {}; struct psa_storage_info_t info; + if (IS_ENABLED(CONFIG_MBEDTLS_PSA_ITS_BACKEND_MBEDTLS_FILE)) { + /* The mbedtls file backend does not support this option */ + ztest_test_skip(); + return; + } + ret = psa_its_set(uid, sizeof(data), data, PSA_STORAGE_FLAG_WRITE_ONCE); zassert_equal(ret, PSA_SUCCESS, "%s%d", (ret == PSA_ERROR_NOT_PERMITTED) ? "Has the flash been erased since this test ran? " : "", ret); diff --git a/tests/subsys/secure_storage/psa/its/testcase.yaml b/tests/subsys/secure_storage/psa/its/testcase.yaml index bf72516e4b246..8f6a16070f2f2 100644 --- a/tests/subsys/secure_storage/psa/its/testcase.yaml +++ b/tests/subsys/secure_storage/psa/its/testcase.yaml @@ -52,3 +52,9 @@ tests: integration_platforms: - nrf9151dk/nrf9151/ns extra_args: EXTRA_CONF_FILE=overlay-tfm.conf + + secure_storage.psa.its.mbedtls_file: + platform_allow: + - native_sim + extra_configs: + - CONFIG_MBEDTLS_PSA_ITS_BACKEND_MBEDTLS_FILE=y