diff --git a/subsys/secure_storage/Kconfig.its_store b/subsys/secure_storage/Kconfig.its_store index 9e4d9b65020..99ac19e3757 100644 --- a/subsys/secure_storage/Kconfig.its_store +++ b/subsys/secure_storage/Kconfig.its_store @@ -4,9 +4,26 @@ choice SECURE_STORAGE_ITS_STORE_IMPLEMENTATION prompt "ITS store module implementation" +DT_ITS_PARTITION := $(dt_chosen_path,secure_storage_its_partition) +DT_STORAGE_PARTITION := $(dt_nodelabel_path,storage_partition) + +config SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_ZMS + bool "ITS store module implementation using ZMS for storage" + depends on FLASH_HAS_DRIVER_ENABLED \ + && $(dt_path_enabled,$(DT_ITS_PARTITION)) \ + && $(dt_node_has_compat,$(dt_node_parent,$(DT_ITS_PARTITION)),fixed-partitions) + select ZMS + help + This implementation of the ITS store module makes direct use of ZMS for storage. + It needs a `secure_storage_its_partition` devicetree chosen property that points + to a fixed storage partition that will be dedicated to the ITS. It has lower + overhead compared to the settings-based implementation, both in terms of runtime + execution and storage space, and also ROM footprint if the settings subsystem is disabled. + As this implementations directly maps the PSA storage UIDs to ZMS entry IDs, it limits + their values to the first 30 bits. + config SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_SETTINGS bool "ITS store module implementation using the settings subsystem for storage" - DT_STORAGE_PARTITION := $(dt_nodelabel_path,storage_partition) depends on FLASH_HAS_DRIVER_ENABLED \ && $(dt_path_enabled,$(DT_STORAGE_PARTITION)) \ && $(dt_node_has_compat,$(dt_node_parent,$(DT_STORAGE_PARTITION)),fixed-partitions) @@ -25,6 +42,20 @@ config SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_CUSTOM endchoice # SECURE_STORAGE_ITS_STORE_IMPLEMENTATION +if SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_ZMS + +config SECURE_STORAGE_ITS_STORE_ZMS_SECTOR_SIZE + int "Sector size of the ZMS partition" + default 4096 + help + The sector size impacts the runtime behavior of ZMS and restricts the maximum + ITS entry data size (which is the sector size minus ZMS and ITS overhead). + Changing it will result in loss of existing data stored on a partition. + It must be a multiple of the flash page size on devices that require an erase. + See the ZMS documentation for more information. + +endif # SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_ZMS + if SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_SETTINGS config SECURE_STORAGE_ITS_STORE_SETTINGS_PREFIX diff --git a/subsys/secure_storage/include/internal/zephyr/secure_storage/its/common.h b/subsys/secure_storage/include/internal/zephyr/secure_storage/its/common.h index 4b73eafcf3d..347d96f435e 100644 --- a/subsys/secure_storage/include/internal/zephyr/secure_storage/its/common.h +++ b/subsys/secure_storage/include/internal/zephyr/secure_storage/its/common.h @@ -19,6 +19,7 @@ typedef enum { SECURE_STORAGE_ITS_CALLER_PSA_ITS, SECURE_STORAGE_ITS_CALLER_PSA_PS, SECURE_STORAGE_ITS_CALLER_MBEDTLS, + SECURE_STORAGE_ITS_CALLER_COUNT } secure_storage_its_caller_id_t; /** The UID (caller + entry IDs) of an ITS entry. */ diff --git a/subsys/secure_storage/include/internal/zephyr/secure_storage/its/store.h b/subsys/secure_storage/include/internal/zephyr/secure_storage/its/store.h index fec3448b215..6dbb7a8a3be 100644 --- a/subsys/secure_storage/include/internal/zephyr/secure_storage/its/store.h +++ b/subsys/secure_storage/include/internal/zephyr/secure_storage/its/store.h @@ -19,9 +19,7 @@ * @param data_length The number of bytes in `data`. * @param data The data to store. * - * @retval `PSA_SUCCESS` on success. - * @retval `PSA_ERROR_INSUFFICIENT_STORAGE` if there is insufficient storage space. - * @retval `PSA_ERROR_STORAGE_FAILURE` on any other failure. + * @return One of the return values of `psa_its_set()`. */ psa_status_t secure_storage_its_store_set(secure_storage_its_uid_t uid, size_t data_length, const void *data); @@ -34,9 +32,7 @@ psa_status_t secure_storage_its_store_set(secure_storage_its_uid_t uid, * @param[out] data_length On success, the number of bytes written to `data`. * May be less than `data_size`. * - * @retval `PSA_SUCCESS` on success. - * @retval `PSA_ERROR_DOES_NOT_EXIST` if no entry with the given UID exists. - * @retval `PSA_ERROR_STORAGE_FAILURE` on any other failure. + * @return One of the return values of `psa_its_get()`. */ psa_status_t secure_storage_its_store_get(secure_storage_its_uid_t uid, size_t data_size, void *data, size_t *data_length); diff --git a/subsys/secure_storage/src/its/CMakeLists.txt b/subsys/secure_storage/src/its/CMakeLists.txt index b9e2bb877d9..90340047ff5 100644 --- a/subsys/secure_storage/src/its/CMakeLists.txt +++ b/subsys/secure_storage/src/its/CMakeLists.txt @@ -24,6 +24,9 @@ if (NOT CONFIG_SECURE_STORAGE_ITS_TRANSFORM_AEAD_NO_INSECURE_KEY_WARNING) endif() endif() -zephyr_library_sources_ifdef(CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_SETTINGS - store_settings.c +zephyr_library_sources_ifdef(CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_ZMS + store/zms.c +) +zephyr_library_sources_ifdef(CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_SETTINGS + store/settings.c ) diff --git a/subsys/secure_storage/src/its/store_settings.c b/subsys/secure_storage/src/its/store/settings.c similarity index 100% rename from subsys/secure_storage/src/its/store_settings.c rename to subsys/secure_storage/src/its/store/settings.c diff --git a/subsys/secure_storage/src/its/store/zms.c b/subsys/secure_storage/src/its/store/zms.c new file mode 100644 index 00000000000..a0703e81e72 --- /dev/null +++ b/subsys/secure_storage/src/its/store/zms.c @@ -0,0 +1,122 @@ +/* Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#ifdef CONFIG_SECURE_STORAGE_ITS_IMPLEMENTATION_ZEPHYR +#include +#endif + +LOG_MODULE_DECLARE(secure_storage, CONFIG_SECURE_STORAGE_LOG_LEVEL); + +BUILD_ASSERT(CONFIG_SECURE_STORAGE_ITS_STORE_ZMS_SECTOR_SIZE + > 2 * CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE); + +#define PARTITION_DT_NODE DT_CHOSEN(secure_storage_its_partition) + +static struct zms_fs s_zms = { + .flash_device = FIXED_PARTITION_NODE_DEVICE(PARTITION_DT_NODE), + .offset = FIXED_PARTITION_NODE_OFFSET(PARTITION_DT_NODE), + .sector_size = CONFIG_SECURE_STORAGE_ITS_STORE_ZMS_SECTOR_SIZE, +}; + +static int init_zms(void) +{ + int ret; + + s_zms.sector_count = FIXED_PARTITION_NODE_SIZE(PARTITION_DT_NODE) / s_zms.sector_size; + + ret = zms_mount(&s_zms); + if (ret) { + LOG_DBG("Failed. (%d)", ret); + } + return ret; +} +SYS_INIT(init_zms, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); + +/* Bit position of the ITS caller ID in the ZMS entry ID. */ +#define ITS_CALLER_ID_POS 30 +/* Make sure that every ITS caller ID fits in ZMS entry IDs at the defined position. */ +BUILD_ASSERT(1 << (32 - ITS_CALLER_ID_POS) >= SECURE_STORAGE_ITS_CALLER_COUNT); + +static bool has_forbidden_bits_set(secure_storage_its_uid_t uid) +{ + if (uid.uid & GENMASK64(63, ITS_CALLER_ID_POS)) { + LOG_DBG("UID %u/0x%llx cannot be used as it has bits set past " + "the first " STRINGIFY(ITS_CALLER_ID_POS) " ones.", + uid.caller_id, (unsigned long long)uid.uid); + return true; + } + return false; +} + +static uint32_t zms_id_from(secure_storage_its_uid_t uid) +{ + return (uint32_t)uid.uid | (uid.caller_id << ITS_CALLER_ID_POS); +} + +psa_status_t secure_storage_its_store_set(secure_storage_its_uid_t uid, + size_t data_length, const void *data) +{ + psa_status_t psa_ret; + ssize_t zms_ret; + const uint32_t zms_id = zms_id_from(uid); + + if (has_forbidden_bits_set(uid)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + zms_ret = zms_write(&s_zms, zms_id, data, data_length); + if (zms_ret == data_length) { + psa_ret = PSA_SUCCESS; + } else if (zms_ret == -ENOSPC) { + psa_ret = PSA_ERROR_INSUFFICIENT_STORAGE; + } else { + psa_ret = PSA_ERROR_STORAGE_FAILURE; + } + LOG_DBG("%s 0x%x with %zu bytes. (%zd)", (psa_ret == PSA_SUCCESS) ? + "Wrote" : "Failed to write", zms_id, data_length, zms_ret); + return psa_ret; +} + +psa_status_t secure_storage_its_store_get(secure_storage_its_uid_t uid, size_t data_size, + void *data, size_t *data_length) +{ + psa_status_t psa_ret; + ssize_t zms_ret; + const uint32_t zms_id = zms_id_from(uid); + + if (has_forbidden_bits_set(uid)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + zms_ret = zms_read(&s_zms, zms_id, data, data_size); + if (zms_ret > 0) { + *data_length = zms_ret; + psa_ret = PSA_SUCCESS; + } else if (zms_ret == -ENOENT) { + psa_ret = PSA_ERROR_DOES_NOT_EXIST; + } else { + psa_ret = PSA_ERROR_STORAGE_FAILURE; + } + LOG_DBG("%s 0x%x for up to %zu bytes. (%zd)", (psa_ret != PSA_ERROR_STORAGE_FAILURE) ? + "Read" : "Failed to read", zms_id, data_size, zms_ret); + return psa_ret; +} + +psa_status_t secure_storage_its_store_remove(secure_storage_its_uid_t uid) +{ + int zms_ret; + const uint32_t zms_id = zms_id_from(uid); + + if (has_forbidden_bits_set(uid)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + zms_ret = zms_delete(&s_zms, zms_id); + LOG_DBG("%s 0x%x. (%d)", zms_ret ? "Failed to delete" : "Deleted", zms_id, zms_ret); + BUILD_ASSERT(PSA_SUCCESS == 0); + return zms_ret; +} diff --git a/tests/subsys/secure_storage/psa/its/src/main.c b/tests/subsys/secure_storage/psa/its/src/main.c index d9bab46ba09..1fb1b522133 100644 --- a/tests/subsys/secure_storage/psa/its/src/main.c +++ b/tests/subsys/secure_storage/psa/its/src/main.c @@ -114,7 +114,7 @@ ZTEST(secure_storage_psa_its, test_write_once_flag) { psa_status_t ret; /* Use a UID that isn't used in the other tests for the write-once entry. */ - const psa_storage_uid_t uid = ~UID; + const psa_storage_uid_t uid = 1 << 16; const uint8_t data[MAX_DATA_SIZE] = {}; struct psa_storage_info_t info;