From 12317ecc13137f6e14f57c0e19e1d4db231ca9bc Mon Sep 17 00:00:00 2001 From: Marcin Kajor Date: Fri, 19 Apr 2024 11:58:57 +0200 Subject: [PATCH] samples: matter: Secure persistent storage implementation * added abstract PersistentStorage interface * added the reference implementation of the interface * the implementation leverages two independent backends, settings and secure storage * added Kconfigs to allow for the backends to be compiled conditionally (in non mutually exclusive way) * adapted common cmake module * aligned Matter Bridge to use the new interface * fix FiniteMap includes * updated documentation and release notes Signed-off-by: Marcin Kajor --- applications/matter_bridge/CMakeLists.txt | 1 - applications/matter_bridge/Kconfig | 4 + .../getting_started/advanced_kconfigs.rst | 26 +++ .../releases/release-notes-changelog.rst | 8 +- .../matter/common/cmake/source_common.cmake | 7 + samples/matter/common/src/Kconfig | 5 + .../src/bridge/bridge_storage_manager.cpp | 26 +-- .../src/bridge/bridge_storage_manager.h | 7 +- .../common/src/persistent_storage/Kconfig | 34 +++ .../backends/persistent_storage_secure.cpp | 198 ++++++++++++++++++ .../backends/persistent_storage_secure.h | 120 +++++++++++ .../persistent_storage_settings.cpp} | 83 +++----- .../backends/persistent_storage_settings.h | 58 +++++ .../persistent_storage/persistent_storage.h | 163 ++++++++++++++ .../persistent_storage_common.h | 77 +++++++ .../persistent_storage_impl.h | 58 +++++ .../persistent_storage_util.h | 114 ---------- samples/matter/common/src/util/finite_map.h | 25 ++- 18 files changed, 817 insertions(+), 197 deletions(-) create mode 100644 samples/matter/common/src/persistent_storage/Kconfig create mode 100644 samples/matter/common/src/persistent_storage/backends/persistent_storage_secure.cpp create mode 100644 samples/matter/common/src/persistent_storage/backends/persistent_storage_secure.h rename samples/matter/common/src/persistent_storage/{persistent_storage_util.cpp => backends/persistent_storage_settings.cpp} (60%) create mode 100644 samples/matter/common/src/persistent_storage/backends/persistent_storage_settings.h create mode 100644 samples/matter/common/src/persistent_storage/persistent_storage.h create mode 100644 samples/matter/common/src/persistent_storage/persistent_storage_common.h create mode 100644 samples/matter/common/src/persistent_storage/persistent_storage_impl.h delete mode 100644 samples/matter/common/src/persistent_storage/persistent_storage_util.h diff --git a/applications/matter_bridge/CMakeLists.txt b/applications/matter_bridge/CMakeLists.txt index 266e83e752d8..c638eb946d4b 100644 --- a/applications/matter_bridge/CMakeLists.txt +++ b/applications/matter_bridge/CMakeLists.txt @@ -39,7 +39,6 @@ target_sources(app PRIVATE ${ZEPHYR_NRF_MODULE_DIR}/samples/matter/common/src/bridge/bridge_storage_manager.cpp ${ZEPHYR_NRF_MODULE_DIR}/samples/matter/common/src/bridge/bridged_device_data_provider.cpp ${ZEPHYR_NRF_MODULE_DIR}/samples/matter/common/src/binding/binding_handler.cpp - ${ZEPHYR_NRF_MODULE_DIR}/samples/matter/common/src/persistent_storage/persistent_storage_util.cpp ) if(CONFIG_BRIDGED_DEVICE_BT) diff --git a/applications/matter_bridge/Kconfig b/applications/matter_bridge/Kconfig index eae983839c09..212aecdc7f04 100644 --- a/applications/matter_bridge/Kconfig +++ b/applications/matter_bridge/Kconfig @@ -156,8 +156,12 @@ endif config CHIP_ENABLE_READ_CLIENT default y +config NCS_SAMPLE_MATTER_PERSISTENT_STORAGE + default y + source "${ZEPHYR_CONNECTEDHOMEIP_MODULE_DIR}/config/nrfconnect/chip-module/Kconfig.features" source "${ZEPHYR_CONNECTEDHOMEIP_MODULE_DIR}/config/nrfconnect/chip-module/Kconfig.defaults" +source "${ZEPHYR_NRF_MODULE_DIR}/samples/matter/common/src/persistent_storage/Kconfig" source "${ZEPHYR_NRF_MODULE_DIR}/samples/matter/common/src/bridge/Kconfig" source "${ZEPHYR_NRF_MODULE_DIR}/samples/matter/common/src/Kconfig" source "Kconfig.zephyr" diff --git a/doc/nrf/protocols/matter/getting_started/advanced_kconfigs.rst b/doc/nrf/protocols/matter/getting_started/advanced_kconfigs.rst index df44f38d1d4e..12f758b4beda 100644 --- a/doc/nrf/protocols/matter/getting_started/advanced_kconfigs.rst +++ b/doc/nrf/protocols/matter/getting_started/advanced_kconfigs.rst @@ -172,3 +172,29 @@ Read Client functionality The Read Client functionality is used for reading attributes from another device in the Matter network. This functionality is disabled by default for Matter samples in the |NCS|, except for ones that need to read attributes from the bound devices, such as the :ref:`matter_light_switch_sample` and :ref:`matter_thermostat_sample` samples, and the :ref:`matter_bridge_app` application. Enable the feature if your device needs to be able to access attributes from a different device within the Matter network using, for example, bindings. + +Persistent storage +================== + +The persistent storage module allows for the application data and configuration to survive a device reboot. +|NCS| Matter applications use one generic Persistent Storage API that can be enabled by the :kconfig:option:`CONFIG_NCS_SAMPLE_MATTER_PERSISTENT_STORAGE` Kconfig option. +This API consists of methods with ``Secure`` and ``NonSecure`` prefixes, which handle secure (ARM Platform Security Architecture Persistent Storage) and non-secure (raw Zephyr settings) storage operations, respectively. + +You can learn more details about the Persistent Storage API from the :file:`ncs/nrf/samples/matter/common/src/persistent_storage/persistent_storage.h` header file. + +The interface is implemented by two available backends. +Both can be used simultaneously by controlling the following Kconfig options: + +* :kconfig:option:`CONFIG_NCS_SAMPLE_MATTER_SETTINGS_STORAGE_BACKEND` - Activates the implementation that takes advantage of the raw :ref:`Zephyr settings`. + This backend implements ``NonSecure`` methods of the Persistent Storage API and returns ``PSErrorCode::NotSupported`` for ``Secure`` methods. +* :kconfig:option:`CONFIG_NCS_SAMPLE_MATTER_SECURE_STORAGE_BACKEND` - Activates the module based on the ARM PSA Protected Storage API implementation from the :ref:`trusted_storage_readme` |NCS| library. + This backend implements ``Secure`` methods of the Persistent Storage API and returns ``PSErrorCode::NotSupported`` for ``NonSecure`` methods. + +If both backends are activated at the same time (:kconfig:option:`CONFIG_NCS_SAMPLE_MATTER_SETTINGS_STORAGE_BACKEND` and :kconfig:option:`CONFIG_NCS_SAMPLE_MATTER_SECURE_STORAGE_BACKEND` enabled) all methods of the generic interface are supported. + +Similarly to the non-secure backend, the secure backend leverages the Zephyr Settings to interface with the FLASH memory. + +Additionally, in case of the secure storage backend, the following Kconfig options control the storage limits: + +* :kconfig:option:`CONFIG_NCS_SAMPLE_MATTER_SECURE_STORAGE_MAX_ENTRY_NUMBER` - Defines the maximum number or assets that can be stored in the secure storage. +* :kconfig:option:`CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_MAX_DATA_SIZE` - Defines the maximum length of the secret that is stored. diff --git a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst index 76407d94c3e9..820ff94a49c8 100644 --- a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst +++ b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst @@ -94,7 +94,11 @@ Bluetooth Mesh Matter ------ -* Added support for merging the generated factory data HEX file with the firmware HEX file by using the devicetree configuration, when Partition Manager is not enabled in the project. +* Added: + + * Support for merging the generated factory data HEX file with the firmware HEX file by using the devicetree configuration, when Partition Manager is not enabled in the project. + * Support for the unified Persistent Storage API, including the implementation of the PSA Persistent Storage. + * Updated default MRP retry intervals for Thread devices to two seconds to reduce the number of spurious retransmissions in Thread networks. Matter fork @@ -219,6 +223,8 @@ Matter Bridge The :kconfig:option:`CONFIG_BRIDGE_BT_MAX_SCANNED_DEVICES` kconfig option to set the maximum number of scanned Bluetooth LE devices. The :kconfig:option:`CONFIG_BRIDGE_BT_SCAN_TIMEOUT_MS` kconfig option to set the scan timeout. +* Updated the implementation of the persistent storage to leverage ``NonSecure``-prefixed methods from the common Persistent Storage module. + IPC radio firmware ------------------ diff --git a/samples/matter/common/cmake/source_common.cmake b/samples/matter/common/cmake/source_common.cmake index e5d2dab186a8..c5a2b61a87ee 100644 --- a/samples/matter/common/cmake/source_common.cmake +++ b/samples/matter/common/cmake/source_common.cmake @@ -51,3 +51,10 @@ if(CONFIG_NCS_SAMPLE_MATTER_TEST_EVENT_TRIGGERS) target_sources(app PRIVATE ${MATTER_COMMONS_SRC_DIR}/event_triggers/default_event_triggers.cpp) endif() endif() + +if(CONFIG_NCS_SAMPLE_MATTER_PERSISTENT_STORAGE) + target_sources_ifdef(CONFIG_NCS_SAMPLE_MATTER_SETTINGS_STORAGE_BACKEND app PRIVATE + ${MATTER_COMMONS_SRC_DIR}/persistent_storage/backends/persistent_storage_settings.cpp) + target_sources_ifdef(CONFIG_NCS_SAMPLE_MATTER_SECURE_STORAGE_BACKEND app PRIVATE + ${MATTER_COMMONS_SRC_DIR}/persistent_storage/backends/persistent_storage_secure.cpp) +endif() diff --git a/samples/matter/common/src/Kconfig b/samples/matter/common/src/Kconfig index 42167a6fa9ae..2d76f4b9c74c 100644 --- a/samples/matter/common/src/Kconfig +++ b/samples/matter/common/src/Kconfig @@ -82,3 +82,8 @@ config NCS_SAMPLE_MATTER_TEST_EVENT_TRIGGERS_MAX_TRIGGERS_DELEGATES help Defines the maximum number for the TestEventTriggerDelegate implementations to be registered in the nRF test event triggers class. + +config NCS_SAMPLE_MATTER_PERSISTENT_STORAGE + bool "Persistent storage support for Matter samples" + help + Matter persistent storage support with the configurable backend. diff --git a/samples/matter/common/src/bridge/bridge_storage_manager.cpp b/samples/matter/common/src/bridge/bridge_storage_manager.cpp index 922e8cb99c48..98b9f41575aa 100644 --- a/samples/matter/common/src/bridge/bridge_storage_manager.cpp +++ b/samples/matter/common/src/bridge/bridge_storage_manager.cpp @@ -12,7 +12,7 @@ template bool LoadDataToObject(Nrf::PersistentStorageNode *node, T &da { size_t readSize = 0; - bool result = Nrf::PersistentStorage::Instance().Load(node, &data, sizeof(T), readSize); + bool result = Nrf::GetPersistentStorage().NonSecureLoad(node, &data, sizeof(T), readSize); return result; } @@ -32,7 +32,7 @@ namespace Nrf { bool BridgeStorageManager::StoreBridgedDevicesCount(uint8_t count) { - return Nrf::PersistentStorage::Instance().Store(&mBridgedDevicesCount, &count, sizeof(count)); + return Nrf::GetPersistentStorage().NonSecureStore(&mBridgedDevicesCount, &count, sizeof(count)); } bool BridgeStorageManager::LoadBridgedDevicesCount(uint8_t &count) @@ -46,7 +46,7 @@ bool BridgeStorageManager::StoreBridgedDevicesIndexes(uint8_t *indexes, uint8_t return false; } - return Nrf::PersistentStorage::Instance().Store(&mBridgedDevicesIndexes, indexes, count); + return Nrf::GetPersistentStorage().NonSecureStore(&mBridgedDevicesIndexes, indexes, count); } bool BridgeStorageManager::LoadBridgedDevicesIndexes(uint8_t *indexes, uint8_t maxCount, size_t &count) @@ -55,14 +55,14 @@ bool BridgeStorageManager::LoadBridgedDevicesIndexes(uint8_t *indexes, uint8_t m return false; } - return Nrf::PersistentStorage::Instance().Load(&mBridgedDevicesIndexes, indexes, maxCount, count); + return Nrf::GetPersistentStorage().NonSecureLoad(&mBridgedDevicesIndexes, indexes, maxCount, count); } bool BridgeStorageManager::StoreBridgedDeviceEndpointId(uint16_t endpointId, uint8_t bridgedDeviceIndex) { Nrf::PersistentStorageNode id = CreateIndexNode(bridgedDeviceIndex, &mBridgedDeviceEndpointId); - return Nrf::PersistentStorage::Instance().Store(&id, &endpointId, sizeof(endpointId)); + return Nrf::GetPersistentStorage().NonSecureStore(&id, &endpointId, sizeof(endpointId)); } bool BridgeStorageManager::LoadBridgedDeviceEndpointId(uint16_t &endpointId, uint8_t bridgedDeviceIndex) @@ -76,7 +76,7 @@ bool BridgeStorageManager::RemoveBridgedDeviceEndpointId(uint8_t bridgedDeviceIn { Nrf::PersistentStorageNode id = CreateIndexNode(bridgedDeviceIndex, &mBridgedDeviceEndpointId); - return Nrf::PersistentStorage::Instance().Remove(&id); + return Nrf::GetPersistentStorage().NonSecureRemove(&id); } bool BridgeStorageManager::StoreBridgedDeviceNodeLabel(const char *label, size_t labelLength, @@ -84,7 +84,7 @@ bool BridgeStorageManager::StoreBridgedDeviceNodeLabel(const char *label, size_t { Nrf::PersistentStorageNode id = CreateIndexNode(bridgedDeviceIndex, &mBridgedDeviceNodeLabel); - return Nrf::PersistentStorage::Instance().Store(&id, label, labelLength); + return Nrf::GetPersistentStorage().NonSecureStore(&id, label, labelLength); } bool BridgeStorageManager::LoadBridgedDeviceNodeLabel(char *label, size_t labelMaxLength, size_t &labelLength, @@ -92,21 +92,21 @@ bool BridgeStorageManager::LoadBridgedDeviceNodeLabel(char *label, size_t labelM { Nrf::PersistentStorageNode id = CreateIndexNode(bridgedDeviceIndex, &mBridgedDeviceNodeLabel); - return Nrf::PersistentStorage::Instance().Load(&id, label, labelMaxLength, labelLength); + return Nrf::GetPersistentStorage().NonSecureLoad(&id, label, labelMaxLength, labelLength); } bool BridgeStorageManager::RemoveBridgedDeviceNodeLabel(uint8_t bridgedDeviceIndex) { Nrf::PersistentStorageNode id = CreateIndexNode(bridgedDeviceIndex, &mBridgedDeviceNodeLabel); - return Nrf::PersistentStorage::Instance().Remove(&id); + return Nrf::GetPersistentStorage().NonSecureRemove(&id); } bool BridgeStorageManager::StoreBridgedDeviceType(uint16_t deviceType, uint8_t bridgedDeviceIndex) { Nrf::PersistentStorageNode id = CreateIndexNode(bridgedDeviceIndex, &mBridgedDeviceType); - return Nrf::PersistentStorage::Instance().Store(&id, &deviceType, sizeof(deviceType)); + return Nrf::GetPersistentStorage().NonSecureStore(&id, &deviceType, sizeof(deviceType)); } bool BridgeStorageManager::LoadBridgedDeviceType(uint16_t &deviceType, uint8_t bridgedDeviceIndex) @@ -120,7 +120,7 @@ bool BridgeStorageManager::RemoveBridgedDeviceType(uint8_t bridgedDeviceIndex) { Nrf::PersistentStorageNode id = CreateIndexNode(bridgedDeviceIndex, &mBridgedDeviceType); - return Nrf::PersistentStorage::Instance().Remove(&id); + return Nrf::GetPersistentStorage().NonSecureRemove(&id); } bool BridgeStorageManager::StoreBridgedDevice(const MatterBridgedDevice *device, uint8_t index) @@ -145,7 +145,7 @@ bool BridgeStorageManager::StoreBtAddress(bt_addr_le_t addr, uint8_t bridgedDevi { Nrf::PersistentStorageNode id = CreateIndexNode(bridgedDeviceIndex, &mBtAddress); - return Nrf::PersistentStorage::Instance().Store(&id, &addr, sizeof(addr)); + return Nrf::GetPersistentStorage().NonSecureStore(&id, &addr, sizeof(addr)); } bool BridgeStorageManager::LoadBtAddress(bt_addr_le_t &addr, uint8_t bridgedDeviceIndex) @@ -159,7 +159,7 @@ bool BridgeStorageManager::RemoveBtAddress(uint8_t bridgedDeviceIndex) { Nrf::PersistentStorageNode id = CreateIndexNode(bridgedDeviceIndex, &mBtAddress); - return Nrf::PersistentStorage::Instance().Remove(&id); + return Nrf::GetPersistentStorage().NonSecureRemove(&id); } #endif diff --git a/samples/matter/common/src/bridge/bridge_storage_manager.h b/samples/matter/common/src/bridge/bridge_storage_manager.h index c8f60cf3d3b4..6572dd9d87bf 100644 --- a/samples/matter/common/src/bridge/bridge_storage_manager.h +++ b/samples/matter/common/src/bridge/bridge_storage_manager.h @@ -7,13 +7,14 @@ #pragma once #include "matter_bridged_device.h" -#include "persistent_storage/persistent_storage_util.h" +#include "persistent_storage/persistent_storage.h" #ifdef CONFIG_BRIDGED_DEVICE_BT #include #endif -namespace Nrf { +namespace Nrf +{ /* * The class implements the following key-values storage structure: @@ -78,7 +79,7 @@ class BridgeStorageManager { * @return true if module has been initialized successfully * @return false an error occurred */ - bool Init() { return Nrf::PersistentStorage::Instance().Init(); } + bool Init() { return Nrf::GetPersistentStorage().NonSecureInit(); } /** * @brief Store bridged devices count into settings diff --git a/samples/matter/common/src/persistent_storage/Kconfig b/samples/matter/common/src/persistent_storage/Kconfig new file mode 100644 index 000000000000..623014b1257e --- /dev/null +++ b/samples/matter/common/src/persistent_storage/Kconfig @@ -0,0 +1,34 @@ +# +# Copyright (c) 2024 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +if NCS_SAMPLE_MATTER_PERSISTENT_STORAGE + +config NCS_SAMPLE_MATTER_SETTINGS_STORAGE_BACKEND + bool "Settings based storage implementation for Matter samples" + depends on SETTINGS + default y + +config NCS_SAMPLE_MATTER_SECURE_STORAGE_BACKEND + bool "Secure storage implementation for Matter samples" + select TRUSTED_STORAGE + select PSA_PROTECTED_STORAGE + +if NCS_SAMPLE_MATTER_SECURE_STORAGE_BACKEND + +config NCS_SAMPLE_MATTER_SECURE_STORAGE_MAX_ENTRY_NUMBER + int "Maximum number of entries that can be stored securely" + default 30 + +config NCS_SAMPLE_MATTER_SECURE_STORAGE_PSA_KEY_VALUE_OFFSET + hex "The PSA key offset dedicated for Matter application" + default 0x40000 + +config TRUSTED_STORAGE_BACKEND_AEAD_MAX_DATA_SIZE + default 1024 + +endif + +endif diff --git a/samples/matter/common/src/persistent_storage/backends/persistent_storage_secure.cpp b/samples/matter/common/src/persistent_storage/backends/persistent_storage_secure.cpp new file mode 100644 index 000000000000..4de71f76fa32 --- /dev/null +++ b/samples/matter/common/src/persistent_storage/backends/persistent_storage_secure.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "persistent_storage_secure.h" + +namespace Nrf +{ + +PersistentStorageSecure::UidMap PersistentStorageSecure::sUidMap{}; +PersistentStorageSecure::Byte PersistentStorageSecure::sSerializedMapBuff[kMaxMapSerializationBufferSize]{}; + +PSErrorCode PersistentStorageSecure::_SecureInit() +{ + return LoadUIDMap(); +} + +PSErrorCode PersistentStorageSecure::_SecureStore(PersistentStorageNode *node, const void *data, size_t dataSize) +{ + /* Check if we can store more assets and return prematurely if the limit has been already reached. */ + if (kMaxEntriesNumber <= sUidMap.Size()) { + return PSErrorCode::Failure; + } + + char key[PersistentStorageNode::kMaxKeyNameLength]; + + if (node->GetKey(key)) { + psa_storage_uid_t uid = UIDFromString(key); + psa_status_t status = psa_ps_set(uid, dataSize, data, PSA_STORAGE_FLAG_NONE); + + if (status == PSA_SUCCESS) { + if (sUidMap.Insert(uid, StringWrapper(key))) { + /* The map has been updated, store it. */ + if (PSErrorCode::Success != StoreUIDMap()) { + /* We cannot store the updated UID map, so it's pointless to keep the data + * associated with calculated UID persistently. */ + psa_ps_remove(uid); + } else { + return PSErrorCode::Success; + } + } + /* It fine for the Insert() to fail, in case the given key is already present in the map. */ + return PSErrorCode::Success; + } + } + return PSErrorCode::Failure; +} + +PSErrorCode PersistentStorageSecure::_SecureLoad(PersistentStorageNode *node, void *data, size_t dataMaxSize, + size_t &outSize) +{ + psa_storage_uid_t uid; + if (HasEntry(node, uid)) { + psa_status_t status = psa_ps_get(uid, 0, dataMaxSize, data, &outSize); + return (status == PSA_SUCCESS ? PSErrorCode::Success : PSErrorCode::Failure); + } + return PSErrorCode::Failure; +} + +PSErrorCode PersistentStorageSecure::_SecureHasEntry(PersistentStorageNode *node) +{ + psa_storage_uid_t uid; + return (HasEntry(node, uid) ? PSErrorCode::Success : PSErrorCode::Failure); +} + +PSErrorCode PersistentStorageSecure::_SecureRemove(PersistentStorageNode *node) +{ + char key[PersistentStorageNode::kMaxKeyNameLength]; + + if (node->GetKey(key)) { + bool alreadyInTheMap{ false }; + psa_storage_uid_t uid = UIDFromString(key, &alreadyInTheMap); + if (!alreadyInTheMap) { + psa_status_t status = psa_ps_remove(uid); + + if (status == PSA_SUCCESS) { + sUidMap.Erase(uid); + return PSErrorCode::Success; + } + } + } + + return PSErrorCode::Failure; +} + +psa_storage_uid_t PersistentStorageSecure::UIDFromString(char *str, bool *alreadyInTheMap) +{ + for (auto &it : sUidMap.mMap) { + if (it.value == str) { + if (alreadyInTheMap) { + *alreadyInTheMap = true; + } + return static_cast(it.key); + } + } + + /* The first available UID under kKeyOffset is reserved for the UID Map, so we need to include that when storing + * regular keys by adding kMapUidRelativeOffset. */ + uint16_t slot = sUidMap.GetFirstFreeSlot(); + if (alreadyInTheMap) { + *alreadyInTheMap = false; + } + return static_cast(slot + kKeyOffset + kMapUidRelativeOffset); +} + +PSErrorCode PersistentStorageSecure::StoreUIDMap() +{ + size_t outSize{ 0 }; + if (PSErrorCode::Success == SerializeUIDMap(sSerializedMapBuff, kMaxMapSerializationBufferSize, outSize)) { + psa_status_t status = psa_ps_set(kKeyOffset, outSize, sSerializedMapBuff, PSA_STORAGE_FLAG_NONE); + if (status == PSA_SUCCESS) { + return PSErrorCode::Success; + } + } + return PSErrorCode::Failure; +} + +PSErrorCode PersistentStorageSecure::SerializeUIDMap(Byte *buff, size_t buffSize, size_t &outSize) +{ + size_t keySize{ sizeof(SerializedUIDType) }; + size_t valueSize{ 0 }; + UidMap::ElementCounterType offset{ 0 }; + UidMap::ElementCounterType mapSize = sUidMap.Size(); + + if (buffSize < kMaxMapSerializationBufferSize) { + return PSErrorCode::Failure; + } + + memcpy(buff + offset, &mapSize, sizeof(mapSize)); + offset += sizeof(mapSize); + + for (auto it = std::begin(sUidMap.mMap); it != std::end(sUidMap.mMap) - sUidMap.FreeSlots(); ++it) { + valueSize = strlen(it->value.mStr) + 1; + SerializedUIDType keyToSerialize = static_cast(it->key); + memcpy(buff + offset, &keyToSerialize, keySize); + offset += keySize; + memcpy(buff + offset, it->value.mStr, valueSize); + offset += valueSize; + } + outSize = offset; + return PSErrorCode::Success; +} + +PSErrorCode PersistentStorageSecure::LoadUIDMap() +{ + size_t outSize{ 0 }; + + psa_status_t status = psa_ps_get(kKeyOffset, 0, kMaxMapSerializationBufferSize, sSerializedMapBuff, &outSize); + + if (status == PSA_SUCCESS) { + if (PSErrorCode::Success == DeserializeUIDMap(sSerializedMapBuff, kMaxMapSerializationBufferSize)) { + return PSErrorCode::Success; + } + } + return PSErrorCode::Failure; +} + +PSErrorCode PersistentStorageSecure::DeserializeUIDMap(const Byte *buff, size_t buffSize) +{ + UidMap::ElementCounterType mapSize{ 0 }; + UidMap::ElementCounterType offset{ 0 }; + SerializedUIDType key{ 0 }; + char value[PersistentStorageNode::kMaxKeyNameLength] = { 0 }; + + memcpy(&mapSize, buff + offset, sizeof(mapSize)); + offset += sizeof(mapSize); + + for (uint16_t element = 0; element < mapSize; ++element) { + memcpy(&key, buff + offset, sizeof(key)); + offset += sizeof(key); + strcpy(value, buff + offset); + offset += strlen(value) + 1; + sUidMap.Insert(static_cast(key), StringWrapper(value)); + } + + /* The stored size shall equal the resulting size. */ + if (sUidMap.Size() != mapSize) { + return PSErrorCode::Failure; + } + + return PSErrorCode::Success; +} + +bool PersistentStorageSecure::HasEntry(PersistentStorageNode *node, psa_storage_uid_t &uid) +{ + char key[PersistentStorageNode::kMaxKeyNameLength]; + bool alreadyInTheMap{ false }; + + if (node->GetKey(key)) { + uid = UIDFromString(key, &alreadyInTheMap); + } + + return alreadyInTheMap; +} + +} /* namespace Nrf */ diff --git a/samples/matter/common/src/persistent_storage/backends/persistent_storage_secure.h b/samples/matter/common/src/persistent_storage/backends/persistent_storage_secure.h new file mode 100644 index 000000000000..7592c3f92e8e --- /dev/null +++ b/samples/matter/common/src/persistent_storage/backends/persistent_storage_secure.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include "../persistent_storage_common.h" +#include "finite_map.h" + +#include + +namespace Nrf +{ +class PersistentStorageSecure { +protected: + PSErrorCode _NonSecureInit(); + PSErrorCode _NonSecureStore(PersistentStorageNode *node, const void *data, size_t dataSize); + PSErrorCode _NonSecureLoad(PersistentStorageNode *node, void *data, size_t dataMaxSize, size_t &outSize); + PSErrorCode _NonSecureHasEntry(PersistentStorageNode *node); + PSErrorCode _NonSecureRemove(PersistentStorageNode *node); + + PSErrorCode _SecureInit(); + PSErrorCode _SecureStore(PersistentStorageNode *node, const void *data, size_t dataSize); + PSErrorCode _SecureLoad(PersistentStorageNode *node, void *data, size_t dataMaxSize, size_t &outSize); + PSErrorCode _SecureHasEntry(PersistentStorageNode *node); + PSErrorCode _SecureRemove(PersistentStorageNode *node); + +private: + static constexpr size_t kMaxEntriesNumber = CONFIG_NCS_SAMPLE_MATTER_SECURE_STORAGE_MAX_ENTRY_NUMBER; + static constexpr psa_storage_uid_t kKeyOffset = CONFIG_NCS_SAMPLE_MATTER_SECURE_STORAGE_PSA_KEY_VALUE_OFFSET; + static constexpr uint8_t kMapUidRelativeOffset = 1; + + /* Needed to interface with FiniteMap. */ + struct StringWrapper { + static constexpr auto kSize = PersistentStorageNode::kMaxKeyNameLength; + StringWrapper() {} + StringWrapper(char *str) { strcpy(mStr, str); } + + ~StringWrapper() {} + + /* Disable copy semantics and implement move semantics. */ + StringWrapper(const StringWrapper &other) = delete; + StringWrapper &operator=(const StringWrapper &other) = delete; + + StringWrapper(StringWrapper &&other) + { + strcpy(mStr, other.mStr); + other.Clear(); + } + + StringWrapper &operator=(StringWrapper &&other) + { + if (this != &other) { + this->Clear(); + strcpy(mStr, other.mStr); + other.Clear(); + } + return *this; + } + + operator bool() const { return !strcmp(mStr, ""); } + /* This will work also when comparing against a raw string. */ + bool operator==(const StringWrapper &other) { return (strcmp(mStr, other.mStr) == 0); } + + void Clear() { memset(mStr, 0, kSize); } + + char mStr[kSize] = { 0 }; + }; + + using UidMap = FiniteMap; + using Byte = char; + /* We have the range of the UID [0x40000, 40000 + kMaxEntriesNumber], so 4 bytes is enough to store it. + Note that psa_storage_uid_t is 8 byte long.*/ + using SerializedUIDType = uint32_t; + + static PSErrorCode SerializeUIDMap(Byte *buff, size_t buffSize, size_t &outSize); + static PSErrorCode DeserializeUIDMap(const Byte *buff, size_t buffSize); + static PSErrorCode StoreUIDMap(); + static PSErrorCode LoadUIDMap(); + static bool HasEntry(PersistentStorageNode *node, psa_storage_uid_t &uid); + static psa_storage_uid_t UIDFromString(char *str, bool *alreadyInTheMap = nullptr); + + static constexpr size_t kMaxMapSerializationBufferSize = + (PersistentStorageNode::kMaxKeyNameLength + sizeof(SerializedUIDType)) * kMaxEntriesNumber + + sizeof(UidMap::ElementCounterType); + + static UidMap sUidMap; + static Byte sSerializedMapBuff[kMaxMapSerializationBufferSize]; +}; + +inline PSErrorCode PersistentStorageSecure::_NonSecureInit() +{ + return PSErrorCode::NotSupported; +}; + +inline PSErrorCode PersistentStorageSecure::_NonSecureStore(PersistentStorageNode *node, const void *data, + size_t dataSize) +{ + return PSErrorCode::NotSupported; +} + +inline PSErrorCode PersistentStorageSecure::_NonSecureLoad(PersistentStorageNode *node, void *data, size_t dataMaxSize, + size_t &outSize) +{ + return PSErrorCode::NotSupported; +} + +inline PSErrorCode PersistentStorageSecure::_NonSecureHasEntry(PersistentStorageNode *node) +{ + return PSErrorCode::NotSupported; +} + +inline PSErrorCode PersistentStorageSecure::_NonSecureRemove(PersistentStorageNode *node) +{ + return PSErrorCode::NotSupported; +} + +} /* namespace Nrf */ diff --git a/samples/matter/common/src/persistent_storage/persistent_storage_util.cpp b/samples/matter/common/src/persistent_storage/backends/persistent_storage_settings.cpp similarity index 60% rename from samples/matter/common/src/persistent_storage/persistent_storage_util.cpp rename to samples/matter/common/src/persistent_storage/backends/persistent_storage_settings.cpp index c300dc087687..2de6e224e846 100644 --- a/samples/matter/common/src/persistent_storage/persistent_storage_util.cpp +++ b/samples/matter/common/src/persistent_storage/backends/persistent_storage_settings.cpp @@ -1,12 +1,13 @@ /* - * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ -#include "persistent_storage_util.h" +#include "persistent_storage_settings.h" #include +#include LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); @@ -20,8 +21,7 @@ struct ReadEntry { }; /* Random magic bytes to represent an empty value. - It is needed because Zephyr settings subsystem does not distinguish an empty value from no value. -*/ + It is needed because Zephyr settings subsystem does not distinguish an empty value from no value. */ constexpr uint8_t kEmptyValue[] = { 0x22, 0xa6, 0x54, 0xd1, 0x39 }; constexpr size_t kEmptyValueSize = sizeof(kEmptyValue); @@ -63,38 +63,39 @@ int LoadEntryCallback(const char *name, size_t entrySize, settings_read_cb readC } } /* namespace */ -namespace Nrf { - -bool PersistentStorage::Init() +namespace Nrf +{ +PSErrorCode PersistentStorageSettings::_NonSecureInit() { - return settings_load() ? false : true; + return settings_load() ? PSErrorCode::Failure : PSErrorCode::Success; } -bool PersistentStorage::Store(PersistentStorageNode *node, const void *data, size_t dataSize) +PSErrorCode PersistentStorageSettings::_NonSecureStore(PersistentStorageNode *node, const void *data, size_t dataSize) { if (!data || !node) { - return false; + return PSErrorCode::Failure; } char key[PersistentStorageNode::kMaxKeyNameLength]; if (!node->GetKey(key)) { - return false; + return PSErrorCode::Failure; } - return (0 == settings_save_one(key, data, dataSize)); + return (settings_save_one(key, data, dataSize) ? PSErrorCode::Failure : PSErrorCode::Success); } -bool PersistentStorage::Load(PersistentStorageNode *node, void *data, size_t dataMaxSize, size_t &outSize) +PSErrorCode PersistentStorageSettings::_NonSecureLoad(PersistentStorageNode *node, void *data, size_t dataMaxSize, + size_t &outSize) { if (!data || !node) { - return false; + return PSErrorCode::Failure; } char key[PersistentStorageNode::kMaxKeyNameLength]; if (!node->GetKey(key)) { - return false; + return PSErrorCode::Failure; } size_t resultSize; @@ -105,46 +106,46 @@ bool PersistentStorage::Load(PersistentStorageNode *node, void *data, size_t dat outSize = resultSize; } - return result; + return (result ? PSErrorCode::Success : PSErrorCode::Failure); } -bool PersistentStorage::HasEntry(PersistentStorageNode *node) +PSErrorCode PersistentStorageSettings::_NonSecureHasEntry(PersistentStorageNode *node) { if (!node) { - return false; + return PSErrorCode::Failure; } char key[PersistentStorageNode::kMaxKeyNameLength]; if (!node->GetKey(key)) { - return false; + return PSErrorCode::Failure; } - return LoadEntry(key); + return (LoadEntry(key) ? PSErrorCode::Success : PSErrorCode::Failure); } -bool PersistentStorage::Remove(PersistentStorageNode *node) +PSErrorCode PersistentStorageSettings::_NonSecureRemove(PersistentStorageNode *node) { if (!node) { - return false; + return PSErrorCode::Failure; } char key[PersistentStorageNode::kMaxKeyNameLength]; if (!node->GetKey(key)) { - return false; + return PSErrorCode::Failure; } if (!LoadEntry(key)) { - return false; + return PSErrorCode::Failure; } settings_delete(key); - return true; + return PSErrorCode::Success; } -bool PersistentStorage::LoadEntry(const char *key, void *data, size_t dataMaxSize, size_t *outSize) +bool PersistentStorageSettings::LoadEntry(const char *key, void *data, size_t dataMaxSize, size_t *outSize) { ReadEntry entry{ data, dataMaxSize, 0, false }; settings_load_subtree_direct(key, LoadEntryCallback, &entry); @@ -159,34 +160,4 @@ bool PersistentStorage::LoadEntry(const char *key, void *data, size_t dataMaxSiz return true; } - -bool PersistentStorageNode::GetKey(char *key) -{ - if (!key || mKeyName[0] == '\0') { - return false; - } - - /* Recursively call GetKey method for the parents until the full key name including all hierarchy levels will be - * created. */ - if (mParent != nullptr) { - char parentKey[kMaxKeyNameLength]; - - if (!mParent->GetKey(parentKey)) { - return false; - } - - int result = snprintf(key, kMaxKeyNameLength, "%s/%s", parentKey, mKeyName); - - if (result < 0 || result >= kMaxKeyNameLength) { - return false; - } - - } else { - /* In case of not having a parent, return only own key name. */ - strncpy(key, mKeyName, kMaxKeyNameLength); - } - - return true; -} - } /* namespace Nrf */ diff --git a/samples/matter/common/src/persistent_storage/backends/persistent_storage_settings.h b/samples/matter/common/src/persistent_storage/backends/persistent_storage_settings.h new file mode 100644 index 000000000000..824783bf212d --- /dev/null +++ b/samples/matter/common/src/persistent_storage/backends/persistent_storage_settings.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include "../persistent_storage_common.h" + +namespace Nrf +{ +class PersistentStorageSettings { +protected: + PSErrorCode _NonSecureInit(); + PSErrorCode _NonSecureStore(PersistentStorageNode *node, const void *data, size_t dataSize); + PSErrorCode _NonSecureLoad(PersistentStorageNode *node, void *data, size_t dataMaxSize, size_t &outSize); + PSErrorCode _NonSecureHasEntry(PersistentStorageNode *node); + PSErrorCode _NonSecureRemove(PersistentStorageNode *node); + + PSErrorCode _SecureInit(); + PSErrorCode _SecureStore(PersistentStorageNode *node, const void *data, size_t dataSize); + PSErrorCode _SecureLoad(PersistentStorageNode *node, void *data, size_t dataMaxSize, size_t &outSize); + PSErrorCode _SecureHasEntry(PersistentStorageNode *node); + PSErrorCode _SecureRemove(PersistentStorageNode *node); + +private: + bool LoadEntry(const char *key, void *data = nullptr, size_t dataMaxSize = 0, size_t *outSize = nullptr); +}; + +inline PSErrorCode PersistentStorageSettings::_SecureInit() +{ + return PSErrorCode::NotSupported; +}; + +inline PSErrorCode PersistentStorageSettings::_SecureStore(PersistentStorageNode *node, const void *data, + size_t dataSize) +{ + return PSErrorCode::NotSupported; +} + +inline PSErrorCode PersistentStorageSettings::_SecureLoad(PersistentStorageNode *node, void *data, size_t dataMaxSize, + size_t &outSize) +{ + return PSErrorCode::NotSupported; +} + +inline PSErrorCode PersistentStorageSettings::_SecureHasEntry(PersistentStorageNode *node) +{ + return PSErrorCode::NotSupported; +} + +inline PSErrorCode PersistentStorageSettings::_SecureRemove(PersistentStorageNode *node) +{ + return PSErrorCode::NotSupported; +} + +} /* namespace Nrf */ diff --git a/samples/matter/common/src/persistent_storage/persistent_storage.h b/samples/matter/common/src/persistent_storage/persistent_storage.h new file mode 100644 index 000000000000..d4f65bba3f97 --- /dev/null +++ b/samples/matter/common/src/persistent_storage/persistent_storage.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include "persistent_storage_common.h" + +namespace Nrf +{ + +class PersistentStorageImpl; + +/** + * @brief Interface class to manage persistent storage using generic PersistentStorageNode data unit. + * + * PersistentStorage interface consists of NonSecure* and Secure* methods that implement the persistence related + * operations. The NonSecure* prefix indicates that the method does not provide additional security layer and keeps the + * raw material in a persistent storage. Secure* prefix indicates that the method shall leverage the additional security + * layer, like PSA Certified API, that typically causes extra computational overhead and memory usage. + */ +class PersistentStorage { +public: + /** + * @brief Perform the initialization required before using the storage. + * + * @return true if success. + * @return false otherwise. + */ + PSErrorCode NonSecureInit(); + + /** + * @brief Store data into the persistent storage. + * + * @param node address of the tree node containing information about the key. + * @param data data to store into a specific key. + * @param dataSize a size of input buffer. + * @return true if key has been written successfully. + * @return false an error occurred. + */ + PSErrorCode NonSecureStore(PersistentStorageNode *node, const void *data, size_t dataSize); + + /** + * @brief Load data from the persistent storage. + * + * @param node address of the tree node containing information about the key. + * @param data data buffer to load from a specific key. + * @param dataMaxSize a size of data buffer to load. + * @param outSize an actual size of read data. + * @return true if key has been loaded successfully. + * @return false an error occurred. + */ + PSErrorCode NonSecureLoad(PersistentStorageNode *node, void *data, size_t dataMaxSize, size_t &outSize); + + /** + * @brief Check if given key entry exists in the persistent storage. + * + * @param node address of the tree node containing information about the key. + * @return true if key entry exists. + * @return false if key entry does not exist. + */ + PSErrorCode NonSecureHasEntry(PersistentStorageNode *node); + + /** + * @brief Remove given key entry from the persistent storage. + * + * @param node address of the tree node containing information about the key. + * @return true if key entry has been removed successfully. + * @return false an error occurred. + */ + PSErrorCode NonSecureRemove(PersistentStorageNode *node); + + /* Secure storage API counterparts.*/ + PSErrorCode SecureInit(); + PSErrorCode SecureStore(PersistentStorageNode *node, const void *data, size_t dataSize); + PSErrorCode SecureLoad(PersistentStorageNode *node, void *data, size_t dataMaxSize, size_t &outSize); + PSErrorCode SecureHasEntry(PersistentStorageNode *node); + PSErrorCode SecureRemove(PersistentStorageNode *node); + +protected: + PersistentStorage() = default; + ~PersistentStorage() = default; + + PersistentStorage(const PersistentStorage &) = delete; + PersistentStorage(PersistentStorage &&) = delete; + PersistentStorage &operator=(const PersistentStorage &) = delete; + PersistentStorage &operator=(PersistentStorage &&) = delete; + +private: + PersistentStorageImpl *Impl(); +}; + +/* This should be defined by the implementation class. */ +extern PersistentStorage &GetPersistentStorage(); + +} /* namespace Nrf */ + +#include "persistent_storage_impl.h" +namespace Nrf +{ + +inline PersistentStorageImpl *PersistentStorage::Impl() +{ + return static_cast(this); +} + +/* Non secure storage API. */ +inline PSErrorCode PersistentStorage::NonSecureInit() +{ + return Impl()->_NonSecureInit(); +}; + +inline PSErrorCode PersistentStorage::NonSecureStore(PersistentStorageNode *node, const void *data, size_t dataSize) +{ + return Impl()->_NonSecureStore(node, data, dataSize); +} + +inline PSErrorCode PersistentStorage::NonSecureLoad(PersistentStorageNode *node, void *data, size_t dataMaxSize, + size_t &outSize) +{ + return Impl()->_NonSecureLoad(node, data, dataMaxSize, outSize); +} + +inline PSErrorCode PersistentStorage::NonSecureHasEntry(PersistentStorageNode *node) +{ + return Impl()->_NonSecureHasEntry(node); +} + +inline PSErrorCode PersistentStorage::NonSecureRemove(PersistentStorageNode *node) +{ + return Impl()->_NonSecureRemove(node); +} + +/* Secure storage API. */ +inline PSErrorCode PersistentStorage::SecureInit() +{ + return Impl()->_SecureInit(); +}; + +inline PSErrorCode PersistentStorage::SecureStore(PersistentStorageNode *node, const void *data, size_t dataSize) +{ + return Impl()->_SecureStore(node, data, dataSize); +} + +inline PSErrorCode PersistentStorage::SecureLoad(PersistentStorageNode *node, void *data, size_t dataMaxSize, + size_t &outSize) +{ + return Impl()->_SecureLoad(node, data, dataMaxSize, outSize); +} + +inline PSErrorCode PersistentStorage::SecureHasEntry(PersistentStorageNode *node) +{ + return Impl()->_SecureHasEntry(node); +} + +inline PSErrorCode PersistentStorage::SecureRemove(PersistentStorageNode *node) +{ + return Impl()->_SecureRemove(node); +} + +} /* namespace Nrf */ diff --git a/samples/matter/common/src/persistent_storage/persistent_storage_common.h b/samples/matter/common/src/persistent_storage/persistent_storage_common.h new file mode 100644 index 000000000000..cb3e708428c3 --- /dev/null +++ b/samples/matter/common/src/persistent_storage/persistent_storage_common.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include + +namespace Nrf +{ +enum PSErrorCode : uint8_t { Failure, Success, NotSupported }; + +/** + * @brief Class representing single tree node and containing information about its key. + */ +class PersistentStorageNode { +public: + static constexpr uint8_t kMaxKeyNameLength{ 16 }; + + /** + * @brief Constructor assigns name of a key for this node and sets parent node address in the tree + * hierarchy. The node does not need to have a parent (parent = nullptr), if it is a top level element. + */ + PersistentStorageNode(const char *keyName, size_t keyNameLength, PersistentStorageNode *parent = nullptr) + { + if (keyName && keyNameLength < kMaxKeyNameLength) { + memcpy(mKeyName, keyName, keyNameLength); + mKeyName[keyNameLength] = '\0'; + } + mParent = parent; + } + + /** + * @brief Gets complete key name for this node including its position in the tree hierarchy. The key + * name is a key name specific for this node concatenated with the names of all parents up to the top of the + * tree. + * + * @return true if the key has been created successfully + * @return false otherwise + */ + bool GetKey(char *key) + { + if (!key || mKeyName[0] == '\0') { + return false; + } + + /* Recursively call GetKey method for the parents until the full key name including all hierarchy levels + * will be created. */ + if (mParent != nullptr) { + char parentKey[kMaxKeyNameLength]; + + if (!mParent->GetKey(parentKey)) { + return false; + } + + int result = snprintf(key, kMaxKeyNameLength, "%s/%s", parentKey, mKeyName); + + if (result < 0 || result >= kMaxKeyNameLength) { + return false; + } + + } else { + /* In case of not having a parent, return only own key name. */ + strncpy(key, mKeyName, kMaxKeyNameLength); + } + + return true; + } + +private: + PersistentStorageNode *mParent = nullptr; + char mKeyName[kMaxKeyNameLength] = { 0 }; +}; + +} /* namespace Nrf */ diff --git a/samples/matter/common/src/persistent_storage/persistent_storage_impl.h b/samples/matter/common/src/persistent_storage/persistent_storage_impl.h new file mode 100644 index 000000000000..259b9c625878 --- /dev/null +++ b/samples/matter/common/src/persistent_storage/persistent_storage_impl.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include "persistent_storage.h" + +#ifdef CONFIG_NCS_SAMPLE_MATTER_SETTINGS_STORAGE_BACKEND +#include "backends/persistent_storage_settings.h" +#endif + +#ifdef CONFIG_NCS_SAMPLE_MATTER_SECURE_STORAGE_BACKEND +#include "backends/persistent_storage_secure.h" +#endif + +namespace Nrf +{ +class PersistentStorageImpl : public PersistentStorage +#ifdef CONFIG_NCS_SAMPLE_MATTER_SETTINGS_STORAGE_BACKEND + , + public PersistentStorageSettings +#endif +#ifdef CONFIG_NCS_SAMPLE_MATTER_SECURE_STORAGE_BACKEND + , + public PersistentStorageSecure +#endif +{ + friend class PersistentStorage; + +#ifdef CONFIG_NCS_SAMPLE_MATTER_SETTINGS_STORAGE_BACKEND + + using PersistentStorageSettings::_NonSecureHasEntry; + using PersistentStorageSettings::_NonSecureInit; + using PersistentStorageSettings::_NonSecureLoad; + using PersistentStorageSettings::_NonSecureRemove; + using PersistentStorageSettings::_NonSecureStore; +#endif + +#ifdef CONFIG_NCS_SAMPLE_MATTER_SECURE_STORAGE_BACKEND + using PersistentStorageSecure::_SecureHasEntry; + using PersistentStorageSecure::_SecureInit; + using PersistentStorageSecure::_SecureLoad; + using PersistentStorageSecure::_SecureRemove; + using PersistentStorageSecure::_SecureStore; +#endif +}; + +/* Implementation of the generic PersistentStorage getter. */ +inline PersistentStorage &GetPersistentStorage() +{ + static PersistentStorageImpl sInstance; + return sInstance; +} + +} /* namespace Nrf */ diff --git a/samples/matter/common/src/persistent_storage/persistent_storage_util.h b/samples/matter/common/src/persistent_storage/persistent_storage_util.h deleted file mode 100644 index 55ea3e028485..000000000000 --- a/samples/matter/common/src/persistent_storage/persistent_storage_util.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#pragma once - -#include -#include - -namespace Nrf { - -/** - * @brief Class representing single settings tree node and containing information about its key. - */ -class PersistentStorageNode { -public: - static constexpr auto kMaxKeyNameLength = (SETTINGS_MAX_NAME_LEN + 1); - - /** - * @brief Constructor assigns name of a key for this settings node and sets parent node address in the tree - * hierarchy. The node does not need to have a parent (parent = nullptr), if it is a top level element. - */ - PersistentStorageNode(const char *keyName, size_t keyNameLength, PersistentStorageNode *parent = nullptr) - { - if (keyName && keyNameLength < kMaxKeyNameLength) { - memcpy(mKeyName, keyName, keyNameLength); - mKeyName[keyNameLength] = '\0'; - } - mParent = parent; - } - - /** - * @brief Gets complete settings key name for this node including its position in the tree hierarchy. The key - * name is a key name specific for this node concatenated with the names of all parents up to the top of the - * tree. - * - * @return true if the key has been created successfully - * @return false otherwise - */ - bool GetKey(char *key); - -private: - PersistentStorageNode *mParent = nullptr; - char mKeyName[kMaxKeyNameLength] = { 0 }; -}; - -/** - * @brief Class to manage peristent storage using generic PersistentStorageNode data unit that wraps settings key - * information. - */ -class PersistentStorage { -public: - /** - * @brief Load all settings from persistent storage - * - * @return true if settings have been loaded - * @return false otherwise - */ - bool Init(); - - /** - * @brief Store data into settings - * - * @param node address of settings tree node containing information about the key - * @param data data to store into a specific settings key - * @param dataSize a size of input buffer - * @return true if key has been written successfully - * @return false an error occurred - */ - bool Store(PersistentStorageNode *node, const void *data, size_t dataSize); - - /** - * @brief Load data from settings - * - * @param node address of settings tree node containing information about the key - * @param data data buffer to load from a specific settings key - * @param dataMaxSize a size of data buffer to load - * @param outSize an actual size of read data - * @return true if key has been loaded successfully - * @return false an error occurred - */ - bool Load(PersistentStorageNode *node, void *data, size_t dataMaxSize, size_t &outSize); - - /** - * @brief Check if given key entry exists in settings - * - * @param node address of settings tree node containing information about the key - * @return true if key entry exists - * @return false if key entry does not exist - */ - bool HasEntry(PersistentStorageNode *node); - - /** - * @brief Remove given key entry from settings - * - * @param node address of settings tree node containing information about the key - * @return true if key entry has been removed successfully - * @return false an error occurred - */ - bool Remove(PersistentStorageNode *node); - - static PersistentStorage &Instance() - { - static PersistentStorage sInstance; - return sInstance; - } - -private: - bool LoadEntry(const char *key, void *data = nullptr, size_t dataMaxSize = 0, size_t *outSize = nullptr); -}; - -} /* namespace Nrf */ diff --git a/samples/matter/common/src/util/finite_map.h b/samples/matter/common/src/util/finite_map.h index 63458e2bfb06..7934c590fbd1 100644 --- a/samples/matter/common/src/util/finite_map.h +++ b/samples/matter/common/src/util/finite_map.h @@ -6,9 +6,12 @@ #pragma once +#include #include -#include -#include +#include +#include +#include +#include namespace Nrf { @@ -29,14 +32,16 @@ namespace Nrf * iterating though stored item via publicly available mMap member * retrieving the first free slot (GetFirstFreeSlot) Prerequisites: - * T1 must be trivial and the maximum numeric limit for the T1-type value is reserved and assigned as an invalid key. + * T1 must be trivial and the maximum numeric limit for the T1-type value is reserved and assigned as an invalid + key. * T2 must have move semantics and bool()/==operators implemented */ -template struct FiniteMap { +template struct FiniteMap { static_assert(std::is_trivial_v); static constexpr T1 kInvalidKey{ std::numeric_limits::max() }; static constexpr std::size_t kNoSlotsFound{ N + 1 }; + using ElementCounterType = uint16_t; struct Item { /* Initialize with invalid key (0 is a valid key) */ @@ -47,7 +52,7 @@ template struct FiniteMap { bool Insert(T1 key, T2 &&value) { if (Contains(key)) { - /* The key with sane value already exists in the map, return prematurely. */ + /* The key already exists in the map, return prematurely. */ return false; } else if (mElementsCount < N) { std::size_t slot = GetFirstFreeSlot(); @@ -94,11 +99,13 @@ template struct FiniteMap { return false; } - std::size_t FreeSlots() { return N - mElementsCount; } + ElementCounterType FreeSlots() { return N - mElementsCount; } - std::size_t GetFirstFreeSlot() + ElementCounterType Size() { return mElementsCount; } + + ElementCounterType GetFirstFreeSlot() { - std::size_t foundIndex = 0; + ElementCounterType foundIndex = 0; for (auto &it : mMap) { if (kInvalidKey == it.key) return foundIndex; @@ -124,7 +131,7 @@ template struct FiniteMap { } Item mMap[N]; - uint16_t mElementsCount{ 0 }; + ElementCounterType mElementsCount{ 0 }; }; } /* namespace Nrf */