secure_storage: add a ZMS-based implementation of the ITS store module

It becomes the new default when the secure_storage_its_partition
devicetree chosen property is defined as it is a preferred alternative.

See the help message of the
`CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_ZMS` Kconfig option
for more information.

Signed-off-by: Tomi Fontanilles <tomi.fontanilles@nordicsemi.no>
This commit is contained in:
Tomi Fontanilles 2024-11-11 18:04:38 +02:00 committed by Fabio Baltieri
parent d27e4dc463
commit 0ea6f352e7
7 changed files with 163 additions and 10 deletions

View File

@ -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

View File

@ -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. */

View File

@ -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);

View File

@ -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
)

View File

@ -0,0 +1,122 @@
/* Copyright (c) 2024 Nordic Semiconductor
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/secure_storage/its/store.h>
#include <zephyr/logging/log.h>
#include <zephyr/fs/zms.h>
#include <zephyr/storage/flash_map.h>
#ifdef CONFIG_SECURE_STORAGE_ITS_IMPLEMENTATION_ZEPHYR
#include <zephyr/secure_storage/its/transform.h>
#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;
}

View File

@ -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;