Skip to content

Commit

Permalink
samples: matter: Secure persistent storage implementation
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
markaj-nordic authored and rlubos committed Apr 19, 2024
1 parent 3302905 commit 12317ec
Show file tree
Hide file tree
Showing 18 changed files with 817 additions and 197 deletions.
1 change: 0 additions & 1 deletion applications/matter_bridge/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions applications/matter_bridge/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
26 changes: 26 additions & 0 deletions doc/nrf/protocols/matter/getting_started/advanced_kconfigs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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<zephyr:settings_api>`.
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.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
------------------

Expand Down
7 changes: 7 additions & 0 deletions samples/matter/common/cmake/source_common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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()
5 changes: 5 additions & 0 deletions samples/matter/common/src/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
26 changes: 13 additions & 13 deletions samples/matter/common/src/bridge/bridge_storage_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ template <class T> 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;
}
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -76,37 +76,37 @@ 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,
uint8_t bridgedDeviceIndex)
{
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,
uint8_t bridgedDeviceIndex)
{
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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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

Expand Down
7 changes: 4 additions & 3 deletions samples/matter/common/src/bridge/bridge_storage_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <zephyr/bluetooth/addr.h>
#endif

namespace Nrf {
namespace Nrf
{

/*
* The class implements the following key-values storage structure:
Expand Down Expand Up @@ -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
Expand Down
34 changes: 34 additions & 0 deletions samples/matter/common/src/persistent_storage/Kconfig
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 12317ec

Please sign in to comment.