From 2666efb9ac3ad72f80c9262b51c2c2325a4da81c Mon Sep 17 00:00:00 2001 From: ATmobica Date: Wed, 7 Dec 2022 12:20:50 +0000 Subject: [PATCH] [OIS] PSA protected storage support Add KV store class base on PSA Protected Storage. Rename OpenIoTSDKConfig to KVBlockDeviceStore. Build system adaptation to support various storage type. Change KV manager and Configuration manager to support various storage type. Add CONFIG_CHIP_OPEN_IOT_SDK_USE_PSA_PS Cmake flag to enable PSA PS support. Initialize the KV store manager during CHIP stack setup. Signed-off-by: ATmobica --- config/openiotsdk/CMakeLists.txt | 1 + config/openiotsdk/cmake/chip.cmake | 6 + docs/examples/openiotsdk_examples.md | 21 + examples/lock-app/openiotsdk/CMakeLists.txt | 1 + .../targets/an552/partition/flash_layout.h | 20 +- src/platform/openiotsdk/BUILD.gn | 41 +- src/platform/openiotsdk/CHIPPlatformConfig.h | 2 + .../openiotsdk/ConfigurationManagerImpl.cpp | 34 +- .../openiotsdk/ConfigurationManagerImpl.h | 5 +- ...oTSDKConfig.cpp => KVBlockDeviceStore.cpp} | 274 ++++---- ...penIoTSDKConfig.h => KVBlockDeviceStore.h} | 91 ++- src/platform/openiotsdk/KVPsaPsStore.cpp | 624 ++++++++++++++++++ src/platform/openiotsdk/KVPsaPsStore.h | 196 ++++++ .../openiotsdk/KeyValueStoreManagerImpl.cpp | 90 +-- .../openiotsdk/KeyValueStoreManagerImpl.h | 7 +- 15 files changed, 1170 insertions(+), 243 deletions(-) rename src/platform/openiotsdk/{OpenIoTSDKConfig.cpp => KVBlockDeviceStore.cpp} (56%) rename src/platform/openiotsdk/{OpenIoTSDKConfig.h => KVBlockDeviceStore.h} (62%) create mode 100644 src/platform/openiotsdk/KVPsaPsStore.cpp create mode 100644 src/platform/openiotsdk/KVPsaPsStore.h diff --git a/config/openiotsdk/CMakeLists.txt b/config/openiotsdk/CMakeLists.txt index 23091cf20d309b..1e7a77a0f21615 100644 --- a/config/openiotsdk/CMakeLists.txt +++ b/config/openiotsdk/CMakeLists.txt @@ -191,6 +191,7 @@ chip_gn_arg_bool ("chip_progress_logging" CONFIG_CHIP_PROGRESS_L chip_gn_arg_bool ("chip_automation_logging" CONFIG_CHIP_AUTOMATION_LOGGING) chip_gn_arg_bool ("chip_error_logging" CONFIG_CHIP_ERROR_LOGGING) chip_gn_arg_bool ("chip_openiotsdk_use_tfm" TFM_SUPPORT) +chip_gn_arg_bool ("chip_openiotsdk_use_psa_ps" CONFIG_CHIP_OPEN_IOT_SDK_USE_PSA_PS) if (TARGET cmsis-rtos-api) chip_gn_arg_string("target_os" "cmsis-rtos") endif() diff --git a/config/openiotsdk/cmake/chip.cmake b/config/openiotsdk/cmake/chip.cmake index 1021d9e72b8645..eae7377a4314bd 100644 --- a/config/openiotsdk/cmake/chip.cmake +++ b/config/openiotsdk/cmake/chip.cmake @@ -31,6 +31,12 @@ set(CONFIG_CHIP_PROGRESS_LOGGING YES CACHE BOOL "Enable logging at progress leve set(CONFIG_CHIP_AUTOMATION_LOGGING YES CACHE BOOL "Enable logging at automation level") set(CONFIG_CHIP_ERROR_LOGGING YES CACHE BOOL "Enable logging at error level") +set(CONFIG_CHIP_OPEN_IOT_SDK_USE_PSA_PS NO CACHE BOOL "Enable using PSA Protected Storage") + +if(CONFIG_CHIP_OPEN_IOT_SDK_USE_PSA_PS AND NOT TFM_SUPPORT) + message( FATAL_ERROR "You can not use PSA Protected Storage without TF-M support" ) +endif() + # Add CHIP sources add_subdirectory(${OPEN_IOT_SDK_CONFIG} ./chip_build) diff --git a/docs/examples/openiotsdk_examples.md b/docs/examples/openiotsdk_examples.md index 3faf997a1a0297..6cdca9c5a8fdf1 100644 --- a/docs/examples/openiotsdk_examples.md +++ b/docs/examples/openiotsdk_examples.md @@ -164,6 +164,27 @@ You can also provide the own version of Matter example by setting set(TFM_NS_APP_VERSION "0.0.1") ``` +### Trusted Firmware-M Protected Storage + +There is an option to add +[TF-M Protected Storage Service](https://tf-m-user-guide.trustedfirmware.org/integration_guide/services/tfm_ps_integration_guide.html) +support for `key-value` storage component in Matter examples. You need to set +`CONFIG_CHIP_OPEN_IOT_SDK_USE_PSA_PS` variable inside main application +`CMakeLists.txt` fi + +``` +set(CONFIG_CHIP_OPEN_IOT_SDK_USE_PSA_PS YES) +``` + +This option causes `key-value` objects will be stored in a secure part of flash +memory and the Protected Storage Service takes care of their encryption and +authentication. + +**NOTE** + +The `TF-M Protected Storage` option requires enabling +[TF-M](#trusted-firmware-m) support. + ## Building You build using a vscode task or call the script directly from the command line. diff --git a/examples/lock-app/openiotsdk/CMakeLists.txt b/examples/lock-app/openiotsdk/CMakeLists.txt index 013ee1ccfbf74f..defdeb368ac908 100644 --- a/examples/lock-app/openiotsdk/CMakeLists.txt +++ b/examples/lock-app/openiotsdk/CMakeLists.txt @@ -27,6 +27,7 @@ set(APP_TARGET chip-openiotsdk-lock-app-example_ns) set(TFM_SUPPORT YES) set(TFM_PROJECT_CONFIG_HEADER_FILE "${CMAKE_CURRENT_SOURCE_DIR}/tf-m-config/TfmProjectConfig.h") set(TFM_NS_APP_VERSION "0.0.1") +set(CONFIG_CHIP_OPEN_IOT_SDK_USE_PSA_PS YES) # Toolchain files need to exist before first call to project include(toolchain) diff --git a/examples/platform/openiotsdk/tf-m/targets/an552/partition/flash_layout.h b/examples/platform/openiotsdk/tf-m/targets/an552/partition/flash_layout.h index be124858850d4a..5adc3dcf35daff 100644 --- a/examples/platform/openiotsdk/tf-m/targets/an552/partition/flash_layout.h +++ b/examples/platform/openiotsdk/tf-m/targets/an552/partition/flash_layout.h @@ -28,10 +28,10 @@ * 0x0026_0000 Secure image secondary slot (384 KB) * 0x002C_0000 Non-secure image secondary slot (2 MB) * 0x004C_0000 Scratch area (2 MB) - * 0x006C_0000 Protected Storage Area (20 KB) - * 0x006C_5000 Internal Trusted Storage Area (16 KB) - * 0x006C_9000 OTP / NV counters area (8 KB) - * 0x006C_B000 Unused + * 0x006C_0000 Protected Storage Area (64 KB) + * 0x006D_0000 Internal Trusted Storage Area (64 KB) + * 0x006E_0000 OTP / NV counters area (8 KB) + * 0x006E_2000 Unused * * Flash layout on AN552 with BL2 (single image boot): * @@ -44,10 +44,10 @@ * 0x0026_0000 Secure image secondary (384 KB) * 0x002C_0000 Non-secure image secondary (384 KB) * 0x004C_0000 Scratch area (2 MB) - * 0x006C_0000 Protected Storage Area (20 KB) - * 0x006C_5000 Internal Trusted Storage Area (16 KB) - * 0x006C_9000 OTP / NV counters area (8 KB) - * 0x006C_B000 Unused + * 0x006C_0000 Protected Storage Area (64 KB) + * 0x006D_0000 Internal Trusted Storage Area (64 KB) + * 0x006E_0000 OTP / NV counters area (8 KB) + * 0x006E_2000 Unused */ /* This header file is included from linker scatter file as well, where only a @@ -143,11 +143,11 @@ /* Protected Storage (PS) Service definitions */ #define FLASH_PS_AREA_OFFSET (FLASH_AREA_SCRATCH_OFFSET + FLASH_AREA_SCRATCH_SIZE) -#define FLASH_PS_AREA_SIZE (0x5000) /* 20 KB */ +#define FLASH_PS_AREA_SIZE (0x10000) /* 64 KB */ /* Internal Trusted Storage (ITS) Service definitions */ #define FLASH_ITS_AREA_OFFSET (FLASH_PS_AREA_OFFSET + FLASH_PS_AREA_SIZE) -#define FLASH_ITS_AREA_SIZE (0x4000) /* 16 KB */ +#define FLASH_ITS_AREA_SIZE (0x10000) /* 64 KB */ /* OTP_definitions */ #define FLASH_OTP_NV_COUNTERS_AREA_OFFSET (FLASH_ITS_AREA_OFFSET + FLASH_ITS_AREA_SIZE) diff --git a/src/platform/openiotsdk/BUILD.gn b/src/platform/openiotsdk/BUILD.gn index e0c54ce6b20236..a8cd947ae411bc 100644 --- a/src/platform/openiotsdk/BUILD.gn +++ b/src/platform/openiotsdk/BUILD.gn @@ -22,14 +22,32 @@ assert(chip_device_platform == "openiotsdk") declare_args() { # Add Trusted Firmware-M (TF-M) support chip_openiotsdk_use_tfm = false + + # By default use flash block device storage + chip_openiotsdk_use_psa_ps = false } buildconfig_header("openiotsdk_buildconfig") { header = "OpenIoTSDKConfig.h" header_dir = "ois" + if (chip_openiotsdk_use_psa_ps) { + _chip_openiotsdk_kv_store_config_include = + "" + _chip_openiotsdk_persisted_storage_key_type = "uint64_t" + } else { + _chip_openiotsdk_kv_store_config_include = + "" + _chip_openiotsdk_persisted_storage_key_type = "const char *" + } + + defines = [ + "CHIP_OPEN_IOT_SDK_KV_STORE_CONFIG_INCLUDE=${_chip_openiotsdk_kv_store_config_include}", + "CHIP_CONFIG_PERSISTED_STORAGE_KEY_TYPE=${_chip_openiotsdk_persisted_storage_key_type}", + ] + if (chip_openiotsdk_use_tfm) { - defines = [ "CHIP_OPEN_IOT_SDK_USE_TFM=1" ] + defines += [ "CHIP_OPEN_IOT_SDK_USE_TFM=1" ] } } @@ -54,14 +72,27 @@ static_library("openiotsdk") { "NetworkCommissioningEthernetDriver.cpp", "OpenIoTSDKArchUtils.c", "OpenIoTSDKArchUtils.h", - "OpenIoTSDKConfig.cpp", - "OpenIoTSDKConfig.h", - "OpenIoTSDKConfig.h", + "OpenIoTSDKPort.h", "PlatformManagerImpl.cpp", "PlatformManagerImpl.h", "SystemPlatformConfig.h", "SystemTimeSupport.cpp", ] - public_deps = [ "${chip_root}/src/platform:platform_base" ] + public_deps = [ + ":openiotsdk_buildconfig", + "${chip_root}/src/platform:platform_base", + ] + + if (chip_openiotsdk_use_psa_ps) { + sources += [ + "KVPsaPsStore.cpp", + "KVPsaPsStore.h", + ] + } else { + sources += [ + "KVBlockDeviceStore.cpp", + "KVBlockDeviceStore.h", + ] + } } diff --git a/src/platform/openiotsdk/CHIPPlatformConfig.h b/src/platform/openiotsdk/CHIPPlatformConfig.h index 58da36298c27ef..efc4afd358fdf6 100644 --- a/src/platform/openiotsdk/CHIPPlatformConfig.h +++ b/src/platform/openiotsdk/CHIPPlatformConfig.h @@ -26,6 +26,8 @@ #include +#include + // ==================== General Platform Adaptations ==================== #define CHIP_CONFIG_EXPECTED_LOW_PROCESSING_TIME 10 diff --git a/src/platform/openiotsdk/ConfigurationManagerImpl.cpp b/src/platform/openiotsdk/ConfigurationManagerImpl.cpp index a10a15ba34f5d6..84da3ef5c767c1 100644 --- a/src/platform/openiotsdk/ConfigurationManagerImpl.cpp +++ b/src/platform/openiotsdk/ConfigurationManagerImpl.cpp @@ -49,8 +49,10 @@ CHIP_ERROR ConfigurationManagerImpl::Init() { CHIP_ERROR err; + KVStoreConfig::Init(); + // Initialize the generic implementation base class. - err = Internal::GenericConfigurationManagerImpl::Init(); + err = Internal::GenericConfigurationManagerImpl::Init(); SuccessOrExit(err); exit: @@ -69,7 +71,7 @@ void ConfigurationManagerImpl::InitiateFactoryReset(void) CHIP_ERROR ConfigurationManagerImpl::ReadPersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t & value) { - CHIP_ERROR err = ReadConfigValue(key, value); + CHIP_ERROR err = KVStoreConfig::ReadConfigValueCounter(key, value); if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) { err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; @@ -79,73 +81,73 @@ CHIP_ERROR ConfigurationManagerImpl::ReadPersistedStorageValue(::chip::Platform: CHIP_ERROR ConfigurationManagerImpl::WritePersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t value) { - return OpenIoTSDKConfig::WriteCounter(key, value); + return KVStoreConfig::WriteConfigValueCounter(key, value); } CHIP_ERROR ConfigurationManagerImpl::ReadConfigValue(Key key, bool & val) { - return OpenIoTSDKConfig::ReadConfigValue(key, val); + return KVStoreConfig::ReadConfigValue(key, val); } CHIP_ERROR ConfigurationManagerImpl::ReadConfigValue(Key key, uint32_t & val) { - return OpenIoTSDKConfig::ReadConfigValue(key, val); + return KVStoreConfig::ReadConfigValue(key, val); } CHIP_ERROR ConfigurationManagerImpl::ReadConfigValue(Key key, uint64_t & val) { - return OpenIoTSDKConfig::ReadConfigValue(key, val); + return KVStoreConfig::ReadConfigValue(key, val); } CHIP_ERROR ConfigurationManagerImpl::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) { - return OpenIoTSDKConfig::ReadConfigValueStr(key, buf, bufSize, outLen); + return KVStoreConfig::ReadConfigValueStr(key, buf, bufSize, outLen); } CHIP_ERROR ConfigurationManagerImpl::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) { - return OpenIoTSDKConfig::ReadConfigValueBin(key, buf, bufSize, outLen); + return KVStoreConfig::ReadConfigValueBin(key, buf, bufSize, outLen); } CHIP_ERROR ConfigurationManagerImpl::WriteConfigValue(Key key, bool val) { - return OpenIoTSDKConfig::WriteConfigValue(key, val); + return KVStoreConfig::WriteConfigValue(key, val); } CHIP_ERROR ConfigurationManagerImpl::WriteConfigValue(Key key, uint32_t val) { - return OpenIoTSDKConfig::WriteConfigValue(key, val); + return KVStoreConfig::WriteConfigValue(key, val); } CHIP_ERROR ConfigurationManagerImpl::WriteConfigValue(Key key, uint64_t val) { - return OpenIoTSDKConfig::WriteConfigValue(key, val); + return KVStoreConfig::WriteConfigValue(key, val); } CHIP_ERROR ConfigurationManagerImpl::WriteConfigValueStr(Key key, const char * str) { - return OpenIoTSDKConfig::WriteConfigValueStr(key, str); + return KVStoreConfig::WriteConfigValueStr(key, str); } CHIP_ERROR ConfigurationManagerImpl::WriteConfigValueStr(Key key, const char * str, size_t strLen) { - return OpenIoTSDKConfig::WriteConfigValueStr(key, str, strLen); + return KVStoreConfig::WriteConfigValueStr(key, str, strLen); } CHIP_ERROR ConfigurationManagerImpl::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) { - return OpenIoTSDKConfig::WriteConfigValueBin(key, data, dataLen); + return KVStoreConfig::WriteConfigValueBin(key, data, dataLen); } void ConfigurationManagerImpl::RunConfigUnitTest(void) { - OpenIoTSDKConfig::RunConfigUnitTest(); + KVStoreConfig::RunConfigUnitTest(); } void ConfigurationManagerImpl::DoFactoryReset(intptr_t arg) { ChipLogProgress(DeviceLayer, "Performing factory reset"); - const CHIP_ERROR err = OpenIoTSDKConfig::FactoryResetConfig(); + const CHIP_ERROR err = KVStoreConfig::FactoryResetConfig(); if (err != CHIP_NO_ERROR) { ChipLogError(DeviceLayer, "FactoryResetConfig() failed: %s", ErrorStr(err)); diff --git a/src/platform/openiotsdk/ConfigurationManagerImpl.h b/src/platform/openiotsdk/ConfigurationManagerImpl.h index ad4effe0645978..044c3d55d6f377 100644 --- a/src/platform/openiotsdk/ConfigurationManagerImpl.h +++ b/src/platform/openiotsdk/ConfigurationManagerImpl.h @@ -25,7 +25,8 @@ #pragma once #include -#include + +#include CHIP_OPEN_IOT_SDK_KV_STORE_CONFIG_INCLUDE namespace chip { namespace DeviceLayer { @@ -33,7 +34,7 @@ namespace DeviceLayer { /** * Concrete implementation of the ConfigurationManager singleton object for the Zephyr platform. */ -class ConfigurationManagerImpl : public Internal::GenericConfigurationManagerImpl +class ConfigurationManagerImpl : public Internal::GenericConfigurationManagerImpl { public: diff --git a/src/platform/openiotsdk/OpenIoTSDKConfig.cpp b/src/platform/openiotsdk/KVBlockDeviceStore.cpp similarity index 56% rename from src/platform/openiotsdk/OpenIoTSDKConfig.cpp rename to src/platform/openiotsdk/KVBlockDeviceStore.cpp index b26167b663c9ad..fc6f364976b0d7 100644 --- a/src/platform/openiotsdk/OpenIoTSDKConfig.cpp +++ b/src/platform/openiotsdk/KVBlockDeviceStore.cpp @@ -17,7 +17,7 @@ /** * @file - * Utilities for interacting with the the Open IoT SDK key-value storage. + * Open IoT SDK key-value storage base on flash TDBStore. */ #include @@ -28,7 +28,7 @@ #include #include -#include +#include #include namespace chip { @@ -37,53 +37,84 @@ namespace Internal { // *** CAUTION ***: Changing the names or namespaces of these values will *break* existing devices. -#define STR_EXPAND(tok) #tok - -// Note: An external mbed parameter could be useful so an application can put -// chip NVS values in a single place -#define CHIP_CONFIG_KV_STORE_PARTITION STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV) - // NVS namespaces used to store device configuration information. #define CHIP_CONFIG_FACTORY_PREFIX "chip-factory-" #define CHIP_CONFIG_CONFIG_PREFIX "chip-config-" #define CHIP_CONFIG_COUNTER_PREFIX "chip-counters-" -#define FACTORY_KEY(key) CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_FACTORY_PREFIX key -#define CONFIG_KEY(key) CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_CONFIG_PREFIX key - -const char OpenIoTSDKConfig::kConfigNamespace_ChipFactory[] = CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_FACTORY_PREFIX; -const char OpenIoTSDKConfig::kConfigNamespace_ChipConfig[] = CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_CONFIG_PREFIX; -const char OpenIoTSDKConfig::kConfigNamespace_ChipCounters[] = CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_COUNTER_PREFIX; +#define FACTORY_KEY(key) CHIP_CONFIG_FACTORY_PREFIX key +#define CONFIG_KEY(key) CHIP_CONFIG_CONFIG_PREFIX key +#define COUNTER_KEY(key) CHIP_CONFIG_COUNTER_PREFIX key // Keys stored in the chip-factory namespace -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_SerialNum = { FACTORY_KEY("serial-num") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_MfrDeviceId = { FACTORY_KEY("device-id") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_MfrDeviceCert = { FACTORY_KEY("device-cert") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_MfrDeviceICACerts = { FACTORY_KEY("device-ca-certs") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_MfrDevicePrivateKey = { FACTORY_KEY("device-key") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_HardwareVersion = { FACTORY_KEY("hardware-ver") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_ManufacturingDate = { FACTORY_KEY("mfg-date") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_SetupPinCode = { FACTORY_KEY("pin-code") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_SetupDiscriminator = { FACTORY_KEY("discriminator") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_Spake2pIterationCount = { FACTORY_KEY("iteration-count") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_Spake2pSalt = { FACTORY_KEY("salt") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_Spake2pVerifier = { FACTORY_KEY("verifier") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_SerialNum = { FACTORY_KEY("serial-num") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_MfrDeviceId = { FACTORY_KEY("device-id") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_MfrDeviceCert = { FACTORY_KEY("device-cert") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_MfrDeviceICACerts = { FACTORY_KEY("device-ca-certs") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_MfrDevicePrivateKey = { FACTORY_KEY("device-key") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_HardwareVersion = { FACTORY_KEY("hardware-ver") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_ManufacturingDate = { FACTORY_KEY("mfg-date") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_SetupPinCode = { FACTORY_KEY("pin-code") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_SetupDiscriminator = { FACTORY_KEY("discriminator") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_Spake2pIterationCount = { FACTORY_KEY("iteration-count") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_Spake2pSalt = { FACTORY_KEY("salt") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_Spake2pVerifier = { FACTORY_KEY("verifier") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_VendorId = { FACTORY_KEY("vendor-id") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_ProductId = { FACTORY_KEY("product-id") }; // Keys stored in the chip-config namespace -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_ServiceConfig = { CONFIG_KEY("service-config") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_PairedAccountId = { CONFIG_KEY("account-id") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_ServiceId = { CONFIG_KEY("service-id") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_LastUsedEpochKeyId = { CONFIG_KEY("last-ek-id") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_FailSafeArmed = { CONFIG_KEY("fail-safe-armed") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_WiFiStationSecType = { CONFIG_KEY("sta-sec-type") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_RegulatoryLocation = { CONFIG_KEY("regulatory-location") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_CountryCode = { CONFIG_KEY("country-code") }; -const OpenIoTSDKConfig::Key OpenIoTSDKConfig::kConfigKey_UniqueId = { CONFIG_KEY("unique-id") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_ServiceConfig = { CONFIG_KEY("service-config") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_PairedAccountId = { CONFIG_KEY("account-id") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_ServiceId = { CONFIG_KEY("service-id") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_LastUsedEpochKeyId = { CONFIG_KEY("last-ek-id") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_FailSafeArmed = { CONFIG_KEY("fail-safe-armed") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_WiFiStationSecType = { CONFIG_KEY("sta-sec-type") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_RegulatoryLocation = { CONFIG_KEY("regulatory-location") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_CountryCode = { CONFIG_KEY("country-code") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_LocationCapability = { CONFIG_KEY("location-capability") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kConfigKey_UniqueId = { CONFIG_KEY("unique-id") }; + +// Keys stored in the Chip-counters namespace +const KVBlockDeviceStore::Key KVBlockDeviceStore::kCounterKey_RebootCount = { COUNTER_KEY("reboot-count") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kCounterKey_UpTime = { COUNTER_KEY("up-time") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kCounterKey_TotalOperationalHours = { COUNTER_KEY("total-operational-hours") }; +const KVBlockDeviceStore::Key KVBlockDeviceStore::kCounterKey_BootReason = { COUNTER_KEY("boot-reason") }; using iotsdk::storage::kv_status; using iotsdk::storage::KVStore; -CHIP_ERROR OpenIoTSDKConfig::ReadConfigValue(Key key, bool & val) +iotsdk::storage::TDBStore * KVBlockDeviceStore::tdb = nullptr; + +CHIP_ERROR KVBlockDeviceStore::Init(void) +{ + if (tdb) + { + return CHIP_NO_ERROR; + } + + // Create a TDBStore using the underlying storage + tdb = new iotsdk::storage::TDBStore(GetBlockDevice()); + + if (!tdb) + { + return CHIP_ERROR_INTERNAL; + } + + // KVStore uses dual stage initialization so we can handle any errors + // Call the `init` method to setup the TDBStore + kv_status err = tdb->init(); + if (err != kv_status::OK) + { + delete tdb; + // zero tdb as we use it keep track of init + tdb = nullptr; + return CHIP_ERROR_INTERNAL; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVBlockDeviceStore::ReadConfigValue(Key key, bool & val) { if (Init() != CHIP_NO_ERROR) { @@ -111,7 +142,7 @@ CHIP_ERROR OpenIoTSDKConfig::ReadConfigValue(Key key, bool & val) return CHIP_NO_ERROR; } -CHIP_ERROR OpenIoTSDKConfig::ReadConfigValue(Key key, uint32_t & val) +CHIP_ERROR KVBlockDeviceStore::ReadConfigValue(Key key, uint32_t & val) { if (Init() != CHIP_NO_ERROR) { @@ -139,7 +170,7 @@ CHIP_ERROR OpenIoTSDKConfig::ReadConfigValue(Key key, uint32_t & val) return CHIP_NO_ERROR; } -CHIP_ERROR OpenIoTSDKConfig::ReadConfigValue(Key key, uint64_t & val) +CHIP_ERROR KVBlockDeviceStore::ReadConfigValue(Key key, uint64_t & val) { if (Init() != CHIP_NO_ERROR) { @@ -167,7 +198,7 @@ CHIP_ERROR OpenIoTSDKConfig::ReadConfigValue(Key key, uint64_t & val) return CHIP_NO_ERROR; } -CHIP_ERROR OpenIoTSDKConfig::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) +CHIP_ERROR KVBlockDeviceStore::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) { CHIP_ERROR err = ReadConfigValueBin(key, reinterpret_cast(buf), bufSize, outLen); // Note: The system expect the trailing null to be added. @@ -183,7 +214,12 @@ CHIP_ERROR OpenIoTSDKConfig::ReadConfigValueStr(Key key, char * buf, size_t bufS return CHIP_NO_ERROR; } -CHIP_ERROR OpenIoTSDKConfig::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) +CHIP_ERROR KVBlockDeviceStore::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) +{ + return ReadConfigValueBin(key, buf, bufSize, outLen, 0); +} + +CHIP_ERROR KVBlockDeviceStore::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen, size_t offset) { if (Init() != CHIP_NO_ERROR) { @@ -203,13 +239,13 @@ CHIP_ERROR OpenIoTSDKConfig::ReadConfigValueBin(Key key, uint8_t * buf, size_t b return CHIP_ERROR_INTERNAL; } - err = tdb->get(key, reinterpret_cast(buf), bufSize, &outLen); + err = tdb->get(key, reinterpret_cast(buf), bufSize, &outLen, offset); if (err != kv_status::OK) { return CHIP_ERROR_INTERNAL; } - if (bufSize < info.size) + if (bufSize < info.size - offset) { return CHIP_ERROR_BUFFER_TOO_SMALL; } @@ -217,7 +253,19 @@ CHIP_ERROR OpenIoTSDKConfig::ReadConfigValueBin(Key key, uint8_t * buf, size_t b return CHIP_NO_ERROR; } -CHIP_ERROR OpenIoTSDKConfig::WriteConfigValue(Key key, bool val) +CHIP_ERROR KVBlockDeviceStore::ReadConfigValueCounter(Key counterId, uint32_t & value) +{ + char key[50] = { 0 }; + auto err = ConstructCounterKey(counterId, key, sizeof(key)); + if (err != CHIP_NO_ERROR) + { + return err; + } + + return ReadConfigValue(key, value); +} + +CHIP_ERROR KVBlockDeviceStore::WriteConfigValue(Key key, bool val) { if (Init() != CHIP_NO_ERROR) { @@ -228,7 +276,7 @@ CHIP_ERROR OpenIoTSDKConfig::WriteConfigValue(Key key, bool val) return err == kv_status::OK ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } -CHIP_ERROR OpenIoTSDKConfig::WriteConfigValue(Key key, uint32_t val) +CHIP_ERROR KVBlockDeviceStore::WriteConfigValue(Key key, uint32_t val) { if (Init() != CHIP_NO_ERROR) { @@ -239,7 +287,7 @@ CHIP_ERROR OpenIoTSDKConfig::WriteConfigValue(Key key, uint32_t val) return err == kv_status::OK ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } -CHIP_ERROR OpenIoTSDKConfig::WriteConfigValue(Key key, uint64_t val) +CHIP_ERROR KVBlockDeviceStore::WriteConfigValue(Key key, uint64_t val) { if (Init() != CHIP_NO_ERROR) { @@ -250,17 +298,17 @@ CHIP_ERROR OpenIoTSDKConfig::WriteConfigValue(Key key, uint64_t val) return err == kv_status::OK ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } -CHIP_ERROR OpenIoTSDKConfig::WriteConfigValueStr(Key key, const char * str) +CHIP_ERROR KVBlockDeviceStore::WriteConfigValueStr(Key key, const char * str) { return WriteConfigValueBin(key, reinterpret_cast(str), strlen(str)); } -CHIP_ERROR OpenIoTSDKConfig::WriteConfigValueStr(Key key, const char * str, size_t strLen) +CHIP_ERROR KVBlockDeviceStore::WriteConfigValueStr(Key key, const char * str, size_t strLen) { return WriteConfigValueBin(key, reinterpret_cast(str), strLen); } -CHIP_ERROR OpenIoTSDKConfig::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) +CHIP_ERROR KVBlockDeviceStore::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) { if (Init() != CHIP_NO_ERROR) { @@ -285,7 +333,19 @@ CHIP_ERROR OpenIoTSDKConfig::WriteConfigValueBin(Key key, const uint8_t * data, } } -CHIP_ERROR OpenIoTSDKConfig::ClearConfigValue(Key key) +CHIP_ERROR KVBlockDeviceStore::WriteConfigValueCounter(Key counterId, uint32_t value) +{ + char key[50] = { 0 }; + auto err = ConstructCounterKey(counterId, key, sizeof(key)); + if (err != CHIP_NO_ERROR) + { + return err; + } + + return WriteConfigValue(key, value); +} + +CHIP_ERROR KVBlockDeviceStore::ClearConfigValue(Key key) { if (Init() != CHIP_NO_ERROR) { @@ -295,38 +355,44 @@ CHIP_ERROR OpenIoTSDKConfig::ClearConfigValue(Key key) kv_status err = tdb->remove(key); if (err == kv_status::ITEM_NOT_FOUND) { - return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; } return err == kv_status::OK ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } -bool OpenIoTSDKConfig::ConfigValueExists(Key key) +CHIP_ERROR KVBlockDeviceStore::FactoryResetConfig() { - if (Init() != CHIP_NO_ERROR) + // tdb->reset is not used, we want to preserve other setting and factory + // configuration + auto err = ClearNamespace(CHIP_CONFIG_CONFIG_PREFIX); + if (err != CHIP_NO_ERROR) { - return false; + return err; } + return ClearNamespace(CHIP_CONFIG_COUNTER_PREFIX); +} - KVStore::info_t info; - kv_status err = tdb->get_info(key, &info); - return err == kv_status::OK ? true : false; +void KVBlockDeviceStore::RunConfigUnitTest() +{ + // Run common unit test. + ::chip::DeviceLayer::Internal::RunConfigUnitTest(); } -CHIP_ERROR OpenIoTSDKConfig::FactoryResetConfig() +bool KVBlockDeviceStore::ConfigValueExists(Key key) { - // tdb->reset is not used, we want to preserve other setting and factory - // configuration - auto err = ClearNamespace(kConfigNamespace_ChipConfig); - if (err != CHIP_NO_ERROR) + if (Init() != CHIP_NO_ERROR) { - return err; + return false; } - return ClearNamespace(kConfigNamespace_ChipCounters); + + KVStore::info_t info; + kv_status err = tdb->get_info(key, &info); + return err == kv_status::OK ? true : false; } -CHIP_ERROR OpenIoTSDKConfig::ConstructCounterKey(Key id, char * buf, size_t bufSize) +CHIP_ERROR KVBlockDeviceStore::ConstructCounterKey(Key id, char * buf, size_t bufSize) { - auto length = snprintf(buf, bufSize - 1, CHIP_CONFIG_KV_STORE_PARTITION CHIP_CONFIG_COUNTER_PREFIX "%s", id); + auto length = snprintf(buf, bufSize - 1, CHIP_CONFIG_COUNTER_PREFIX "%s", id); if (length < 0) { return CHIP_ERROR_INTERNAL; @@ -341,31 +407,7 @@ CHIP_ERROR OpenIoTSDKConfig::ConstructCounterKey(Key id, char * buf, size_t bufS } } -CHIP_ERROR OpenIoTSDKConfig::ReadCounter(Key counterId, uint32_t & value) -{ - char key[50] = { 0 }; - auto err = ConstructCounterKey(counterId, key, sizeof(key)); - if (err != CHIP_NO_ERROR) - { - return err; - } - - return ReadConfigValue(key, value); -} - -CHIP_ERROR OpenIoTSDKConfig::WriteCounter(Key counterId, uint32_t value) -{ - char key[50] = { 0 }; - auto err = ConstructCounterKey(counterId, key, sizeof(key)); - if (err != CHIP_NO_ERROR) - { - return err; - } - - return WriteConfigValue(key, value); -} - -CHIP_ERROR OpenIoTSDKConfig::ClearNamespace(const char * ns) +CHIP_ERROR KVBlockDeviceStore::ClearNamespace(const char * ns) { if (Init() != CHIP_NO_ERROR) { @@ -403,43 +445,29 @@ CHIP_ERROR OpenIoTSDKConfig::ClearNamespace(const char * ns) return err == kv_status::OK ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } -void OpenIoTSDKConfig::RunConfigUnitTest() +KVBlockDeviceStoreKeyBuilder::KVBlockDeviceStoreKeyBuilder(const char * key) { - // Run common unit test. - ::chip::DeviceLayer::Internal::RunConfigUnitTest(); -} - -CHIP_ERROR OpenIoTSDKConfig::Init(void) -{ - if (tdb) - { - return CHIP_NO_ERROR; - } - - // Create a TDBStore using the underlying storage - tdb = new iotsdk::storage::TDBStore(GetBlockDevice()); - - if (!tdb) - { - return CHIP_ERROR_INTERNAL; - } - - // KVStore uses dual stage initialization so we can handle any errors - // Call the `init` method to setup the TDBStore - kv_status err = tdb->init(); - if (err != kv_status::OK) - { - delete tdb; - // zero tdb as we use it keep track of init - tdb = nullptr; - return CHIP_ERROR_INTERNAL; + // Check sign by sign if key contains illegal characters + // Each illegal character will be replaced by '!' + capital encoded letter value + char * out = buffer + strlen(buffer); + char * illegal_ptr; + while ((out < buffer + sizeof(buffer) - 3) && *key) // 2 chars for potential illegal char + 1 for \0 + { + illegal_ptr = strchr(illegalCharacters, *key); + if (illegal_ptr) + { + *out++ = '!'; + *out++ = 'A' + (int) (illegal_ptr - illegalCharacters); + } + else + { + *out++ = *key; + } + key++; } - - return CHIP_NO_ERROR; + valid = true; } -iotsdk::storage::TDBStore * OpenIoTSDKConfig::tdb = nullptr; - } // namespace Internal } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/openiotsdk/OpenIoTSDKConfig.h b/src/platform/openiotsdk/KVBlockDeviceStore.h similarity index 62% rename from src/platform/openiotsdk/OpenIoTSDKConfig.h rename to src/platform/openiotsdk/KVBlockDeviceStore.h index bf112641945d2a..5935d599ba17a8 100644 --- a/src/platform/openiotsdk/OpenIoTSDKConfig.h +++ b/src/platform/openiotsdk/KVBlockDeviceStore.h @@ -17,14 +17,17 @@ /** * @file - * Utilities for interacting with the the Open IoT SDK key-value storage. + * Open IoT SDK key-value storage base on flash TDBStore. */ #pragma once +#include + +#include +#include #include #include -#include #include @@ -33,24 +36,17 @@ namespace DeviceLayer { namespace Internal { /** - * Provides functions and definitions for accessing device configuration information on the ESP32. - * - * This class is designed to be mixed-in to concrete implementation classes as a means to - * provide access to configuration information to generic base classes. + * This class provides access to configuration information for Open IoT SDK platform + * stored in Lightweight Key Value storage over a flash block device. */ -class OpenIoTSDKConfig +class KVBlockDeviceStore { public: - using Key = const char *; - - // NVS prefix used to store device configuration information. - static const char kConfigNamespace_ChipFactory[]; - static const char kConfigNamespace_ChipConfig[]; - static const char kConfigNamespace_ChipCounters[]; + using Key = chip::Platform::PersistedStorage::Key; // Key definitions for well-known keys. + // Factory keys static const Key kConfigKey_SerialNum; - static const Key kConfigKey_UniqueId; static const Key kConfigKey_MfrDeviceId; static const Key kConfigKey_MfrDeviceCert; static const Key kConfigKey_MfrDeviceICACerts; @@ -58,48 +54,91 @@ class OpenIoTSDKConfig static const Key kConfigKey_HardwareVersion; static const Key kConfigKey_ManufacturingDate; static const Key kConfigKey_SetupPinCode; + static const Key kConfigKey_SetupDiscriminator; + static const Key kConfigKey_Spake2pIterationCount; + static const Key kConfigKey_Spake2pSalt; + static const Key kConfigKey_Spake2pVerifier; + static const Key kConfigKey_VendorId; + static const Key kConfigKey_ProductId; + + // Config Keys static const Key kConfigKey_ServiceConfig; static const Key kConfigKey_PairedAccountId; static const Key kConfigKey_ServiceId; static const Key kConfigKey_LastUsedEpochKeyId; static const Key kConfigKey_FailSafeArmed; static const Key kConfigKey_WiFiStationSecType; - static const Key kConfigKey_SetupDiscriminator; static const Key kConfigKey_RegulatoryLocation; static const Key kConfigKey_CountryCode; - static const Key kConfigKey_Spake2pIterationCount; - static const Key kConfigKey_Spake2pSalt; - static const Key kConfigKey_Spake2pVerifier; + static const Key kConfigKey_LocationCapability; + static const Key kConfigKey_UniqueId; + + // Counter Keys + static const Key kCounterKey_RebootCount; + static const Key kCounterKey_UpTime; + static const Key kCounterKey_TotalOperationalHours; + static const Key kCounterKey_BootReason; + + // Initialization + static CHIP_ERROR Init(void); - // Config value accessors. + // Config value accessors static CHIP_ERROR ReadConfigValue(Key key, bool & val); static CHIP_ERROR ReadConfigValue(Key key, uint32_t & val); static CHIP_ERROR ReadConfigValue(Key key, uint64_t & val); static CHIP_ERROR ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen); static CHIP_ERROR ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen); + static CHIP_ERROR ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen, size_t offset); + static CHIP_ERROR ReadConfigValueCounter(Key counterId, uint32_t & val); + static CHIP_ERROR WriteConfigValue(Key key, bool val); static CHIP_ERROR WriteConfigValue(Key key, uint32_t val); static CHIP_ERROR WriteConfigValue(Key key, uint64_t val); static CHIP_ERROR WriteConfigValueStr(Key key, const char * str); static CHIP_ERROR WriteConfigValueStr(Key key, const char * str, size_t strLen); static CHIP_ERROR WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen); + static CHIP_ERROR WriteConfigValueCounter(Key counterId, uint32_t val); + static CHIP_ERROR ClearConfigValue(Key key); + + // Additional functions + static CHIP_ERROR FactoryResetConfig(void); + static void RunConfigUnitTest(void); static bool ConfigValueExists(Key key); - static CHIP_ERROR FactoryResetConfig(); - static CHIP_ERROR Init(void); - // NVS Namespace helper functions. +private: + static iotsdk::storage::TDBStore * tdb; + + // NVS Namespace helper functions static CHIP_ERROR ConstructCounterKey(Key id, char * buf, size_t bufSize); - static CHIP_ERROR ReadCounter(Key counterId, uint32_t & value); - static CHIP_ERROR WriteCounter(Key counterId, uint32_t value); static CHIP_ERROR ClearNamespace(const char * ns); +}; - static void RunConfigUnitTest(void); +class KVBlockDeviceStoreKeyBuilder +{ +public: + KVBlockDeviceStoreKeyBuilder(const char * key); + + void AddKey(void) {} + void RemoveKey(void) {} + + KVBlockDeviceStore::Key GetKey() const; private: - static iotsdk::storage::TDBStore * tdb; + char buffer[PersistentStorageDelegate::kKeyLengthMax + 1] = "chip-kvs-"; + bool valid; + // Mbed KV storage does not accept these characters in the key definition + const char * illegalCharacters = " */?:;\"|<>\\"; }; +inline KVBlockDeviceStore::Key KVBlockDeviceStoreKeyBuilder::GetKey() const +{ + return valid ? buffer : nullptr; +} + } // namespace Internal } // namespace DeviceLayer } // namespace chip + +using KVStoreConfig = chip::DeviceLayer::Internal::KVBlockDeviceStore; +using KVStoreKeyBuilder = chip::DeviceLayer::Internal::KVBlockDeviceStoreKeyBuilder; diff --git a/src/platform/openiotsdk/KVPsaPsStore.cpp b/src/platform/openiotsdk/KVPsaPsStore.cpp new file mode 100644 index 00000000000000..74023134ec0e97 --- /dev/null +++ b/src/platform/openiotsdk/KVPsaPsStore.cpp @@ -0,0 +1,624 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Open IoT SDK key-value storage base on flash TDBStore. + */ + +#include + +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +// *** CAUTION ***: Changing the values of these keys can *break* existing devices. +const KVPsaPsStore::Key KVPsaPsStore::kMatterFactory_KeyOffset = 0x0; +const KVPsaPsStore::Key KVPsaPsStore::kMatterConfig_KeyOffset = 0x1; +const KVPsaPsStore::Key KVPsaPsStore::kMatterCounter_KeyOffset = 0x2; +const KVPsaPsStore::Key KVPsaPsStore::kMatterKvs_KeyOffset = 0x3; + +// Keys stored in the Matter factory group +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_SerialNum = GetPsaPaKey(kMatterFactory_KeyOffset, 0x00); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_MfrDeviceId = GetPsaPaKey(kMatterFactory_KeyOffset, 0x01); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_MfrDeviceCert = GetPsaPaKey(kMatterFactory_KeyOffset, 0x02); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_MfrDeviceICACerts = GetPsaPaKey(kMatterFactory_KeyOffset, 0x03); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_MfrDevicePrivateKey = GetPsaPaKey(kMatterFactory_KeyOffset, 0x04); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_HardwareVersion = GetPsaPaKey(kMatterFactory_KeyOffset, 0x05); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_ManufacturingDate = GetPsaPaKey(kMatterFactory_KeyOffset, 0x06); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_SetupPinCode = GetPsaPaKey(kMatterFactory_KeyOffset, 0x07); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_SetupDiscriminator = GetPsaPaKey(kMatterFactory_KeyOffset, 0x08); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_Spake2pIterationCount = GetPsaPaKey(kMatterFactory_KeyOffset, 0x09); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_Spake2pSalt = GetPsaPaKey(kMatterFactory_KeyOffset, 0x0A); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_Spake2pVerifier = GetPsaPaKey(kMatterFactory_KeyOffset, 0x0B); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_VendorId = GetPsaPaKey(kMatterFactory_KeyOffset, 0x0C); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_ProductId = GetPsaPaKey(kMatterFactory_KeyOffset, 0x0D); + +// Keys stored in the Matter config group +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_ServiceConfig = GetPsaPaKey(kMatterConfig_KeyOffset, 0x00); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_PairedAccountId = GetPsaPaKey(kMatterConfig_KeyOffset, 0x01); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_ServiceId = GetPsaPaKey(kMatterConfig_KeyOffset, 0x02); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_LastUsedEpochKeyId = GetPsaPaKey(kMatterConfig_KeyOffset, 0x03); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_FailSafeArmed = GetPsaPaKey(kMatterConfig_KeyOffset, 0x04); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_WiFiStationSecType = GetPsaPaKey(kMatterConfig_KeyOffset, 0x05); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_RegulatoryLocation = GetPsaPaKey(kMatterConfig_KeyOffset, 0x06); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_CountryCode = GetPsaPaKey(kMatterConfig_KeyOffset, 0x07); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_LocationCapability = GetPsaPaKey(kMatterConfig_KeyOffset, 0x08); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_UniqueId = GetPsaPaKey(kMatterConfig_KeyOffset, 0x09); + +// Keys stored in the Matter counters group +const KVPsaPsStore::Key KVPsaPsStore::kCounterKey_RebootCount = GetPsaPaKey(kMatterCounter_KeyOffset, 0x00); +const KVPsaPsStore::Key KVPsaPsStore::kCounterKey_UpTime = GetPsaPaKey(kMatterCounter_KeyOffset, 0x01); +const KVPsaPsStore::Key KVPsaPsStore::kCounterKey_TotalOperationalHours = GetPsaPaKey(kMatterCounter_KeyOffset, 0x02); +const KVPsaPsStore::Key KVPsaPsStore::kCounterKey_BootReason = GetPsaPaKey(kMatterCounter_KeyOffset, 0x03); + +// Keys stored in the Matter key-value group +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_KvsStringKeyMap = GetPsaPaKey(kMatterKvs_KeyOffset, 0x00); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_KvsFirstKeySlot = GetPsaPaKey(kMatterKvs_KeyOffset, 0x01); +const KVPsaPsStore::Key KVPsaPsStore::kConfigKey_KvsLastKeySlot = GetPsaPaKey(kMatterKvs_KeyOffset, KVS_MAX_ENTRIES); + +// NVS helper variables +const KVPsaPsStore::Key KVPsaPsStore::kMinConfigKey_MatterConfig = GetPsaPaKey(kMatterConfig_KeyOffset, 0x00); +const KVPsaPsStore::Key KVPsaPsStore::kMaxConfigKey_MatterConfig = GetPsaPaKey(kMatterConfig_KeyOffset, 0xFF); +const KVPsaPsStore::Key KVPsaPsStore::kMinConfigKey_MatterCounter = GetPsaPaKey(kMatterCounter_KeyOffset, 0x00); +const KVPsaPsStore::Key KVPsaPsStore::kMaxConfigKey_MatterCounter = GetPsaPaKey(kMatterCounter_KeyOffset, 0xFF); + +const KVPsaPsStore::Key KVPsaPsStore::kMinMatterPsaPaKeyRegion = GetPsaPaKey(kMatterFactory_KeyOffset, 0x00); +const KVPsaPsStore::Key KVPsaPsStore::kMaxMatterPsaPaKeyRegion = GetPsaPaKey(kMatterKvs_KeyOffset, 0xFF); + +char mKvsStoredKeyString[KVS_MAX_ENTRIES][PersistentStorageDelegate::kKeyLengthMax + 1]; +chip::System::Mutex mKvsStoredKeyMutex; + +bool KVPsaPsStore::initialized = false; + +CHIP_ERROR KVPsaPsStore::Init(void) +{ + if (initialized) + { + return CHIP_NO_ERROR; + } + + memset(mKvsStoredKeyString, 0, sizeof(mKvsStoredKeyString)); + size_t outLen; + CHIP_ERROR err = ReadConfigValueBin(kConfigKey_KvsStringKeyMap, reinterpret_cast(mKvsStoredKeyString), + sizeof(mKvsStoredKeyString), outLen); + + if ((err != CHIP_NO_ERROR) && (err != CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND)) // Initial boot + { + return err; + } + + chip::System::Mutex::Init(mKvsStoredKeyMutex); + initialized = true; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::ReadConfigValue(Key key, bool & val) +{ + if (!ConfigValueExists(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + size_t actual_size = 0; + CHIP_ERROR err = PsaStatus2ChipError(psa_ps_get(key, 0, sizeof(val), reinterpret_cast(&val), &actual_size)); + if (err != CHIP_NO_ERROR) + { + return err; + } + + if (actual_size != sizeof(val)) + { + return CHIP_ERROR_BAD_REQUEST; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::ReadConfigValue(Key key, uint32_t & val) +{ + + if (!ConfigValueExists(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + size_t actual_size = 0; + CHIP_ERROR err = PsaStatus2ChipError(psa_ps_get(key, 0, sizeof(val), reinterpret_cast(&val), &actual_size)); + if (err != CHIP_NO_ERROR) + { + return err; + } + + if (actual_size != sizeof(val)) + { + return CHIP_ERROR_BAD_REQUEST; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::ReadConfigValue(Key key, uint64_t & val) +{ + if (!ConfigValueExists(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + size_t actual_size = 0; + CHIP_ERROR err = PsaStatus2ChipError(psa_ps_get(key, 0, sizeof(val), reinterpret_cast(&val), &actual_size)); + if (err != CHIP_NO_ERROR) + { + return err; + } + + if (actual_size != sizeof(val)) + { + return CHIP_ERROR_BAD_REQUEST; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) +{ + // Note: The system expect adding the terminator char. + CHIP_ERROR err = ReadConfigValueBin(key, reinterpret_cast(buf), (bufSize - 1), outLen); + if (err != CHIP_NO_ERROR) + { + return err; + } + + buf[outLen] = 0; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) +{ + return ReadConfigValueBin(key, buf, bufSize, outLen, 0); +} + +CHIP_ERROR KVPsaPsStore::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen, size_t offset) +{ + size_t keySize; + if (!ConfigValueExists(key, keySize)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + if (buf != NULL) + { + size_t actual_size = 0; + size_t readLength = bufSize >= (keySize - offset) ? keySize - offset : bufSize; + CHIP_ERROR err = PsaStatus2ChipError(psa_ps_get(key, offset, readLength, reinterpret_cast(buf), &actual_size)); + if (err != CHIP_NO_ERROR) + { + return err; + } + + outLen = actual_size; + if (bufSize < keySize - offset) + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::ReadConfigValueCounter(Key counterId, uint32_t & val) +{ + Key key = kMinConfigKey_MatterCounter + counterId; + + if (!ConfigValueExists(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + size_t actual_size = 0; + CHIP_ERROR err = PsaStatus2ChipError(psa_ps_get(key, 0, sizeof(val), reinterpret_cast(&val), &actual_size)); + if (err != CHIP_NO_ERROR) + { + return err; + } + + if (actual_size != sizeof(val)) + { + return CHIP_ERROR_BAD_REQUEST; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::WriteConfigValue(Key key, bool val) +{ + if (!ValidConfigKey(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + CHIP_ERROR err = PsaStatus2ChipError(psa_ps_set(key, sizeof(val), reinterpret_cast(&val), PSA_STORAGE_FLAG_NONE)); + if (err != CHIP_NO_ERROR) + { + return err; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::WriteConfigValue(Key key, uint32_t val) +{ + if (!ValidConfigKey(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + CHIP_ERROR err = PsaStatus2ChipError(psa_ps_set(key, sizeof(val), reinterpret_cast(&val), PSA_STORAGE_FLAG_NONE)); + if (err != CHIP_NO_ERROR) + { + return err; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::WriteConfigValue(Key key, uint64_t val) +{ + if (!ValidConfigKey(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + CHIP_ERROR err = PsaStatus2ChipError(psa_ps_set(key, sizeof(val), reinterpret_cast(&val), PSA_STORAGE_FLAG_NONE)); + if (err != CHIP_NO_ERROR) + { + return err; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::WriteConfigValueStr(Key key, const char * str) +{ + return WriteConfigValueBin(key, reinterpret_cast(str), (str != NULL) ? strlen(str) : 0); +} + +CHIP_ERROR KVPsaPsStore::WriteConfigValueStr(Key key, const char * str, size_t strLen) +{ + return WriteConfigValueBin(key, reinterpret_cast(str), (strLen > 0) ? strLen : 1); +} + +CHIP_ERROR KVPsaPsStore::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) +{ + if (!ValidConfigKey(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + // Two different behavior: If the pointer is not null, the value is updated + // or create. If the pointer is null, the key is removed if it exist. + if (data != nullptr) + { + CHIP_ERROR err = PsaStatus2ChipError( + psa_ps_set(key, dataLen, const_cast(reinterpret_cast(data)), PSA_STORAGE_FLAG_NONE)); + if (err != CHIP_NO_ERROR) + { + return err; + } + } + else if (ConfigValueExists(key)) + { + return ClearConfigValue(key); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::WriteConfigValueCounter(Key counterId, uint32_t val) +{ + Key key = kMinConfigKey_MatterCounter + counterId; + + if (!ValidConfigKey(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + CHIP_ERROR err = PsaStatus2ChipError(psa_ps_set(key, sizeof(val), reinterpret_cast(&val), PSA_STORAGE_FLAG_NONE)); + if (err != CHIP_NO_ERROR) + { + return err; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::ClearConfigValue(Key key) +{ + if (!ValidConfigKey(key)) + { + return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + } + + CHIP_ERROR err = PsaStatus2ChipError(psa_ps_remove(key)); + if (err != CHIP_NO_ERROR) + { + return err; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::FactoryResetConfig() +{ + // Deletes all Config and KVS group objects. + // Factory and Counter type objects are NOT deleted. + + if (Init() != CHIP_NO_ERROR) + { + return CHIP_ERROR_INTERNAL; + } + + // Iterate over all the Matter Config objects and delete each one. + CHIP_ERROR err = ForEachObject(kMinConfigKey_MatterConfig, kMaxConfigKey_MatterConfig, false, + [](const Key & key, const size_t & size) -> CHIP_ERROR { return ClearConfigValue(key); }); + if (err != CHIP_NO_ERROR) + { + return err; + } + + // Iterate over all the Matter KVS objects and delete each one (including KVS key map). + err = ForEachObject(kConfigKey_KvsStringKeyMap, kConfigKey_KvsLastKeySlot, false, + [](const Key & key, const size_t & size) -> CHIP_ERROR { return ClearConfigValue(key); }); + if (err != CHIP_NO_ERROR) + { + return err; + } + + mKvsStoredKeyMutex.Lock(); + memset(mKvsStoredKeyString, 0, sizeof(mKvsStoredKeyString)); + mKvsStoredKeyMutex.Unlock(); + + return err; +} + +void KVPsaPsStore::RunConfigUnitTest() +{ + // Run common unit test. + ::chip::DeviceLayer::Internal::RunConfigUnitTest(); +} + +bool KVPsaPsStore::ValidConfigKey(Key key) +{ + // Returns true if the key is in the Matter reserved key range. + return ((key >= kMinMatterPsaPaKeyRegion) && (key <= kMaxMatterPsaPaKeyRegion)); +} + +bool KVPsaPsStore::ValidKvsKey(Key key) +{ + // Returns true if the key is in the KVS group range. + return ((key >= kConfigKey_KvsFirstKeySlot) && (key <= kConfigKey_KvsLastKeySlot)); +} + +void KVPsaPsStore::KVSKeyMapUpdate() +{ + OnScheduleKVSKeyMapUpdate(nullptr, nullptr); +} + +void KVPsaPsStore::ScheduleKVSKeyMapUpdate() +{ + CHIP_ERROR err = SystemLayer().StartTimer( + std::chrono::duration_cast(System::Clock::Seconds32(KVS_KEY_MAP_UPDATE_DELAY_SEC)), + OnScheduleKVSKeyMapUpdate, NULL); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Start KVS key map update timer failed: %" CHIP_ERROR_FORMAT, err.Format()); + } +} + +void KVPsaPsStore::OnScheduleKVSKeyMapUpdate(System::Layer * systemLayer, void * appState) +{ + mKvsStoredKeyMutex.Lock(); + CHIP_ERROR err = WriteConfigValueBin(kConfigKey_KvsStringKeyMap, reinterpret_cast(mKvsStoredKeyString), + sizeof(mKvsStoredKeyString)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "KVS key map update failed: %" CHIP_ERROR_FORMAT, err.Format()); + } + mKvsStoredKeyMutex.Unlock(); +} + +bool KVPsaPsStore::ConfigValueExists(Key key, size_t & size) +{ + if (!ValidConfigKey(key)) + { + return false; + } + + psa_storage_info_t info; + psa_status_t status = psa_ps_get_info(key, &info); + if (status == PSA_SUCCESS) + { + size = info.size; + } + + return (status == PSA_SUCCESS); +} + +bool KVPsaPsStore::ConfigValueExists(Key key) +{ + size_t size; + return ConfigValueExists(key, size); +} + +CHIP_ERROR KVPsaPsStore::ForEachObject(Key firstKey, Key lastKey, bool addNewRecord, ForEachObjectFunct funct) +{ + CHIP_ERROR err; + // Iterates through the specified range of object key ids. + // Invokes the callers CB function when appropriate. + + for (Key key = firstKey; key <= lastKey; ++key) + { + // Check if object with current key exists. + psa_storage_info_t info; + psa_status_t status = psa_ps_get_info(key, &info); + switch (status) + { + case PSA_SUCCESS: + if (!addNewRecord) + { + // Invoke the caller's function + // (for retrieve,store,delete,enumerate GroupKey operations). + err = funct(key, info.size); + } + break; + case PSA_ERROR_DOES_NOT_EXIST: + if (addNewRecord) + { + // Invoke caller's function + // (for add GroupKey operation). + err = funct(key, info.size); + } + break; + default: + err = PsaStatus2ChipError(status); + break; + } + + if (err != CHIP_NO_ERROR) + { + return err; + } + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR KVPsaPsStore::PsaStatus2ChipError(psa_status_t status) +{ + CHIP_ERROR err; + + switch (status) + { + case PSA_SUCCESS: + err = CHIP_NO_ERROR; + break; + case PSA_ERROR_DOES_NOT_EXIST: + err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; + break; + default: + err = CHIP_ERROR(ChipError::Range::kPlatform, (status * (-1))); + break; + } + + return err; +} + +#define CONVERT_INDEX_TO_KEY(index) (KVPsaPsStore::kConfigKey_KvsFirstKeySlot + index) +#define CONVERT_KEY_TO_INDEX(key) (key - KVPsaPsStore::kConfigKey_KvsFirstKeySlot) + +KVPsaPsStoreKeyBuilder::KVPsaPsStoreKeyBuilder(const char * key) +{ + uint8_t firstEmptyKeySlot = KVS_MAX_ENTRIES; + + if (KVPsaPsStore::Init() != CHIP_NO_ERROR) + { + return; + } + + valid = false; + existing = false; + mKvsStoredKeyMutex.Lock(); + + // Check if key already exists, find the first empty slot in the same time + for (uint8_t keyIndex = 0; keyIndex < KVS_MAX_ENTRIES; keyIndex++) + { + if (strcmp(key, mKvsStoredKeyString[keyIndex]) == 0) + { + keyValue = CONVERT_INDEX_TO_KEY(keyIndex); + if (KVPsaPsStore::ValidKvsKey(keyValue)) + { + valid = true; + existing = true; + } + return; + } + + if ((keyIndex < firstEmptyKeySlot) && (mKvsStoredKeyString[keyIndex][0] == 0)) + { + firstEmptyKeySlot = keyIndex; + } + } + + // Key does not exist, reserve a slot for it + keyValue = CONVERT_INDEX_TO_KEY(firstEmptyKeySlot); + if (KVPsaPsStore::ValidKvsKey(keyValue)) + { + memset(buffer, 0, sizeof(buffer)); + size_t keyLength = strlen(key) <= (sizeof(buffer) - 1) ? strlen(key) : (sizeof(buffer) - 1); + if (keyLength < strlen(key)) + { + ChipLogError(DeviceLayer, "String key length is too long. Truncated to %d bytes", (sizeof(buffer) - 1)); + } + memcpy(buffer, key, keyLength); + buffer[keyLength] = 0; + + valid = true; + } +} + +KVPsaPsStoreKeyBuilder::~KVPsaPsStoreKeyBuilder() +{ + mKvsStoredKeyMutex.Unlock(); +} + +void KVPsaPsStoreKeyBuilder::AddKey() +{ + if (!valid || existing) + { + return; + } + + uint32_t keyIndex = CONVERT_KEY_TO_INDEX(keyValue); + memset(mKvsStoredKeyString[keyIndex], 0, sizeof(mKvsStoredKeyString[keyIndex])); + Platform::CopyString(mKvsStoredKeyString[keyIndex], buffer); + KVPsaPsStore::ScheduleKVSKeyMapUpdate(); +} + +void KVPsaPsStoreKeyBuilder::RemoveKey() +{ + if (!valid) + { + return; + } + + uint32_t keyIndex = CONVERT_KEY_TO_INDEX(keyValue); + memset(mKvsStoredKeyString[keyIndex], 0, sizeof(mKvsStoredKeyString[keyIndex])); + KVPsaPsStore::ScheduleKVSKeyMapUpdate(); +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/openiotsdk/KVPsaPsStore.h b/src/platform/openiotsdk/KVPsaPsStore.h new file mode 100644 index 00000000000000..b66c9cf669df63 --- /dev/null +++ b/src/platform/openiotsdk/KVPsaPsStore.h @@ -0,0 +1,196 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Open IoT SDK key-value storage base on flash TDBStore. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +using namespace chip::Platform::PersistedStorage; + +// PSA Protected Storage interface provides 64-bit ID number, +// For Matter we reserved region ranges from 0x00010000 to 0x0001FFFF +// e.g. key = 0x010214 +// '01' = Matter region +// '02' = the sub region group base offset (Factory, Config, Counter or KVS) +// '14' = the id offset inside the group. +constexpr Key kMatterPsaPaKeyRegion = 0x010000U; +constexpr inline Key GetPsaPaKey(Key group, uint8_t id) +{ + return kMatterPsaPaKeyRegion | (group) << 8 | id; +} + +#define KVS_MAX_ENTRIES 30 + +#define KVS_KEY_MAP_UPDATE_DELAY_SEC 5 + +/** + * This class provides access to configuration information for Open IoT SDK platform + * stored in PSA Protected Storage. + */ +class KVPsaPsStore +{ +public: + using Key = chip::Platform::PersistedStorage::Key; + + // Persistent config values set at manufacturing time. Retained during factory reset. + static const Key kMatterFactory_KeyOffset; + // Persistent config values set at runtime. Cleared during factory reset. + static const Key kMatterConfig_KeyOffset; + // Persistent counter values set at runtime. Retained during factory reset. + static const Key kMatterCounter_KeyOffset; + // Persistent config values set at runtime. Cleared during factory reset. + static const Key kMatterKvs_KeyOffset; + + // Key definitions for well-known keys. + // Factory keys + static const Key kConfigKey_SerialNum; + static const Key kConfigKey_MfrDeviceId; + static const Key kConfigKey_MfrDeviceCert; + static const Key kConfigKey_MfrDeviceICACerts; + static const Key kConfigKey_MfrDevicePrivateKey; + static const Key kConfigKey_HardwareVersion; + static const Key kConfigKey_ManufacturingDate; + static const Key kConfigKey_SetupPinCode; + static const Key kConfigKey_SetupDiscriminator; + static const Key kConfigKey_Spake2pIterationCount; + static const Key kConfigKey_Spake2pSalt; + static const Key kConfigKey_Spake2pVerifier; + static const Key kConfigKey_VendorId; + static const Key kConfigKey_ProductId; + + // Config Keys + static const Key kConfigKey_ServiceConfig; + static const Key kConfigKey_PairedAccountId; + static const Key kConfigKey_ServiceId; + static const Key kConfigKey_LastUsedEpochKeyId; + static const Key kConfigKey_FailSafeArmed; + static const Key kConfigKey_WiFiStationSecType; + static const Key kConfigKey_RegulatoryLocation; + static const Key kConfigKey_CountryCode; + static const Key kConfigKey_LocationCapability; + static const Key kConfigKey_UniqueId; + + // Counter Keys + static const Key kCounterKey_RebootCount; + static const Key kCounterKey_UpTime; + static const Key kCounterKey_TotalOperationalHours; + static const Key kCounterKey_BootReason; + + // KVS storage Keys + static const Key kConfigKey_KvsStringKeyMap; + static const Key kConfigKey_KvsFirstKeySlot; + static const Key kConfigKey_KvsLastKeySlot; + + // NVS helper variables + static const Key kMinConfigKey_MatterConfig; + static const Key kMaxConfigKey_MatterConfig; + static const Key kMinConfigKey_MatterCounter; + static const Key kMaxConfigKey_MatterCounter; + + static const Key kMinMatterPsaPaKeyRegion; + static const Key kMaxMatterPsaPaKeyRegion; + + static CHIP_ERROR Init(void); + + // Config value accessors. + static CHIP_ERROR ReadConfigValue(Key key, bool & val); + static CHIP_ERROR ReadConfigValue(Key key, uint32_t & val); + static CHIP_ERROR ReadConfigValue(Key key, uint64_t & val); + static CHIP_ERROR ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen); + static CHIP_ERROR ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen); + static CHIP_ERROR ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen, size_t offset); + static CHIP_ERROR ReadConfigValueCounter(Key counterId, uint32_t & val); + + static CHIP_ERROR WriteConfigValue(Key key, bool val); + static CHIP_ERROR WriteConfigValue(Key key, uint32_t val); + static CHIP_ERROR WriteConfigValue(Key key, uint64_t val); + static CHIP_ERROR WriteConfigValueStr(Key key, const char * str); + static CHIP_ERROR WriteConfigValueStr(Key key, const char * str, size_t strLen); + static CHIP_ERROR WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen); + static CHIP_ERROR WriteConfigValueCounter(Key counterId, uint32_t val); + + static CHIP_ERROR ClearConfigValue(Key key); + + // Additional functions + static CHIP_ERROR FactoryResetConfig(void); + static void RunConfigUnitTest(void); + static bool ConfigValueExists(Key key); + static bool ValidKvsKey(Key key); + static void KVSKeyMapUpdate(void); + static void ScheduleKVSKeyMapUpdate(void); + +protected: + using ForEachObjectFunct = std::function; + static CHIP_ERROR ForEachObject(Key firstKey, Key lastKey, bool addNewRecord, ForEachObjectFunct funct); + +private: + // NVS helper functions. + static bool ValidConfigKey(Key key); + static bool ConfigValueExists(Key key, size_t & size); + static CHIP_ERROR PsaStatus2ChipError(psa_status_t status); + static void OnScheduleKVSKeyMapUpdate(System::Layer * systemLayer, void * appState); + + static bool initialized; +}; + +class KVPsaPsStoreKeyBuilder +{ +public: + KVPsaPsStoreKeyBuilder(const char * key); + + ~KVPsaPsStoreKeyBuilder(); + + void AddKey(void); + void RemoveKey(void); + + KVPsaPsStore::Key GetKey() const; + +private: + KVPsaPsStore::Key keyValue; + char buffer[PersistentStorageDelegate::kKeyLengthMax + 1]; + bool valid; + bool existing; +}; + +inline KVPsaPsStore::Key KVPsaPsStoreKeyBuilder::GetKey() const +{ + return valid ? keyValue : 0; +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + +using KVStoreConfig = chip::DeviceLayer::Internal::KVPsaPsStore; +using KVStoreKeyBuilder = chip::DeviceLayer::Internal::KVPsaPsStoreKeyBuilder; diff --git a/src/platform/openiotsdk/KeyValueStoreManagerImpl.cpp b/src/platform/openiotsdk/KeyValueStoreManagerImpl.cpp index e88772995c41c0..fb5268d494139f 100644 --- a/src/platform/openiotsdk/KeyValueStoreManagerImpl.cpp +++ b/src/platform/openiotsdk/KeyValueStoreManagerImpl.cpp @@ -27,101 +27,77 @@ #include #include -#include -using chip::DeviceLayer::Internal::OpenIoTSDKConfig; +#include CHIP_OPEN_IOT_SDK_KV_STORE_CONFIG_INCLUDE + +using namespace ::chip::DeviceLayer::Internal; namespace chip { namespace DeviceLayer { namespace PersistedStorage { -class KeyBuilder +CHIP_ERROR KeyValueStoreManagerImpl::ToKeyValueStoreManagerError(CHIP_ERROR err) { -public: - KeyBuilder(const char * key) - { - // Check sign by sign if key contains illegal characters - // Each illegal character will be replaced by '!' + capital encoded letter value - char * out = buffer + strlen(buffer); - char * illegal_ptr; - while ((out < buffer + sizeof(buffer) - 3) && *key) // 2 chars for potential illegal char + 1 for \0 - { - illegal_ptr = strchr(illegalCharacters, *key); - if (illegal_ptr) - { - *out++ = '!'; - *out++ = 'A' + (int) (illegal_ptr - illegalCharacters); - } - else - { - *out++ = *key; - } - key++; - } - valid = true; - } - - const char * str() const { return valid ? buffer : nullptr; } + return err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND ? CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND : err; +} -private: - char buffer[100] = "chip-kvs-"; - bool valid; - // Mbed KV storage does not accept these characters in the key definition - const char * illegalCharacters = " */?:;\"|<>\\"; -}; +CHIP_ERROR KeyValueStoreManagerImpl::Init(void) +{ + return KVStoreConfig::Init(); +} -// NOTE: Currently this platform does not support partial and offset reads -// these will return CHIP_ERROR_NOT_IMPLEMENTED. CHIP_ERROR KeyValueStoreManagerImpl::_Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size, size_t offset) { - if (offset > 0) - { - // Offset and partial reads are not supported. - // Support can be added in the future if this is needed. - return CHIP_ERROR_NOT_IMPLEMENTED; - } - - KeyBuilder key_builder(key); - if (!key_builder.str()) + KVStoreKeyBuilder key_builder(key); + if (!key_builder.GetKey()) { return CHIP_ERROR_PERSISTED_STORAGE_FAILED; } - auto err = - OpenIoTSDKConfig::ReadConfigValueBin(key_builder.str(), reinterpret_cast(value), value_size, *read_bytes_size); - if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + size_t outLen; + CHIP_ERROR err = ToKeyValueStoreManagerError( + KVStoreConfig::ReadConfigValueBin(key_builder.GetKey(), reinterpret_cast(value), value_size, outLen, offset)); + if (read_bytes_size) { - err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + *read_bytes_size = outLen; } return err; } CHIP_ERROR KeyValueStoreManagerImpl::_Delete(const char * key) { - KeyBuilder key_builder(key); - if (!key_builder.str()) + KVStoreKeyBuilder key_builder(key); + if (!key_builder.GetKey()) { return CHIP_ERROR_PERSISTED_STORAGE_FAILED; } - auto err = OpenIoTSDKConfig::ClearConfigValue(key_builder.str()); - if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + CHIP_ERROR err = ToKeyValueStoreManagerError(KVStoreConfig::ClearConfigValue(key_builder.GetKey())); + if (err == CHIP_NO_ERROR) { - err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + key_builder.RemoveKey(); } + return err; } CHIP_ERROR KeyValueStoreManagerImpl::_Put(const char * key, const void * value, size_t value_size) { - KeyBuilder key_builder(key); - if (!key_builder.str()) + KVStoreKeyBuilder key_builder(key); + if (!key_builder.GetKey()) { return CHIP_ERROR_PERSISTED_STORAGE_FAILED; } - return OpenIoTSDKConfig::WriteConfigValueBin(key_builder.str(), reinterpret_cast(value), value_size); + CHIP_ERROR err = ToKeyValueStoreManagerError( + KVStoreConfig::WriteConfigValueBin(key_builder.GetKey(), reinterpret_cast(value), value_size)); + if (err == CHIP_NO_ERROR) + { + key_builder.AddKey(); + } + + return err; } KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; diff --git a/src/platform/openiotsdk/KeyValueStoreManagerImpl.h b/src/platform/openiotsdk/KeyValueStoreManagerImpl.h index 9257c33c6f25d7..3b13ef410444f6 100644 --- a/src/platform/openiotsdk/KeyValueStoreManagerImpl.h +++ b/src/platform/openiotsdk/KeyValueStoreManagerImpl.h @@ -37,12 +37,9 @@ class KeyValueStoreManagerImpl final : public KeyValueStoreManager friend class KeyValueStoreManager; public: - // NOTE: Currently this platform does not support partial and offset reads - // these will return CHIP_ERROR_NOT_IMPLEMENTED. + CHIP_ERROR Init(void); CHIP_ERROR _Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size = nullptr, size_t offset = 0); - CHIP_ERROR _Delete(const char * key); - CHIP_ERROR _Put(const char * key, const void * value, size_t value_size); private: @@ -50,6 +47,8 @@ class KeyValueStoreManagerImpl final : public KeyValueStoreManager friend KeyValueStoreManager & KeyValueStoreMgr(); friend KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(); + CHIP_ERROR ToKeyValueStoreManagerError(CHIP_ERROR err); + static KeyValueStoreManagerImpl sInstance; };