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