diff --git a/config/silabs/Kconfig b/config/silabs/Kconfig index 993ba006d52..3b2372218d0 100644 --- a/config/silabs/Kconfig +++ b/config/silabs/Kconfig @@ -1,17 +1,17 @@ # -# Copyright (c) 2021 Project CHIP Authors +#Copyright(c) 2021 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 +#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 +#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. +#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. # rsource "../zephyr/Kconfig" @@ -19,12 +19,12 @@ rsource "../zephyr/Kconfig" if CHIP menu "Silabs Matter Config" -# See config/zephyr/Kconfig for full definition +#See config / zephyr / Kconfig for full definition config CHIP_DEVICE_VENDOR_NAME string "Vendor Name" default "Silicon Laboratories" -# See config/zephyr/Kconfig for full definition +#See config / zephyr / Kconfig for full definition config CHIP_OTA_REQUESTOR bool "Enable OTA Requestor" default n @@ -38,8 +38,8 @@ config CHIP_OTA_IMAGE_BUILD default y if CHIP_OTA_REQUESTOR depends on SIGN_IMAGES -# Sign the application with the MCUboot ECDSA-P256 development key. Only relevant -# for MCUboot/OTA builds; replace with a private key for production. +#Sign the application with the MCUboot ECDSA - P256 development key.Only relevant +#for MCUboot / OTA builds; replace with a private key for production. config MCUBOOT_SIGNATURE_KEY_FILE default "bootloader/mcuboot/root-ec-p256.pem" depends on BOOTLOADER_MCUBOOT @@ -74,10 +74,11 @@ config CHIP_FACTORY_DATA bool "Use provisioned factory data from Zephyr settings" default n help - Enables Provision::Storage (ProvisionStorageZephyr) that reads provisioned - credentials and commissionable data from Zephyr settings stored in the - storage partition. Factory data is expected to be provisioned into NVS - separately using Silicon Labs generator firmware. + Enables ProvisionStorageReader, which reads + provisioned credentials and commissionable data from Zephyr settings + stored in the storage partition. Factory data is expected to be + provisioned into NVS separately using Silicon Labs generator + firmware. config CHIP_FACTORY_DATA_ROTATING_DEVICE_UID_MAX_LEN int "Maximum length of rotating device ID unique ID in bytes" @@ -90,7 +91,7 @@ config CHIP_FACTORY_RESET_ERASE_SETTINGS default n depends on NVS || ZMS help - Enables storage partition wipe on factory reset. Enabling also wipes + Enables storage partition wipe on factory reset. Enabling also wipes provisioned data. Disabling only resets relevant entries. config CHIP_OPENTHREAD_JOINER_ENABLED @@ -120,7 +121,7 @@ config CHIP_FACTORY_RESET_ON_KEY_MIGRATION_FAILURE config CHIP_PERSISTENT_SUBSCRIPTIONS default n - # selecting experimental for this feature since there is an issue with multiple controllers. +#selecting experimental for this feature since there is an issue with multiple controllers. select EXPERIMENTAL config CHIP_MAX_FABRICS @@ -164,7 +165,7 @@ config CHIP_ENABLE_BDX_LOG_TRANSFER help Enables the BDX protocol for diagnostics log transfer purposes. -# See config/common/cmake/Kconfig for full definition +#See config / common / cmake / Kconfig for full definition config CHIP_WIFI select WIFI imply NET_STATISTICS @@ -178,21 +179,21 @@ config CHIP_WIFI config CHIP_MEMORY_PROFILING bool "Enable features for tracking memory usage" - # Matter stack +#Matter stack select CHIP_STATISTICS - # Heap +#Heap select CHIP_MALLOC_SYS_HEAP_WATERMARKS_SUPPORT if CHIP_MALLOC_SYS_HEAP - select SYS_HEAP_RUNTIME_STATS if CHIP_MALLOC_SYS_HEAP - # Crypto + select SYS_HEAP_RUNTIME_STATS if CHIP_MALLOC_SYS_HEAP +#Crypto select MBEDTLS_MEMORY_DEBUG if !CHIP_CRYPTO_IMPL_PSA - # Network +#Network select NET_STATISTICS select NET_SHELL select NET_BUF_POOL_USAGE select OPENTHREAD_SHELL if !CHIP_WIFI - # Settings +#Settings select SETTINGS_SHELL - # Zephyr +#Zephyr select KERNEL_SHELL help Enables features for tracking memory usage in Matter. @@ -218,18 +219,18 @@ choice CHIP_LAST_FABRIC_REMOVED_ACTION config CHIP_LAST_FABRIC_REMOVED_ERASE_AND_PAIRING_START bool "After removing the last fabric erase NVS and start Bluetooth LE advertising" help - After removing the last fabric the device will perform the factory reset without + After removing the last fabric the device will perform the factory reset without rebooting and start the Bluetooth LE advertisement automatically. - The current RAM state will be saved and the new commissioning to the next + The current RAM state will be saved and the new commissioning to the next fabric will use the next possible fabric index. This option should not be used for - devices that normally do not advertise Bluetooth LE on boot to keep their original + devices that normally do not advertise Bluetooth LE on boot to keep their original behavior. config CHIP_LAST_FABRIC_REMOVED_ERASE_ONLY bool "After removing the last fabric erase NVS only" help After removing the last fabric the device will perform the factory reset only without - rebooting. The current RAM state will be saved and the new commissioning to the next + rebooting. The current RAM state will be saved and the new commissioning to the next fabric will use the next possible fabric index. endchoice @@ -243,9 +244,9 @@ config CHIP_LAST_FABRIC_REMOVED_ACTION_DELAY an action chosen by the CHIP_LAST_FABRIC_REMOVED_ACTION option. This schedule will allow for avoiding race conditions before the device removes non-volatile data. -# ============================================================================== -# System configuration -# ============================================================================== +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == +#System configuration +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == choice LIBC_IMPLEMENTATION default NEWLIB_LIBC @@ -285,9 +286,9 @@ config NVS_LOOKUP_CACHE_SIZE config ZMS_LOOKUP_CACHE_SIZE default 512 if ZMS -# ============================================================================== -# Zephyr networking configuration -# ============================================================================== +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == +#Zephyr networking configuration +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == config NET_IPV6_MLD default y @@ -320,9 +321,9 @@ config NET_BUF_TX_COUNT config ZVFS_POLL_MAX default 6 if CHIP_WIFI -# ============================================================================== -# Bluetooth Low Energy configuration -# ============================================================================== +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == +#Bluetooth Low Energy configuration +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == config BT default y @@ -336,16 +337,16 @@ config BT_PERIPHERAL_PREF_MIN_INT config BT_PERIPHERAL_PREF_MAX_INT default 36 -# Increase BT timeout to 5 s to improve connection reliability and avoid fast drop outs. +#Increase BT timeout to 5 s to improve connection reliability and avoid fast drop outs. config BT_PERIPHERAL_PREF_TIMEOUT default 500 config BT_GAP_AUTO_UPDATE_CONN_PARAMS default y -# Decrease connection parameters update time, as some Matter controllers request -# enabling IP networking faster than BT connection parameters are updated, what may result -# in commissioning instabilities. +#Decrease connection parameters update time, as some Matter controllers request +#enabling IP networking faster than BT connection parameters are updated, what may result +#in commissioning instabilities. config BT_CONN_PARAM_UPDATE_TIMEOUT default 1000 @@ -379,11 +380,11 @@ config BT_DEVICE_NAME_GATT_WRITABLE config BT_GATT_CACHING default n -# ============================================================================== -# DFU configuration -# ============================================================================== +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == +#DFU configuration +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == config BOOT_IMAGE_ACCESS_HOOKS - default n + default n config UPDATEABLE_IMAGE_NUMBER default 1 @@ -392,9 +393,9 @@ config DFU_MULTI_IMAGE_MAX_IMAGE_COUNT int "Maximum number of images for multi-image DFU" default 1 -# ============================================================================== -# OpenThread configuration -# ============================================================================== +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == +#OpenThread configuration +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == config NET_L2_OPENTHREAD default y if !CHIP_WIFI @@ -410,9 +411,9 @@ config OPENTHREAD_DEFAULT_TX_POWER endif # NET_L2_OPENTHREAD -# ============================================================================== -# Crypto configuration -# ============================================================================== +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == +#Crypto configuration +#== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == menu "Crypto configuration" @@ -436,7 +437,7 @@ config CHIP_CRYPTO config MBEDTLS_ENABLE_HEAP bool "Enable MbedTLS heap" - default y + default y config MBEDTLS_HEAP_SIZE int "MbedTLS heap size" @@ -537,12 +538,12 @@ if CHIP_CRYPTO_IMPL_PSA default n config MBEDTLS_CMAC bool - default y + default y config MBEDTLS_USE_PSA_CRYPTO bool default y -# Extend the maximum number of PSA key slots to fit Matter requirements +#Extend the maximum number of PSA key slots to fit Matter requirements config MBEDTLS_PSA_KEY_SLOT_COUNT default 64 endif # CHIP_CRYPTO_IMPL_PSA @@ -569,7 +570,7 @@ config MBEDTLS_PKCS5_C default y config MBEDTLS_PK_WRITE_C bool - default y + default y config MBEDTLS_PK_HAVE_ECC_KEYS bool "Enable PK Have ECC Keys" default y @@ -605,7 +606,7 @@ config MBEDTLS_HAVE_ASM default y config MBEDTLS_CIPHER_CCM_ENABLED - bool + bool default y config MBEDTLS_CIPHER_AES_128_CCM @@ -622,7 +623,7 @@ config MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH if BOARD_SIWX917_RB4338A config MBEDTLS_AES_ROM_TABLES - bool + bool default y config MBEDTLS_AES_FEWER_TABLES diff --git a/examples/all-devices-app/zephyr/silabs/CMakeLists.txt b/examples/all-devices-app/zephyr/silabs/CMakeLists.txt index 054bef32281..8c3ca555b39 100644 --- a/examples/all-devices-app/zephyr/silabs/CMakeLists.txt +++ b/examples/all-devices-app/zephyr/silabs/CMakeLists.txt @@ -29,11 +29,11 @@ target_include_directories(app PRIVATE if(CONFIG_CHIP_FACTORY_DATA) target_sources(app PRIVATE - ${CHIP_ROOT}/examples/platform/silabs/provision/ProvisionStorageZephyr.cpp - ${CHIP_ROOT}/examples/platform/silabs/provision/ProvisionStorageCommon.cpp - ${CHIP_ROOT}/examples/platform/silabs/provision/ProvisionStorageCustom.cpp + ${CHIP_ROOT}/examples/platform/silabs/provision/ProvisionStorageReaderCommon.cpp + ${CHIP_ROOT}/examples/platform/silabs/provision/zephyr/ProvisionStorageReader.cpp ) target_include_directories(app PRIVATE + ${CHIP_ROOT}/examples/platform/silabs ${CHIP_ROOT}/third_party/silabs/matter_support/provision ) target_compile_definitions(app PRIVATE diff --git a/examples/all-devices-app/zephyr/silabs/SilabsAppTask.cpp b/examples/all-devices-app/zephyr/silabs/SilabsAppTask.cpp index 31b1b00b600..c6e7cb3e0d0 100644 --- a/examples/all-devices-app/zephyr/silabs/SilabsAppTask.cpp +++ b/examples/all-devices-app/zephyr/silabs/SilabsAppTask.cpp @@ -20,13 +20,13 @@ #include #include -#include #include #ifdef CONFIG_CHIP_FACTORY_DATA -#include #include #include +#include +#include #else #include #endif @@ -36,14 +36,12 @@ namespace chip::app::AllDevices { CHIP_ERROR InitSilabsCredentials() { #if CONFIG_CHIP_FACTORY_DATA - // Replace all 3 providers to use Silabs provisioning. - static DeviceLayer::Silabs::Provision::Storage sStorage; - CHIP_ERROR err = sStorage.Initialize(); - VerifyOrReturnError(err == CHIP_NO_ERROR, err, ChipLogError(DeviceLayer, "Failed to initialize provision storage.")); - - DeviceLayer::SetDeviceInstanceInfoProvider(&sStorage); - DeviceLayer::SetCommissionableDataProvider(&sStorage); - Credentials::SetDeviceAttestationCredentialsProvider(&sStorage); + // Replace all 3 providers to use the Silabs provision storage reader. + ReturnErrorOnFailure(DeviceLayer::Internal::ZephyrConfig::Init()); + auto & storageReader = DeviceLayer::Silabs::Provision::ProvisionStorageReader::GetInstance(); + DeviceLayer::SetDeviceInstanceInfoProvider(&storageReader); + DeviceLayer::SetCommissionableDataProvider(&storageReader); + Credentials::SetDeviceAttestationCredentialsProvider(&storageReader); #else // CONFIG_CHIP_FACTORY_DATA Credentials::SetDeviceAttestationCredentialsProvider(Credentials::Examples::GetExampleDACProvider()); diff --git a/examples/all-devices-app/zephyr/silabs/SilabsAppTask.h b/examples/all-devices-app/zephyr/silabs/SilabsAppTask.h index 3c5a356cbf0..777b6589234 100644 --- a/examples/all-devices-app/zephyr/silabs/SilabsAppTask.h +++ b/examples/all-devices-app/zephyr/silabs/SilabsAppTask.h @@ -25,17 +25,15 @@ namespace chip::app::AllDevices { -// Initializes the Silabs provisioning storage and points the credential providers at it. -// Uses the example credentials if CONFIG_CHIP_FACTORY_DATA is nil. +// Initializes Silabs provision storage reader and points the credential providers at it. +// Uses the example credentials if CONFIG_CHIP_FACTORY_DATA is not set. CHIP_ERROR InitSilabsCredentials(); - template class SilabsAppTask : public AppTaskBase { public: CHIP_ERROR InitCredentials() { return InitSilabsCredentials(); } - }; class AppTask final : public SilabsAppTask diff --git a/examples/lighting-app/silabs/openthread.gn b/examples/lighting-app/silabs/openthread.gn index acc23ef549a..7271e266917 100644 --- a/examples/lighting-app/silabs/openthread.gn +++ b/examples/lighting-app/silabs/openthread.gn @@ -24,7 +24,7 @@ default_args = { target_cpu = "arm" target_os = "freertos" chip_openthread_ftd = true - optimize_debug_level = "s" + optimize_debug_level = "g" import("//openthread.gni") } diff --git a/examples/lighting-app/silabs/zephyr/CMakeLists.txt b/examples/lighting-app/silabs/zephyr/CMakeLists.txt index 11c65892909..fb9df730a71 100644 --- a/examples/lighting-app/silabs/zephyr/CMakeLists.txt +++ b/examples/lighting-app/silabs/zephyr/CMakeLists.txt @@ -96,11 +96,11 @@ target_sources(app if(CONFIG_CHIP_FACTORY_DATA) target_sources(app PRIVATE - ${CHIP_ROOT}/examples/platform/silabs/provision/ProvisionStorageZephyr.cpp - ${CHIP_ROOT}/examples/platform/silabs/provision/ProvisionStorageCommon.cpp - ${CHIP_ROOT}/examples/platform/silabs/provision/ProvisionStorageCustom.cpp + ${CHIP_ROOT}/examples/platform/silabs/provision/ProvisionStorageReaderCommon.cpp + ${CHIP_ROOT}/examples/platform/silabs/provision/zephyr/ProvisionStorageReader.cpp ) target_include_directories(app PRIVATE + ${CHIP_ROOT}/examples/platform/silabs ${CHIP_ROOT}/third_party/silabs/matter_support/provision ) target_compile_definitions(app PRIVATE diff --git a/examples/platform/silabs/BaseApplication.cpp b/examples/platform/silabs/BaseApplication.cpp index b29d7295e97..7a1f2c583de 100644 --- a/examples/platform/silabs/BaseApplication.cpp +++ b/examples/platform/silabs/BaseApplication.cpp @@ -55,9 +55,12 @@ #ifdef ENABLE_CHIP_SHELL #include #endif // ENABLE_CHIP_SHELL +#include "provision/ProvisionStorageReader.h" #include +#if SL_MATTER_PROVISION_CHANNEL_ENABLED #include +#endif // SL_MATTER_PROVISION_CHANNEL_ENABLED #include #include #include @@ -1073,11 +1076,13 @@ void BaseApplication::DispatchEvent(AppEvent * aEvent) void BaseApplication::ScheduleFactoryReset() { TEMPORARY_RETURN_IGNORED PlatformMgr().ScheduleWork([](intptr_t) { - // Press both buttons to request provisioning + // Press both buttons to request provisioning +#if SL_MATTER_PROVISION_CHANNEL_ENABLED if (GetPlatform().GetButtonState(APP_ACTION_BUTTON)) { TEMPORARY_RETURN_IGNORED Provision::Manager::GetInstance().SetProvisionRequired(true); } +#endif // SL_MATTER_PROVISION_CHANNEL_ENABLED #if defined(SL_WIFI) && SL_WIFI // Removing the matter services on factory reset TEMPORARY_RETURN_IGNORED chip::Dnssd::ServiceAdvertiser::Instance().RemoveServices(); @@ -1223,12 +1228,12 @@ void BaseApplication::OnPlatformEvent(const ChipDeviceEvent * event, intptr_t) void BaseApplication::OutputQrCode(bool refreshLCD) { (void) refreshLCD; // could be unused - +#if SL_MATTER_QR_CODE_ENABLED || SILABS_LOG_ENABLED // Create buffer for the Qr code setup payload that can fit max size and null terminator. char setupPayloadBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; chip::MutableCharSpan setupPayload(setupPayloadBuffer); - CHIP_ERROR err = Provision::Manager::GetInstance().GetStorage().GetSetupPayload(setupPayload); + CHIP_ERROR err = Provision::ProvisionStorageReader::GetInstance().GetSetupPayload(setupPayload); if (CHIP_NO_ERROR == err) { // Print setup info on LCD if available @@ -1246,6 +1251,7 @@ void BaseApplication::OutputQrCode(bool refreshLCD) { ChipLogError(AppServer, "Getting QR code failed!"); } +#endif // SL_MATTER_QR_CODE_ENABLED || SILABS_LOG_ENABLED } bool BaseApplication::GetProvisionStatus() diff --git a/examples/platform/silabs/MatterConfig.cpp b/examples/platform/silabs/MatterConfig.cpp index 2017f12465c..87205c2b01a 100644 --- a/examples/platform/silabs/MatterConfig.cpp +++ b/examples/platform/silabs/MatterConfig.cpp @@ -66,7 +66,15 @@ static chip::DeviceLayer::Internal::Efr32PsaOperationalKeystore gOperationalKeys #if !SL_MATTER_USE_CODE_DRIVEN_DATA_MODEL #include #endif // !SL_MATTER_USE_CODE_DRIVEN_DATA_MODEL +#include "provision/ProvisionStorageReader.h" +#if SL_MATTER_PROVISION_CHANNEL_ENABLED +#include "provision/ProvisionChannel.h" +#include "provision/ProvisionCrypto.h" +#include "provision/ProvisionStorageWriter.h" #include +#elif defined(SL_MATTER_ENABLE_MULTI_OTA_REQUESTOR) && SL_MATTER_ENABLE_MULTI_OTA_REQUESTOR +#include "provision/ProvisionStorageWriter.h" +#endif #include #ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLED @@ -224,11 +232,6 @@ void ApplicationStart(void * unused) SILABS_TRACE_END(TimeTraceOperation::kMatterInit); SILABS_TRACE_BEGIN(TimeTraceOperation::kAppInit); - chip::DeviceLayer::PlatformMgr().LockChipStack(); - // Initialize device attestation config - SetDeviceAttestationCredentialsProvider(&Provision::Manager::GetInstance().GetStorage()); - chip::DeviceLayer::PlatformMgr().UnlockChipStack(); - err = AppTask::GetAppTask().StartAppTask(); if (err != CHIP_NO_ERROR) appError(err); @@ -300,6 +303,25 @@ CHIP_ERROR SilabsMatterConfig::InitMatter(const char * appName) #endif // CHIP_CONFIG_ENABLE_ICD_SERVER #endif // SL_WIFI + // The reader owns its singleton instance because Matter stores these + // provider pointers for the lifetime of the application. It requires no + // Provision Core initialization and exposes no write capability. + auto & provisionStorageReader = Provision::ProvisionStorageReader::GetInstance(); +#if SL_MATTER_PROVISION_CHANNEL_ENABLED + auto & provisionManager = Provision::Manager::GetInstance(); + auto & provisionStorageWriter = Provision::ProvisionStorageWriter::GetInstance(); +#if defined(SLI_SI91X_MCU_INTERFACE) && SLI_SI91X_MCU_INTERFACE + ReturnErrorOnFailure(provisionStorageWriter.Initialize()); +#endif + provisionManager.SetStorageBackend(provisionStorageReader, &provisionStorageWriter); + provisionManager.SetCryptoProvider(Provision::ProvisionCrypto::GetInstance()); + provisionManager.SetChannel(Provision::ProvisionChannel::GetInstance()); + provisionManager.SetResetHandler([]() { GetPlatform().SoftwareReset(); }); + ReturnErrorOnFailure(provisionManager.Init(false /*provisionByDefault*/)); +#elif defined(SL_MATTER_ENABLE_MULTI_OTA_REQUESTOR) && SL_MATTER_ENABLE_MULTI_OTA_REQUESTOR + ReturnErrorOnFailure(Provision::ProvisionStorageWriter::GetInstance().Initialize()); +#endif + err = PlatformMgr().InitChipStack(); VerifyOrReturnError(err == CHIP_NO_ERROR, err, ChipLogError(DeviceLayer, "Failed to Init Chip Stack: %" CHIP_ERROR_FORMAT, err.Format())); @@ -308,13 +330,10 @@ CHIP_ERROR SilabsMatterConfig::InitMatter(const char * appName) VerifyOrReturnError(err == CHIP_NO_ERROR, err, ChipLogError(DeviceLayer, "Failed to Set BLE Device Name: %" CHIP_ERROR_FORMAT, err.Format())); #endif - // Provision Manager - Provision::Manager & provision = Provision::Manager::GetInstance(); - ReturnErrorOnFailure(provision.Init()); - SetDeviceInstanceInfoProvider(&provision.GetStorage()); - SetCommissionableDataProvider(&provision.GetStorage()); - SetDeviceAttestationCredentialsProvider(&provision.GetStorage()); - ChipLogProgress(DeviceLayer, "Provision mode %s", provision.IsProvisionRequired() ? "ENABLED" : "disabled"); + + SetDeviceInstanceInfoProvider(&provisionStorageReader); + SetCommissionableDataProvider(&provisionStorageReader); + SetDeviceAttestationCredentialsProvider(&provisionStorageReader); // Create initParams with SDK example defaults here // TODO: replace with our own init param to avoid double allocation in examples @@ -355,8 +374,7 @@ CHIP_ERROR SilabsMatterConfig::InitMatter(const char * appName) #ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLED static SilabsTestEventTriggerDelegate sTestEventTriggerDelegate; - TEMPORARY_RETURN_IGNORED sTestEventTriggerDelegate.Init(&provision.GetStorage()); - + TEMPORARY_RETURN_IGNORED sTestEventTriggerDelegate.Init(&provisionStorageReader); initParams.testEventTriggerDelegate = &sTestEventTriggerDelegate; #endif // SL_MATTER_TEST_EVENT_TRIGGER_ENABLED diff --git a/examples/platform/silabs/OTAConfig.cpp b/examples/platform/silabs/OTAConfig.cpp index 886a671e752..17e0a6b30f3 100644 --- a/examples/platform/silabs/OTAConfig.cpp +++ b/examples/platform/silabs/OTAConfig.cpp @@ -20,6 +20,11 @@ #include "silabs_utils.h" #include +#if defined(SL_MATTER_ENABLE_MULTI_OTA_REQUESTOR) && SL_MATTER_ENABLE_MULTI_OTA_REQUESTOR +#include +#include +#endif // SL_MATTER_ENABLE_MULTI_OTA_REQUESTOR + #if SL_MATTER_USE_CODE_DRIVEN_DATA_MODEL #include // nogncheck #include // nogncheck @@ -138,7 +143,14 @@ void OTAConfig::Init() gRequestorUser.Init(&gRequestorCore, &imageProcessor); - CHIP_ERROR err = imageProcessor.Init(&gDownloader); +#if defined(SL_MATTER_ENABLE_MULTI_OTA_REQUESTOR) && SL_MATTER_ENABLE_MULTI_OTA_REQUESTOR + // The factory data OTA processor persists attestation credentials through the + // same storage writer and crypto backends used by provisioning. + CHIP_ERROR err = imageProcessor.Init(&gDownloader, chip::DeviceLayer::Silabs::Provision::ProvisionStorageWriter::GetInstance(), + chip::DeviceLayer::Silabs::Provision::ProvisionCrypto::GetInstance()); +#else + CHIP_ERROR err = imageProcessor.Init(&gDownloader); +#endif if (err != CHIP_NO_ERROR) { SILABS_LOG("Image processor init failed"); diff --git a/examples/platform/silabs/provision/BUILD.gn b/examples/platform/silabs/provision/BUILD.gn index 9d6ecf61e5f..2246eedd30a 100644 --- a/examples/platform/silabs/provision/BUILD.gn +++ b/examples/platform/silabs/provision/BUILD.gn @@ -14,57 +14,92 @@ import("//build_overrides/chip.gni") import("//build_overrides/efr32_sdk.gni") +import("${chip_root}/src/platform/silabs/multi-ota/args.gni") import("${silabs_sdk_build_root}/silabs_board.gni") +declare_args() { + sl_use_example_credentials = true +} + if (wifi_soc) { import("${silabs_sdk_build_root}/SiWx917_sdk.gni") } else { import("${silabs_sdk_build_root}/efr32_sdk.gni") } -# Seperate import since the matter_support_root is defined in the ef32_sdk.gni / SiWx917_sdk.gni +# Separate import since matter_support_root is defined in the EFR32/SiWx917 SDK imports. import("${matter_support_root}/provision/args.gni") +config("storage-config") { + include_dirs = [ ".." ] +} + source_set("storage") { + impl_folder = "default" + if (use_provision_flash_storage) { + impl_folder = "flash" + } + sources = [ - "ProvisionStorageCommon.cpp", - "ProvisionStorageCustom.cpp", + "${impl_folder}/ProvisionStorageReader.cpp", + "ProvisionCrypto.h", + "ProvisionStorageReader.h", + "ProvisionStorageReaderCommon.cpp", ] if (use_provision_flash_storage) { - sources += [ "ProvisionStorageFlash.cpp" ] - } else { - sources += [ "ProvisionStorageDefault.cpp" ] + sources += [ + "${impl_folder}/ProvisionStorageFlash.cpp", + "${impl_folder}/ProvisionStorageFlash.h", + ] } if (wifi_soc) { if (sl_si91x_crypto_flavor == "psa") { - if (is_clang) { - libs = [ "${sl_provision_root}/libs/libProvisionPSA-si917-clang.a" ] - } else { - libs = [ "${sl_provision_root}/libs/libProvisionPSA-si917.a" ] - } - } else if (is_clang) { - libs = [ "${sl_provision_root}/libs/libProvision-si917-clang.a" ] + sources += [ "ProvisionCryptoPSA.cpp" ] } else { - libs = [ "${sl_provision_root}/libs/libProvision-si917.a" ] + sources += [ "ProvisionCryptoMbed.cpp" ] } } else { - if (use_provision_flash_storage) { - if (is_clang) { - libs = [ "${sl_provision_root}/libs/libProvisionFlash-${silabs_family}-clang.a" ] - } else { - libs = - [ "${sl_provision_root}/libs/libProvisionFlash-${silabs_family}.a" ] - } + sources += [ "ProvisionCryptoPSA.cpp" ] + } + + if (sl_use_provision_channel || chip_enable_multi_ota_requestor) { + sources += [ + "${impl_folder}/ProvisionStorageWriter.cpp", + "ProvisionStorageWriter.h", + ] + } + + if (sl_use_provision_channel) { + sources += [ + "ProvisionChannel.h", + "ProvisionStorageCustom.cpp", + ] + + if (wifi_soc) { + sources += [ "ProvisionChannelSi917BLE.cpp" ] } else { - if (is_clang) { - libs = [ - "${sl_provision_root}/libs/libProvision-${silabs_family}-clang.a", - ] - } else { - libs = [ "${sl_provision_root}/libs/libProvision-${silabs_family}.a" ] - } + sources += [ "ProvisionChannelEFR32BLE.cpp" ] + } + } + + defines = [ + "SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS=${sl_use_example_credentials}", + "SL_MATTER_USE_FLASH_STORE=${use_provision_flash_storage}", + ] + + # Require the provision library when provision channel or flash storage is used + if (sl_use_provision_channel || use_provision_flash_storage) { + _provision_abi = "m33-hard" + if (wifi_soc) { + _provision_abi = "m4-softfp" } + + if (is_clang) { + _provision_abi += "-clang" + } + + libs = [ "${sl_provision_root}/libs/libProvision-${_provision_abi}.a" ] } deps = [ "${chip_root}/src/lib" ] @@ -74,7 +109,8 @@ source_set("storage") { "${sl_provision_root}:headers", ] + public_configs = [ ":storage-config" ] if (sl_enable_test_event_trigger) { - public_configs = [ "${chip_root}/examples/platform/silabs/test-event-trigger:test-event-trigger-config" ] + public_configs += [ "${chip_root}/examples/platform/silabs/test-event-trigger:test-event-trigger-config" ] } } diff --git a/examples/platform/silabs/provision/ProvisionChannel.h b/examples/platform/silabs/provision/ProvisionChannel.h new file mode 100644 index 00000000000..6172eacbc99 --- /dev/null +++ b/examples/platform/silabs/provision/ProvisionChannel.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + */ +#pragma once + +#include + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { + +class ProvisionChannel final : public IProvisionChannel +{ +public: + static ProvisionChannel & GetInstance(); + + ProvisionChannel(const ProvisionChannel &) = delete; + ProvisionChannel & operator=(const ProvisionChannel &) = delete; + + CHIP_ERROR Init() override; + CHIP_ERROR Read(uint8_t * buffer, size_t bufferLength, size_t & bytesRead) override; + CHIP_ERROR Write(const uint8_t * buffer, size_t bufferLength) override; + CHIP_ERROR OnDataAvailable() override; + +private: + ProvisionChannel() = default; +}; + +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/ProvisionChannelEFR32BLE.cpp b/examples/platform/silabs/provision/ProvisionChannelEFR32BLE.cpp new file mode 100644 index 00000000000..c2c9dd20423 --- /dev/null +++ b/examples/platform/silabs/provision/ProvisionChannelEFR32BLE.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + */ +#include "ProvisionChannel.h" + +#include +#include +#include + +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { + +namespace { +uint8_t sReceiveBuffer[Protocol2::kPackageSizeMax]; +size_t sReceiveSize = 0; +} // namespace + +ProvisionChannel & ProvisionChannel::GetInstance() +{ + static ProvisionChannel instance; + return instance; +} + +CHIP_ERROR ProvisionChannel::Init() +{ + sReceiveSize = 0; + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionChannel::Read(uint8_t * buffer, size_t bufferLength, size_t & bytesRead) +{ + VerifyOrReturnError(sReceiveSize > 0, CHIP_ERROR_READ_FAILED); + VerifyOrReturnError(buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(bufferLength >= sReceiveSize, CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(buffer, sReceiveBuffer, sReceiveSize); + bytesRead = sReceiveSize; + sReceiveSize = 0; + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionChannel::Write(const uint8_t * buffer, size_t bufferLength) +{ + VerifyOrReturnError(buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + const sl_status_t status = sl_bt_gatt_server_write_attribute_value(gattdb_CHIPoBLEChar_Tx, 0, bufferLength, buffer); + return status == SL_STATUS_OK ? CHIP_NO_ERROR : CHIP_ERROR_WRITE_FAILED; +} + +CHIP_ERROR ProvisionChannel::OnDataAvailable() +{ + const sl_status_t status = sl_bt_gatt_server_read_attribute_value(gattdb_CHIPoBLEChar_Rx, 0, Protocol2::kPackageSizeMax, + &sReceiveSize, sReceiveBuffer); + return status == SL_STATUS_OK ? CHIP_NO_ERROR : CHIP_ERROR_READ_FAILED; +} + +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/ProvisionChannelRTT.cpp b/examples/platform/silabs/provision/ProvisionChannelRTT.cpp new file mode 100644 index 00000000000..f54ee08b505 --- /dev/null +++ b/examples/platform/silabs/provision/ProvisionChannelRTT.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + */ +#include "ProvisionChannel.h" + +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { + +ProvisionChannel & ProvisionChannel::GetInstance() +{ + static ProvisionChannel instance; + return instance; +} + +CHIP_ERROR ProvisionChannel::Init() +{ + VerifyOrReturnError(SEGGER_RTT_ConfigUpBuffer(0, nullptr, nullptr, 0, SEGGER_RTT_MODE_NO_BLOCK_TRIM) >= 0, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(SEGGER_RTT_ConfigDownBuffer(0, nullptr, nullptr, 0, SEGGER_RTT_MODE_NO_BLOCK_TRIM) >= 0, + CHIP_ERROR_INTERNAL); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionChannel::Read(uint8_t * buffer, size_t bufferLength, size_t & bytesRead) +{ + VerifyOrReturnError(buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + bytesRead = 0; + const unsigned bytesAvailable = SEGGER_RTT_HasData(0); + VerifyOrReturnError(bytesAvailable > 0, CHIP_ERROR_READ_FAILED); + + const unsigned toRead = bytesAvailable < bufferLength ? bytesAvailable : static_cast(bufferLength); + bytesRead = SEGGER_RTT_Read(0, buffer, toRead); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionChannel::Write(const uint8_t * buffer, size_t bufferLength) +{ + VerifyOrReturnError(buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + size_t sent = 0; + while (sent < bufferLength) + { + const unsigned written = SEGGER_RTT_Write(0, buffer + sent, bufferLength - sent); + VerifyOrReturnError(written > 0, CHIP_ERROR_WRITE_FAILED); + sent += written; + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionChannel::OnDataAvailable() +{ + return CHIP_NO_ERROR; +} + +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/ProvisionChannelSi917BLE.cpp b/examples/platform/silabs/provision/ProvisionChannelSi917BLE.cpp new file mode 100644 index 00000000000..d77213f5c98 --- /dev/null +++ b/examples/platform/silabs/provision/ProvisionChannelSi917BLE.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + */ +#include "ProvisionChannel.h" + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { + +ProvisionChannel & ProvisionChannel::GetInstance() +{ + static ProvisionChannel instance; + return instance; +} + +CHIP_ERROR ProvisionChannel::Init() +{ + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionChannel::Read(uint8_t *, size_t, size_t &) +{ + return CHIP_ERROR_READ_FAILED; +} + +CHIP_ERROR ProvisionChannel::Write(const uint8_t *, size_t) +{ + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionChannel::OnDataAvailable() +{ + return CHIP_NO_ERROR; +} + +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/ProvisionCrypto.h b/examples/platform/silabs/provision/ProvisionCrypto.h new file mode 100644 index 00000000000..872ae6c1ea1 --- /dev/null +++ b/examples/platform/silabs/provision/ProvisionCrypto.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + */ +#pragma once + +#include + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { + +class ProvisionCrypto final : public IProvisionCrypto +{ +public: + static ProvisionCrypto & GetInstance(); + + ProvisionCrypto(const ProvisionCrypto &) = delete; + ProvisionCrypto & operator=(const ProvisionCrypto &) = delete; + + CHIP_ERROR GenerateRandom(MutableByteSpan & output) override; + CHIP_ERROR Hash256(const ByteSpan & input, MutableByteSpan & output) override; + CHIP_ERROR ImportDeviceAttestationKey(const ByteSpan & key) override; + CHIP_ERROR GenerateDeviceAttestationCSR(uint16_t vid, uint16_t pid, const CharSpan & commonName, + MutableCharSpan & csr) override; + CHIP_ERROR SignWithDeviceAttestationKey(const ByteSpan & message, MutableByteSpan & signature) override; + +private: + ProvisionCrypto() = default; +}; + +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/ProvisionCryptoMbed.cpp b/examples/platform/silabs/provision/ProvisionCryptoMbed.cpp new file mode 100644 index 00000000000..fa5d879b2d0 --- /dev/null +++ b/examples/platform/silabs/provision/ProvisionCryptoMbed.cpp @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + */ +#include "ProvisionCrypto.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(SL_MBEDTLS_USE_TINYCRYPT) && SL_MBEDTLS_USE_TINYCRYPT +#include +#endif + +#if SL_MATTER_USE_FLASH_STORE +#include +#include +#endif // SL_MATTER_USE_FLASH_STORE + +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { + +namespace { +using SilabsConfig = chip::DeviceLayer::Internal::SilabsConfig; + +constexpr size_t kDeviceAttestationKeySizeMax = 128; + +struct ScopedPkContext +{ + ScopedPkContext() { mbedtls_pk_init(&context); } + ~ScopedPkContext() { mbedtls_pk_free(&context); } + mbedtls_pk_context context; +}; + +struct ScopedCsrContext +{ + ScopedCsrContext() { mbedtls_x509write_csr_init(&context); } + ~ScopedCsrContext() { mbedtls_x509write_csr_free(&context); } + mbedtls_x509write_csr context; +}; + +#ifndef SLI_SI91X_MCU_INTERFACE +constexpr size_t kSubjectNameLengthMax = 160; +int GetRandom(void *, unsigned char * output, size_t size) +{ + return chip::Crypto::DRBG_get_bytes(output, size) == CHIP_NO_ERROR ? 0 : -1; +} + +CHIP_ERROR FormatMatterOidUtf8DerHex(char * destination, size_t destinationSize, uint16_t value) +{ + char hex[5]; + snprintf(hex, sizeof(hex), "%04X", value); + const int written = + snprintf(destination, destinationSize, "#0C04%02X%02X%02X%02X", static_cast(hex[0]), + static_cast(hex[1]), static_cast(hex[2]), static_cast(hex[3])); + return written == 13 ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; +} +#endif // SLI_SI91X_MCU_INTERFACE + +CHIP_ERROR ReadKey(MutableByteSpan & key) +{ +#if SL_MATTER_USE_FLASH_STORE == 1 + size_t size = 0; + CHIP_ERROR err = Flash::Get(Parameters::ID::kDacKey, key.data(), key.size(), size); + ReturnErrorOnFailure(err); + key.reduce_size(size); + return err; +#else + size_t size = 0; + ReturnErrorOnFailure(SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_Creds_KeyId, key.data(), key.size(), size)); + key.reduce_size(size); + return CHIP_NO_ERROR; +#endif // SL_MATTER_USE_FLASH_STORE +} + +CHIP_ERROR WriteKey(ByteSpan key) +{ +#if SL_MATTER_USE_FLASH_STORE == 1 + return Flash::Set(Parameters::ID::kDacKey, key.data(), key.size()); +#else + return SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_Creds_KeyId, key.data(), key.size()); +#endif // SL_MATTER_USE_FLASH_STORE +} + +#if defined(SLI_SI91X_MCU_INTERFACE) && defined(SL_MBEDTLS_USE_TINYCRYPT) && SL_MBEDTLS_USE_TINYCRYPT +int UnwrapKeyCallback(void * context, int tag, unsigned char * value, size_t size) +{ + if (tag == MBEDTLS_ASN1_OCTET_STRING) + { + auto * key = static_cast(context); + if (size > key->size()) + { + return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; + } + memcpy(key->data(), value, size); + key->reduce_size(size); + } + return 0; +} + +CHIP_ERROR UnwrapKey(const ByteSpan & encoded, MutableByteSpan & key) +{ + uint8_t * current = const_cast(encoded.data()); + uint8_t * end = current + encoded.size(); + const int error = mbedtls_asn1_traverse_sequence_of(¤t, end, 0, 0, 0, 0, UnwrapKeyCallback, &key); + return error == 0 ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; +} +#else +CHIP_ERROR ConvertAsn1Signature(const ByteSpan & encoded, MutableByteSpan & signature) +{ + VerifyOrReturnError(signature.size() >= 64, CHIP_ERROR_BUFFER_TOO_SMALL); + uint8_t * current = const_cast(encoded.data()); + const uint8_t * end = current + encoded.size(); + size_t sequenceLength = 0; + VerifyOrReturnError(mbedtls_asn1_get_tag(¤t, end, &sequenceLength, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) == 0, + CHIP_ERROR_INTERNAL); + + for (size_t component = 0; component < 2; ++component) + { + size_t integerLength = 0; + VerifyOrReturnError(mbedtls_asn1_get_tag(¤t, end, &integerLength, MBEDTLS_ASN1_INTEGER) == 0, CHIP_ERROR_INTERNAL); + while (integerLength > 32 && *current == 0) + { + ++current; + --integerLength; + } + VerifyOrReturnError(integerLength <= 32 && current + integerLength <= end, CHIP_ERROR_INTERNAL); + uint8_t * destination = signature.data() + component * 32; + memset(destination, 0, 32 - integerLength); + memcpy(destination + 32 - integerLength, current, integerLength); + current += integerLength; + } + signature.reduce_size(64); + return CHIP_NO_ERROR; +} +#endif +} // namespace + +ProvisionCrypto & ProvisionCrypto::GetInstance() +{ + static ProvisionCrypto instance; + return instance; +} + +CHIP_ERROR ProvisionCrypto::GenerateRandom(MutableByteSpan & output) +{ + return chip::Crypto::DRBG_get_bytes(output.data(), output.size()); +} + +CHIP_ERROR ProvisionCrypto::Hash256(const ByteSpan & input, MutableByteSpan & output) +{ + VerifyOrReturnError(output.size() >= chip::Crypto::kSHA256_Hash_Length, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(chip::Crypto::Hash_SHA256(input.data(), input.size(), output.data())); + output.reduce_size(chip::Crypto::kSHA256_Hash_Length); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionCrypto::ImportDeviceAttestationKey(const ByteSpan & key) +{ + VerifyOrReturnError(!key.empty() && key.size() <= kDeviceAttestationKeySizeMax, CHIP_ERROR_INVALID_ARGUMENT); + return WriteKey(key); +} + +CHIP_ERROR ProvisionCrypto::GenerateDeviceAttestationCSR(uint16_t vid, uint16_t pid, const CharSpan & commonName, + MutableCharSpan & csr) +{ +#if defined(SLI_SI91X_MCU_INTERFACE) + (void) vid; + (void) pid; + (void) commonName; + (void) csr; + return CHIP_ERROR_NOT_IMPLEMENTED; +#else + VerifyOrReturnError(csr.data() != nullptr && csr.size() >= 512, CHIP_ERROR_BUFFER_TOO_SMALL); + VerifyOrReturnError(commonName.size() <= 64, CHIP_ERROR_INVALID_ARGUMENT); + + char commonNameBuffer[65] = { 0 }; + if (!commonName.empty()) + { + memcpy(commonNameBuffer, commonName.data(), commonName.size()); + } + else + { + memcpy(commonNameBuffer, "Matter Device", sizeof("Matter Device")); + } + + char vidDer[16]; + char pidDer[16]; + ReturnErrorOnFailure(FormatMatterOidUtf8DerHex(vidDer, sizeof(vidDer), vid)); + ReturnErrorOnFailure(FormatMatterOidUtf8DerHex(pidDer, sizeof(pidDer), pid)); + char subjectName[kSubjectNameLengthMax] = { 0 }; + const int subjectLength = + snprintf(subjectName, sizeof(subjectName), "CN=%s, 1.3.6.1.4.1.37244.2.1=%s, 1.3.6.1.4.1.37244.2.2=%s", commonNameBuffer, + vidDer, pidDer); + VerifyOrReturnError(subjectLength > 0 && static_cast(subjectLength) < sizeof(subjectName), CHIP_ERROR_INTERNAL); + + // Declared before csrWriter so the key outlives the CSR writer that references it. + ScopedPkContext key; + ScopedCsrContext csrWriter; + + VerifyOrReturnError(mbedtls_pk_setup(&key.context, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) == 0, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(mbedtls_ecdsa_genkey(mbedtls_pk_ec(key.context), MBEDTLS_ECP_DP_SECP256R1, GetRandom, nullptr) == 0, + CHIP_ERROR_INTERNAL); + VerifyOrReturnError(mbedtls_x509write_csr_set_subject_name(&csrWriter.context, subjectName) == 0, CHIP_ERROR_INTERNAL); + mbedtls_x509write_csr_set_md_alg(&csrWriter.context, MBEDTLS_MD_SHA256); + + mbedtls_x509write_csr_set_key(&csrWriter.context, &key.context); + VerifyOrReturnError( + mbedtls_x509write_csr_pem(&csrWriter.context, reinterpret_cast(csr.data()), csr.size(), GetRandom, nullptr) == 0, + CHIP_ERROR_INTERNAL); + csr.reduce_size(strlen(csr.data()) + 1); + + uint8_t encodedKey[kDeviceAttestationKeySizeMax] = { 0 }; + const int encodedSize = mbedtls_pk_write_key_der(&key.context, encodedKey, sizeof(encodedKey)); + VerifyOrReturnError(encodedSize > 0 && static_cast(encodedSize) <= sizeof(encodedKey), CHIP_ERROR_INTERNAL); + return WriteKey(ByteSpan(encodedKey + sizeof(encodedKey) - encodedSize, static_cast(encodedSize))); +#endif +} + +CHIP_ERROR ProvisionCrypto::SignWithDeviceAttestationKey(const ByteSpan & message, MutableByteSpan & signature) +{ + uint8_t encodedKey[kDeviceAttestationKeySizeMax] = { 0 }; + MutableByteSpan encodedKeySpan(encodedKey); + ReturnErrorOnFailure(ReadKey(encodedKeySpan)); + +#if defined(SLI_SI91X_MCU_INTERFACE) && defined(SL_MBEDTLS_USE_TINYCRYPT) && SL_MBEDTLS_USE_TINYCRYPT + uint8_t privateKey[32] = { 0 }; + MutableByteSpan privateKeySpan(privateKey); + ReturnErrorOnFailure(UnwrapKey(encodedKeySpan, privateKeySpan)); + VerifyOrReturnError(privateKeySpan.size() == sizeof(privateKey), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(signature.size() >= 64, CHIP_ERROR_BUFFER_TOO_SMALL); + + uint8_t hash[chip::Crypto::kSHA256_Hash_Length] = { 0 }; + VerifyOrReturnError(mbedtls_sha256(message.data(), message.size(), hash, 0) == 0, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(uECC_sign(privateKey, hash, sizeof(hash), signature.data()) == UECC_SUCCESS, CHIP_ERROR_INTERNAL); + signature.reduce_size(64); + return CHIP_NO_ERROR; +#else + uint8_t hash[chip::Crypto::kSHA256_Hash_Length] = { 0 }; + uint8_t encodedSignature[chip::Crypto::kMax_ECDSA_Signature_Length] = { 0 }; + size_t encodedSignatureSize = 0; + VerifyOrReturnError(mbedtls_sha256(message.data(), message.size(), hash, 0) == 0, CHIP_ERROR_INTERNAL); + + ScopedPkContext key; + VerifyOrReturnError( + mbedtls_pk_parse_key(&key.context, encodedKeySpan.data(), encodedKeySpan.size(), nullptr, 0, GetRandom, nullptr) == 0, + CHIP_ERROR_INTERNAL); + VerifyOrReturnError(mbedtls_pk_sign(&key.context, MBEDTLS_MD_SHA256, hash, sizeof(hash), encodedSignature, + sizeof(encodedSignature), &encodedSignatureSize, GetRandom, nullptr) == 0, + CHIP_ERROR_INTERNAL); + return ConvertAsn1Signature(ByteSpan(encodedSignature, encodedSignatureSize), signature); +#endif +} + +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/ProvisionCryptoPSA.cpp b/examples/platform/silabs/provision/ProvisionCryptoPSA.cpp new file mode 100644 index 00000000000..553be4bc5a9 --- /dev/null +++ b/examples/platform/silabs/provision/ProvisionCryptoPSA.cpp @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + */ +#include "ProvisionCrypto.h" + +#include +#include +#include +#include +#include +#include +#include +#if defined(__ZEPHYR__) +#include +#include +#else +#include +#endif + +#if defined(SLI_SI91X_MCU_INTERFACE) && !defined(__ZEPHYR__) +#include +#endif + +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { + +namespace { +#if defined(__ZEPHYR__) +using ConfigStore = chip::DeviceLayer::Internal::ZephyrConfig; +#else +using ConfigStore = chip::DeviceLayer::Internal::SilabsConfig; +#endif + +constexpr uint32_t kDefaultDeviceAttestationKeyId = 2; +constexpr size_t kSubjectNameLengthMax = 160; + +#if defined(__ZEPHYR__) +const char * DeviceAttestationKeyIdKey() +{ + return ZephyrStorage::kConfigKeyDacKeyId; +} +#else +ConfigStore::Key DeviceAttestationKeyIdKey() +{ + return ConfigStore::kConfigKey_Creds_KeyId; +} +#endif + +// Key id used for import and CSR generation: the id already stored in config, or the default. +uint32_t ResolveDeviceAttestationKeyId() +{ + uint32_t keyId = 0; + if (ConfigStore::ReadConfigValue(DeviceAttestationKeyIdKey(), keyId) == CHIP_NO_ERROR && keyId != 0) + { + return keyId; + } + return kDefaultDeviceAttestationKeyId; +} + +CHIP_ERROR StoreDeviceAttestationKeyId(uint32_t keyId) +{ + return ConfigStore::WriteConfigValue(DeviceAttestationKeyIdKey(), keyId); +} + +CHIP_ERROR FormatMatterOidUtf8DerHex(char * destination, size_t destinationSize, uint16_t value) +{ + char hex[5]; + snprintf(hex, sizeof(hex), "%04X", value); + const int written = + snprintf(destination, destinationSize, "#0C04%02X%02X%02X%02X", static_cast(hex[0]), + static_cast(hex[1]), static_cast(hex[2]), static_cast(hex[3])); + return written == 13 ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; +} + +void ConfigureKeyAttributes(psa_key_attributes_t & attributes, uint32_t keyId) +{ + psa_set_key_id(&attributes, keyId); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, 256); + psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_usage_flags(&attributes, + PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | + PSA_KEY_USAGE_VERIFY_MESSAGE); +#if defined(SLI_SI91X_MCU_INTERFACE) && !defined(__ZEPHYR__) + psa_set_key_lifetime( + &attributes, + PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_LIFETIME_PERSISTENT, PSA_KEY_VOLATILE_PERSISTENT_WRAPPED)); +#else + psa_set_key_lifetime( + &attributes, + PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_LIFETIME_PERSISTENT, sl_psa_get_most_secure_key_location())); +#endif +} + +// Destroy an existing key at keyId so generate/import can reuse the id. +// Missing keys are expected; only unexpected PSA errors are returned. +psa_status_t DestroyKeyIfPresent(uint32_t keyId) +{ + const psa_status_t status = psa_destroy_key(static_cast(keyId)); + if (status == PSA_SUCCESS || status == PSA_ERROR_INVALID_HANDLE || status == PSA_ERROR_DOES_NOT_EXIST) + { + return PSA_SUCCESS; + } + return status; +} + +psa_status_t GenerateKey(uint32_t keyId) +{ + const psa_status_t destroyStatus = DestroyKeyIfPresent(keyId); + VerifyOrReturnError(destroyStatus == PSA_SUCCESS, destroyStatus); + + psa_key_attributes_t attributes = psa_key_attributes_init(); + ConfigureKeyAttributes(attributes, keyId); + psa_key_id_t generatedId = 0; + const psa_status_t error = psa_generate_key(&attributes, &generatedId); + psa_reset_key_attributes(&attributes); + return error; +} + +psa_status_t ImportKey(uint32_t keyId, const uint8_t * value, size_t size) +{ + const psa_status_t destroyStatus = DestroyKeyIfPresent(keyId); + VerifyOrReturnError(destroyStatus == PSA_SUCCESS, destroyStatus); + + psa_key_attributes_t attributes = psa_key_attributes_init(); + ConfigureKeyAttributes(attributes, keyId); + psa_key_id_t importedId = 0; + const psa_status_t error = psa_import_key(&attributes, value, size, &importedId); + psa_reset_key_attributes(&attributes); + return error; +} + +struct ImportKeyContext +{ + uint32_t keyId; + bool imported; +}; + +int ImportKeyCallback(void * context, int tag, unsigned char * value, size_t size) +{ + if (tag != MBEDTLS_ASN1_OCTET_STRING) + { + return 0; + } + auto * importContext = static_cast(context); + const psa_status_t status = ImportKey(importContext->keyId, value, size); + importContext->imported = status == PSA_SUCCESS; + return static_cast(status); +} +} // namespace + +ProvisionCrypto & ProvisionCrypto::GetInstance() +{ + static ProvisionCrypto instance; + return instance; +} + +CHIP_ERROR ProvisionCrypto::GenerateRandom(MutableByteSpan & output) +{ + return chip::Crypto::DRBG_get_bytes(output.data(), output.size()); +} + +CHIP_ERROR ProvisionCrypto::Hash256(const ByteSpan & input, MutableByteSpan & output) +{ + VerifyOrReturnError(output.size() >= chip::Crypto::kSHA256_Hash_Length, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(chip::Crypto::Hash_SHA256(input.data(), input.size(), output.data())); + output.reduce_size(chip::Crypto::kSHA256_Hash_Length); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionCrypto::ImportDeviceAttestationKey(const ByteSpan & key) +{ + VerifyOrReturnError(!key.empty(), CHIP_ERROR_INVALID_ARGUMENT); + uint8_t * current = const_cast(key.data()); + uint8_t * end = current + key.size(); + ImportKeyContext context{ ResolveDeviceAttestationKeyId(), false }; + const int error = mbedtls_asn1_traverse_sequence_of(¤t, end, 0, 0, 0, 0, ImportKeyCallback, &context); + VerifyOrReturnError(error == 0 && context.imported, CHIP_ERROR_INTERNAL); + return StoreDeviceAttestationKeyId(context.keyId); +} + +CHIP_ERROR ProvisionCrypto::GenerateDeviceAttestationCSR(uint16_t vid, uint16_t pid, const CharSpan & commonName, + MutableCharSpan & csr) +{ + VerifyOrReturnError(csr.data() != nullptr && csr.size() >= 512, CHIP_ERROR_BUFFER_TOO_SMALL); + VerifyOrReturnError(commonName.size() <= 64, CHIP_ERROR_INVALID_ARGUMENT); + + char commonNameBuffer[65] = { 0 }; + if (!commonName.empty()) + { + memcpy(commonNameBuffer, commonName.data(), commonName.size()); + } + else + { + memcpy(commonNameBuffer, "Matter Device", sizeof("Matter Device")); + } + + char vidDer[16]; + char pidDer[16]; + ReturnErrorOnFailure(FormatMatterOidUtf8DerHex(vidDer, sizeof(vidDer), vid)); + ReturnErrorOnFailure(FormatMatterOidUtf8DerHex(pidDer, sizeof(pidDer), pid)); + + char subjectName[kSubjectNameLengthMax] = { 0 }; + const int subjectLength = + snprintf(subjectName, sizeof(subjectName), "CN=%s, 1.3.6.1.4.1.37244.2.1=%s, 1.3.6.1.4.1.37244.2.2=%s", commonNameBuffer, + vidDer, pidDer); + VerifyOrReturnError(subjectLength > 0 && static_cast(subjectLength) < sizeof(subjectName), CHIP_ERROR_INTERNAL); + + const uint32_t keyId = ResolveDeviceAttestationKeyId(); + + mbedtls_pk_context keyContext; + mbedtls_x509write_csr csrContext; + mbedtls_pk_init(&keyContext); + mbedtls_x509write_csr_init(&csrContext); + + CHIP_ERROR result = CHIP_ERROR_INTERNAL; + int error = mbedtls_x509write_csr_set_subject_name(&csrContext, subjectName); + VerifyOrExit(error == 0, result = CHIP_ERROR_INTERNAL); + mbedtls_x509write_csr_set_md_alg(&csrContext, MBEDTLS_MD_SHA256); + + VerifyOrExit(GenerateKey(keyId) == PSA_SUCCESS, result = CHIP_ERROR_INTERNAL); +#if MBEDTLS_VERSION_MAJOR >= 4 + error = mbedtls_pk_wrap_psa(&keyContext, static_cast(keyId)); +#else + error = mbedtls_pk_setup_opaque(&keyContext, keyId); +#endif + VerifyOrExit(error == 0, result = CHIP_ERROR_INTERNAL); + mbedtls_x509write_csr_set_key(&csrContext, &keyContext); + +#if MBEDTLS_VERSION_MAJOR >= 4 + error = mbedtls_x509write_csr_pem(&csrContext, reinterpret_cast(csr.data()), csr.size()); +#else + error = mbedtls_x509write_csr_pem(&csrContext, reinterpret_cast(csr.data()), csr.size(), nullptr, nullptr); +#endif + VerifyOrExit(error == 0, result = CHIP_ERROR_INTERNAL); + csr.reduce_size(strlen(csr.data()) + 1); + result = StoreDeviceAttestationKeyId(keyId); + +exit: + mbedtls_x509write_csr_free(&csrContext); + mbedtls_pk_free(&keyContext); + return result; +} + +CHIP_ERROR ProvisionCrypto::SignWithDeviceAttestationKey(const ByteSpan & message, MutableByteSpan & signature) +{ + VerifyOrReturnError(signature.size() >= 64, CHIP_ERROR_BUFFER_TOO_SMALL); + + // No stored key id means no provisioned DAC key; callers fall back to example credentials on NOT_FOUND. + VerifyOrReturnError(ConfigStore::ConfigValueExists(DeviceAttestationKeyIdKey()), CHIP_ERROR_NOT_FOUND); + uint32_t keyId = 0; + ReturnErrorOnFailure(ConfigStore::ReadConfigValue(DeviceAttestationKeyIdKey(), keyId)); + + size_t signatureSize = 0; + const psa_status_t status = psa_sign_message(static_cast(keyId), PSA_ALG_ECDSA(PSA_ALG_SHA_256), message.data(), + message.size(), signature.data(), signature.size(), &signatureSize); + if (status == PSA_ERROR_INVALID_HANDLE || status == PSA_ERROR_DOES_NOT_EXIST) + { + return CHIP_ERROR_NOT_FOUND; + } + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(signatureSize == 64, CHIP_ERROR_INTERNAL); + signature.reduce_size(signatureSize); + return CHIP_NO_ERROR; +} + +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/ProvisionStorageCommon.cpp b/examples/platform/silabs/provision/ProvisionStorageCommon.cpp deleted file mode 100644 index e38d04be4c2..00000000000 --- a/examples/platform/silabs/provision/ProvisionStorageCommon.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2026 Project CHIP Authors - * All rights reserved. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace chip { -namespace DeviceLayer { -namespace Silabs { -namespace Provision { - -// -// DeviceInstanceInfoProvider -// - -CHIP_ERROR Storage::GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) -{ - constexpr uint8_t kDateLength = 8; // YYYYMMDD - constexpr uint8_t kLegacyDateLength = 10; // YYYY-MM-DD - char date[kManufacturingDateLengthMax + 1] = { 0 }; - char temp[kManufacturingDateLengthMax + 1] = { 0 }; - size_t date_len = 0; - char * parse_end = nullptr; - CHIP_ERROR err = CHIP_NO_ERROR; - - ReturnErrorOnFailure(GetManufacturingDate((uint8_t *) date, sizeof(date), date_len)); - // Convert legacy date format to new date format - if ((kLegacyDateLength == date_len) && ('-' == date[4]) && ('-' == date[7])) - { - date_len = kDateLength; - snprintf(temp, sizeof(temp), "%.4s%.2s%.2s", date, date + 5, date + 8); - memcpy(date, temp, date_len); - ReturnErrorOnFailure(SetManufacturingDate(date, date_len)); - } - VerifyOrExit(date_len >= kDateLength, err = CHIP_ERROR_INVALID_ARGUMENT); - // Year - memcpy(temp, date, 4); // yyyy - temp[4] = 0; - year = static_cast(strtoul(temp, &parse_end, 10)); - VerifyOrExit(parse_end == (temp + 4), err = CHIP_ERROR_INVALID_ARGUMENT); - // Month - memcpy(temp, &date[4], 2); // mm - temp[2] = 0; - month = static_cast(strtoul(temp, &parse_end, 10)); - VerifyOrExit(parse_end == (temp + 2), err = CHIP_ERROR_INVALID_ARGUMENT); - // Day - memcpy(temp, &date[6], 2); // dd - temp[2] = 0; - day = static_cast(strtoul(temp, &parse_end, 10)); - VerifyOrExit(parse_end == (temp + 2), err = CHIP_ERROR_INVALID_ARGUMENT); - -exit: - if (err != CHIP_NO_ERROR && err != CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) - { - printf("Invalid manufacturing date: %s", date); - } - return err; -} - -CHIP_ERROR Storage::GetManufacturingDateSuffix(MutableCharSpan & suffixBuffer) -{ - char date[kManufacturingDateLengthMax + 1] = { 0 }; - size_t date_len = 0; - - ReturnErrorOnFailure(GetManufacturingDate((uint8_t *) date, sizeof(date), date_len)); - if (date_len > 8) - { - const size_t suffixLen = date_len - 8; - VerifyOrReturnError(suffixLen <= suffixBuffer.size(), CHIP_ERROR_BUFFER_TOO_SMALL); - memcpy(suffixBuffer.data(), date + 8, suffixLen); - suffixBuffer.reduce_size(suffixLen); - return CHIP_NO_ERROR; - } - suffixBuffer.reduce_size(0); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::GetRotatingDeviceIdUniqueId(MutableByteSpan & value) -{ - size_t size = 0; - - CHIP_ERROR err = GetPersistentUniqueId(value.data(), value.size(), size); -#if defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - constexpr uint8_t unique_id[] = CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID; - VerifyOrReturnError(sizeof(unique_id) <= value.size(), CHIP_ERROR_BUFFER_TOO_SMALL); - memcpy(value.data(), unique_id, sizeof(unique_id)); - size = sizeof(unique_id); - err = CHIP_NO_ERROR; - } -#endif - ReturnErrorOnFailure(err); - value.reduce_size(size); - return CHIP_NO_ERROR; -} - -// -// CommissionableDataProvider -// - -CHIP_ERROR Storage::GetSpake2pSalt(MutableByteSpan & value) -{ - // Base64 - char salt_b64[kSpake2pSaltB64LengthMax + 1] = { 0 }; - size_t size_b64 = 0; - - CHIP_ERROR err = this->GetSpake2pSalt(salt_b64, sizeof(salt_b64), size_b64); -#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT) - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - size_b64 = strlen(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT); - VerifyOrReturnError(size_b64 <= sizeof(salt_b64), CHIP_ERROR_BUFFER_TOO_SMALL); - memcpy(salt_b64, CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT, size_b64); - err = CHIP_NO_ERROR; - } -#endif - ReturnErrorOnFailure(err); - - // Decode - uint8_t salt[chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length] = { 0 }; - size_t size = chip::Base64Decode32(salt_b64, size_b64, salt); - VerifyOrReturnError(size >= chip::Crypto::kSpake2p_Min_PBKDF_Salt_Length && - size <= chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length, - CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(size <= value.size(), CHIP_ERROR_BUFFER_TOO_SMALL); - - // Copy - memcpy(value.data(), salt, size); - value.reduce_size(size); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::GetSpake2pVerifier(MutableByteSpan & out_value, size_t & out_size) -{ - VerifyOrReturnError(out_value.size() >= chip::Crypto::kSpake2p_VerifierSerialized_Length, CHIP_ERROR_BUFFER_TOO_SMALL); - - // Base64 - char verifier_b64[kSpake2pVerifierB64LengthMax + 1] = { 0 }; - size_t size_b64 = 0; - - CHIP_ERROR err = this->GetSpake2pVerifier(verifier_b64, sizeof(verifier_b64), size_b64); -#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER) - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - size_b64 = strlen(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER); - VerifyOrReturnError(size_b64 <= sizeof(verifier_b64), CHIP_ERROR_BUFFER_TOO_SMALL); - memcpy(verifier_b64, CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER, size_b64); - err = CHIP_NO_ERROR; - } -#endif - ReturnErrorOnFailure(err); - - // Decode - out_size = chip::Base64Decode32(verifier_b64, size_b64, out_value.data()); - VerifyOrReturnError(out_size == chip::Crypto::kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INVALID_ARGUMENT); - out_value.reduce_size(out_size); - return CHIP_NO_ERROR; -} - -} // namespace Provision -} // namespace Silabs -} // namespace DeviceLayer -} // namespace chip diff --git a/examples/platform/silabs/provision/ProvisionStorageDefault.cpp b/examples/platform/silabs/provision/ProvisionStorageDefault.cpp deleted file mode 100644 index 2dbc32d7084..00000000000 --- a/examples/platform/silabs/provision/ProvisionStorageDefault.cpp +++ /dev/null @@ -1,788 +0,0 @@ -/* - * Copyright (c) 2024 Project CHIP Authors - * All rights reserved. - * - * 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. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef NDEBUG -#if defined(SL_MATTER_TEST_EVENT_TRIGGER_ENABLED) && SL_MATTER_TEST_EVENT_TRIGGER_ENABLED && (SL_MATTER_GN_BUILD == 0) -#include -#endif // defined(SL_MATTER_TEST_EVENT_TRIGGER_ENABLED) && (SL_MATTER_GN_BUILD == 0) -#endif // NDEBUG -#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION -#include -#endif // SL_MATTER_ENABLE_OTA_ENCRYPTION -#ifndef SLI_SI91X_MCU_INTERFACE -#include -#endif - -#ifdef SL_PROVISION_GENERATOR -extern void setNvm3End(uint32_t addr); -#elif !SL_MATTER_GN_BUILD -#include -#endif - -extern uint8_t linker_nvm_end[]; -#ifdef _SILICON_LABS_32B_SERIES_3 -extern uint8_t linker_static_secure_tokens_begin; // Defined by the linker script -#endif - -using namespace chip::Credentials; -using namespace chip::DeviceLayer::Internal; - -using SilabsConfig = chip::DeviceLayer::Internal::SilabsConfig; - -namespace chip { -namespace DeviceLayer { -namespace Silabs { -namespace Provision { - -namespace { -// Miss-aligned certificates is a common error, and printing the first few bytes is -// useful to verify proper alignment. Eight bytes is enough for this purpose. -[[maybe_unused]] constexpr size_t kDebugLength = 8; -size_t sCredentialsOffset = 0; - -CHIP_ERROR ErasePage(uint32_t addr) -{ - return chip::DeviceLayer::Silabs::GetPlatform().FlashErasePage(addr); -} - -size_t RoundNearest(size_t n, size_t multiple) -{ - return (n % multiple) > 0 ? n + (multiple - n % multiple) : n; -} - -/** - * Writes "size" bytes to the flash page. The data is padded with 0xff - * up to the nearest 32-bit boundary. - */ -CHIP_ERROR WritePage(uint32_t addr, const uint8_t * data, size_t size) -{ - // The flash driver fails if the size is not a multiple of 4 (32-bits) - size_t size_32 = RoundNearest(size, 4); - if (size_32 == size) - { - // The given data is already aligned to 32-bit - return chip::DeviceLayer::Silabs::GetPlatform().FlashWritePage(addr, data, size); - } - else - { - // Create a temporary buffer, and pad it with "0xff" - uint8_t * p = static_cast(Platform::MemoryAlloc(size_32)); - VerifyOrReturnError(p != nullptr, CHIP_ERROR_INTERNAL); - memcpy(p, data, size); - memset(p + size, 0xff, size_32 - size); - CHIP_ERROR err = chip::DeviceLayer::Silabs::GetPlatform().FlashWritePage(addr, p, size_32); - Platform::MemoryFree(p); - return err; - } -} - -CHIP_ERROR WriteFile(Storage & store, SilabsConfig::Key offset_key, SilabsConfig::Key size_key, const ByteSpan & value) -{ - uint32_t base_addr = 0; - ReturnErrorOnFailure(store.GetCredentialsBaseAddress(base_addr)); - if (0 == sCredentialsOffset) - { - ReturnErrorOnFailure(ErasePage(base_addr)); - } - - ReturnErrorOnFailure(WritePage(base_addr + sCredentialsOffset, value.data(), value.size())); - - // Store file offset - ReturnErrorOnFailure(SilabsConfig::WriteConfigValue(offset_key, (uint32_t) sCredentialsOffset)); - // Store file size - ReturnErrorOnFailure(SilabsConfig::WriteConfigValue(size_key, (uint32_t) value.size())); - // Calculate offset for the next file - sCredentialsOffset = RoundNearest(sCredentialsOffset + value.size(), 64); - return CHIP_NO_ERROR; -} - -CHIP_ERROR ReadFileByOffset(Storage & store, const char * description, uint32_t offset, uint32_t size, MutableByteSpan & value) -{ - uint32_t base_addr = 0; - ReturnErrorOnFailure(store.GetCredentialsBaseAddress(base_addr)); - - uint8_t * address = (uint8_t *) (base_addr + offset); - ByteSpan span(address, size); - ChipLogProgress(DeviceLayer, "%s, addr:0x%06x+%03u, size:%u", description, (unsigned) base_addr, (unsigned) offset, - (unsigned) size); - return CopySpanToMutableSpan(span, value); -} - -CHIP_ERROR ReadFileByKey(Storage & store, const char * description, uint32_t offset_key, uint32_t size_key, MutableByteSpan & value) -{ - uint32_t offset = 0; - uint32_t size = 0; - - // Offset - VerifyOrReturnError(SilabsConfig::ConfigValueExists(offset_key), CHIP_ERROR_NOT_FOUND); - ReturnErrorOnFailure(SilabsConfig::ReadConfigValue(offset_key, offset)); - - // Size - VerifyOrReturnError(SilabsConfig::ConfigValueExists(size_key), CHIP_ERROR_NOT_FOUND); - ReturnErrorOnFailure(SilabsConfig::ReadConfigValue(size_key, size)); - - return ReadFileByOffset(store, description, offset, size, value); -} - -} // namespace - -// -// Initialization -// - -CHIP_ERROR Storage::Initialize(uint32_t flash_addr, uint32_t flash_size) -{ - sCredentialsOffset = 0; - - uint32_t base_addr = (uint32_t) linker_nvm_end; - if (flash_size > 0) - { -#ifndef SLI_SI91X_MCU_INTERFACE - base_addr = (flash_addr + flash_size - FLASH_PAGE_SIZE); -#endif // SLI_SI91X_MCU_INTERFACE -#ifdef _SILICON_LABS_32B_SERIES_3 - uint32_t tokenStartAddr = reinterpret_cast(&linker_static_secure_tokens_begin); - base_addr = tokenStartAddr + FLASH_PAGE_SIZE; -#endif - TEMPORARY_RETURN_IGNORED chip::DeviceLayer::Silabs::GetPlatform().FlashInit(); -#ifdef SL_PROVISION_GENERATOR - setNvm3End(base_addr); -#endif - } - return SetCredentialsBaseAddress(base_addr); -} - -CHIP_ERROR Storage::Commit() -{ - return CHIP_NO_ERROR; -} - -// -// DeviceInstanceInfoProvider -// - -CHIP_ERROR Storage::SetSerialNumber(const char * value, size_t len) -{ - return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_SerialNum, value, len); -} - -CHIP_ERROR Storage::GetSerialNumber(char * value, size_t max) -{ - size_t size = 0; - return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_SerialNum, value, max, size); -} - -CHIP_ERROR Storage::SetVendorId(uint16_t value) -{ - return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_VendorId, value); -} - -CHIP_ERROR Storage::GetVendorId(uint16_t & value) -{ - CHIP_ERROR err = SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_VendorId, value); -#if defined(CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID) && CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - value = CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID; - err = CHIP_NO_ERROR; - } -#endif - return err; -} - -CHIP_ERROR Storage::SetVendorName(const char * value, size_t len) -{ - return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_VendorName, value, len); -} - -CHIP_ERROR Storage::GetVendorName(char * value, size_t max) -{ - size_t name_len = 0; // Without counting null-terminator - - CHIP_ERROR err = SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_VendorName, value, max, name_len); -#if defined(CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME) - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - VerifyOrReturnError(value != nullptr, CHIP_ERROR_NO_MEMORY); - VerifyOrReturnError(max > strlen(CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME), CHIP_ERROR_BUFFER_TOO_SMALL); - Platform::CopyString(value, max, CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME); - err = CHIP_NO_ERROR; - } -#endif - return err; -} - -CHIP_ERROR Storage::SetProductId(uint16_t value) -{ - return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_ProductId, value); -} - -CHIP_ERROR Storage::GetProductId(uint16_t & value) -{ - CHIP_ERROR err = SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_ProductId, value); - -#if defined(CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID) && CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - value = CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID; - err = CHIP_NO_ERROR; - } -#endif - return err; -} - -CHIP_ERROR Storage::SetProductName(const char * value, size_t len) -{ - return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_ProductName, value, len); -} - -CHIP_ERROR Storage::GetProductName(char * value, size_t max) -{ - size_t name_len = 0; // Without counting null-terminator - - CHIP_ERROR err = SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_ProductName, value, max, name_len); -#if defined(CHIP_DEVICE_CONFIG_TEST_PRODUCT_NAME) - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - VerifyOrReturnError(value != nullptr, CHIP_ERROR_NO_MEMORY); - VerifyOrReturnError(max > strlen(CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME), CHIP_ERROR_BUFFER_TOO_SMALL); - Platform::CopyString(value, max, CHIP_DEVICE_CONFIG_TEST_PRODUCT_NAME); - err = CHIP_NO_ERROR; - } -#endif - return err; -} - -CHIP_ERROR Storage::SetProductLabel(const char * value, size_t len) -{ - return SilabsConfig::WriteConfigValueStr(SilabsConfig::KConfigKey_ProductLabel, value, len); -} - -CHIP_ERROR Storage::GetProductLabel(char * value, size_t max) -{ - size_t size = 0; - return SilabsConfig::ReadConfigValueStr(SilabsConfig::KConfigKey_ProductLabel, value, max, size); -} - -CHIP_ERROR Storage::SetProductURL(const char * value, size_t len) -{ - return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_ProductURL, value, len); -} -CHIP_ERROR Storage::GetProductURL(char * value, size_t max) -{ - size_t size = 0; - return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_ProductURL, value, max, size); -} - -CHIP_ERROR Storage::SetPartNumber(const char * value, size_t len) -{ - return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_PartNumber, value, len); -} - -CHIP_ERROR Storage::GetPartNumber(char * value, size_t max) -{ - size_t size = 0; - return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_PartNumber, value, max, size); -} - -CHIP_ERROR Storage::SetHardwareVersion(uint16_t value) -{ - return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_HardwareVersion, value); -} - -CHIP_ERROR Storage::GetHardwareVersion(uint16_t & value) -{ - CHIP_ERROR err = SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_HardwareVersion, value); -#if defined(CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION) - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - value = CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION; - err = CHIP_NO_ERROR; - } -#endif - return err; -} - -CHIP_ERROR Storage::SetHardwareVersionString(const char * value, size_t len) -{ - return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_HardwareVersionString, value, len); -} - -CHIP_ERROR Storage::GetHardwareVersionString(char * value, size_t max) -{ - size_t hw_version_len = 0; // @ithout counting null-terminator - - CHIP_ERROR err = SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_HardwareVersionString, value, max, hw_version_len); -#if defined(CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING) - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - VerifyOrReturnError(value != nullptr, CHIP_ERROR_NO_MEMORY); - VerifyOrReturnError(max > strlen(CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING), CHIP_ERROR_BUFFER_TOO_SMALL); - Platform::CopyString(value, max, CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING); - err = CHIP_NO_ERROR; - } -#endif - return err; -} - -CHIP_ERROR Storage::SetManufacturingDate(const char * value, size_t len) -{ - return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_ManufacturingDate, value, len); -} - -CHIP_ERROR Storage::GetManufacturingDate(uint8_t * value, size_t max, size_t & size) -{ - return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_ManufacturingDate, (char *) value, max, size); -} - -CHIP_ERROR Storage::SetPersistentUniqueId(const uint8_t * value, size_t size) -{ - return SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_PersistentUniqueId, value, size); -} - -CHIP_ERROR Storage::GetPersistentUniqueId(uint8_t * value, size_t max, size_t & size) -{ - return SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_PersistentUniqueId, value, max, size); -} - -// -// CommissionableDataProvider -// - -CHIP_ERROR Storage::SetSetupDiscriminator(uint16_t value) -{ - return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_SetupDiscriminator, value); -} - -CHIP_ERROR Storage::GetSetupDiscriminator(uint16_t & value) -{ - CHIP_ERROR err = SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_SetupDiscriminator, value); -#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR) && CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - value = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR; - err = CHIP_NO_ERROR; - } -#endif - ReturnErrorOnFailure(err); - VerifyOrReturnLogError(value <= kMaxDiscriminatorValue, CHIP_ERROR_INVALID_ARGUMENT); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetSpake2pIterationCount(uint32_t value) -{ - return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_Spake2pIterationCount, value); -} - -CHIP_ERROR Storage::GetSpake2pIterationCount(uint32_t & value) -{ - CHIP_ERROR err = SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_Spake2pIterationCount, value); -#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT) && CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - value = CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT; - err = CHIP_NO_ERROR; - } -#endif - return err; -} - -CHIP_ERROR Storage::SetSetupPasscode(uint32_t value) -{ - (void) value; - return CHIP_ERROR_NOT_IMPLEMENTED; -} - -CHIP_ERROR Storage::GetSetupPasscode(uint32_t & value) -{ - (void) value; - return CHIP_ERROR_NOT_IMPLEMENTED; -} - -CHIP_ERROR Storage::SetSpake2pSalt(const char * value, size_t size) -{ - return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_Spake2pSalt, value, size); -} - -CHIP_ERROR Storage::GetSpake2pSalt(char * value, size_t max, size_t & size) -{ - return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_Spake2pSalt, value, max, size); -} - -CHIP_ERROR Storage::SetSpake2pVerifier(const char * value, size_t size) -{ - return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_Spake2pVerifier, value, size); -} - -CHIP_ERROR Storage::GetSpake2pVerifier(char * value, size_t max, size_t & size) -{ - return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_Spake2pVerifier, value, max, size); -} - -// -// DeviceAttestationCredentialsProvider -// - -CHIP_ERROR Storage::SetFirmwareInformation(const ByteSpan & value) -{ - (void) value; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::GetFirmwareInformation(MutableByteSpan & value) -{ - // TODO: We need a real example FirmwareInformation to be populated. - value.reduce_size(0); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetCertificationDeclaration(const ByteSpan & value) -{ - ReturnErrorOnFailure(WriteFile(*this, SilabsConfig::kConfigKey_Creds_CD_Offset, SilabsConfig::kConfigKey_Creds_CD_Size, value)); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::GetCertificationDeclaration(MutableByteSpan & value) -{ - CHIP_ERROR err = ReadFileByKey(*this, "GetCertificationDeclaration", SilabsConfig::kConfigKey_Creds_CD_Offset, - SilabsConfig::kConfigKey_Creds_CD_Size, value); -#if defined(SL_PROVISION_VERSION_1_0) && SL_PROVISION_VERSION_1_0 - if (CHIP_ERROR_NOT_FOUND == err) - { - // Reading from the old script's location. - err = ReadFileByOffset(*this, "GetDeviceAttestationCert", SL_CREDENTIALS_CD_OFFSET, SL_CREDENTIALS_CD_SIZE, value); - } -#endif -#ifdef SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS - if (CHIP_ERROR_NOT_FOUND == err) - { - // Example CD - err = Examples::GetExampleDACProvider()->GetCertificationDeclaration(value); - } -#endif - return err; -} - -CHIP_ERROR Storage::SetProductAttestationIntermediateCert(const ByteSpan & value) -{ - ReturnErrorOnFailure( - WriteFile(*this, SilabsConfig::kConfigKey_Creds_PAI_Offset, SilabsConfig::kConfigKey_Creds_PAI_Size, value)); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::GetProductAttestationIntermediateCert(MutableByteSpan & value) -{ - CHIP_ERROR err = ReadFileByKey(*this, "GetProductAttestationIntermediateCert", SilabsConfig::kConfigKey_Creds_PAI_Offset, - SilabsConfig::kConfigKey_Creds_PAI_Size, value); -#if defined(SL_PROVISION_VERSION_1_0) && SL_PROVISION_VERSION_1_0 - if (CHIP_ERROR_NOT_FOUND == err) - { - // Reading from the old script's location. - err = ReadFileByOffset(*this, "GetDeviceAttestationCert", SL_CREDENTIALS_PAI_OFFSET, SL_CREDENTIALS_PAI_SIZE, value); - } -#endif -#ifdef SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS - if (CHIP_ERROR_NOT_FOUND == err) - { - // Example PAI - err = Examples::GetExampleDACProvider()->GetProductAttestationIntermediateCert(value); - } -#endif - return err; -} - -CHIP_ERROR Storage::SetDeviceAttestationCert(const ByteSpan & value) -{ - ReturnErrorOnFailure( - WriteFile(*this, SilabsConfig::kConfigKey_Creds_DAC_Offset, SilabsConfig::kConfigKey_Creds_DAC_Size, value)); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::GetDeviceAttestationCert(MutableByteSpan & value) -{ - CHIP_ERROR err = ReadFileByKey(*this, "GetDeviceAttestationCert", SilabsConfig::kConfigKey_Creds_DAC_Offset, - SilabsConfig::kConfigKey_Creds_DAC_Size, value); -#if defined(SL_PROVISION_VERSION_1_0) && SL_PROVISION_VERSION_1_0 - if (CHIP_ERROR_NOT_FOUND == err) - { - // Reading from the old script's location. - err = ReadFileByOffset(*this, "GetDeviceAttestationCert", SL_CREDENTIALS_DAC_OFFSET, SL_CREDENTIALS_DAC_SIZE, value); - } -#endif -#ifdef SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS - if (CHIP_ERROR_NOT_FOUND == err) - { - // Example DAC - return Examples::GetExampleDACProvider()->GetDeviceAttestationCert(value); - } -#endif - return err; -} - -#if defined(SLI_SI91X_MCU_INTERFACE) && defined(SL_MBEDTLS_USE_TINYCRYPT) -CHIP_ERROR Storage::SetDeviceAttestationKey(const ByteSpan & value) -{ - return SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_Creds_KeyId, value.data(), value.size()); -} - -CHIP_ERROR Storage::GetDeviceAttestationCSR(uint16_t vid, uint16_t pid, const CharSpan & cn, MutableCharSpan & csr) -{ - AttestationKey key; - uint8_t temp[kDeviceAttestationKeySizeMax] = { 0 }; - size_t size = 0; - ReturnErrorOnFailure(key.GenerateCSR(vid, pid, cn, csr)); - ReturnErrorOnFailure(key.Export(temp, sizeof(temp), size)); - return SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_Creds_KeyId, temp, size); -} - -CHIP_ERROR Storage::SignWithDeviceAttestationKey(const ByteSpan & message, MutableByteSpan & signature) -{ - if (SilabsConfig::ConfigValueExists(SilabsConfig::kConfigKey_Creds_KeyId)) - { - AttestationKey key; - uint8_t temp[kDeviceAttestationKeySizeMax] = { 0 }; - size_t size = 0; - ReturnErrorOnFailure(SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_Creds_KeyId, temp, sizeof(temp), size)); - key.Import(temp, size); - return key.SignMessage(message, signature); - } - else - { -#ifdef SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS - // Example DAC key - return Examples::GetExampleDACProvider()->SignWithDeviceAttestationKey(message, signature); -#else - return CHIP_ERROR_NOT_FOUND; -#endif - } -} - -#else - -CHIP_ERROR Storage::SetDeviceAttestationKey(const ByteSpan & value) -{ - AttestationKey key; - ReturnErrorOnFailure(key.Import(value.data(), value.size())); - return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_Creds_KeyId, key.GetId()); -} - -CHIP_ERROR Storage::GetDeviceAttestationCSR(uint16_t vid, uint16_t pid, const CharSpan & cn, MutableCharSpan & csr) -{ - AttestationKey key; - ReturnErrorOnFailure(key.GenerateCSR(vid, pid, cn, csr)); - return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_Creds_KeyId, key.GetId()); -} - -CHIP_ERROR Storage::SignWithDeviceAttestationKey(const ByteSpan & message, MutableByteSpan & signature) -{ - CHIP_ERROR err = CHIP_ERROR_NOT_FOUND; - uint32_t kid = 0; - - if (SilabsConfig::ConfigValueExists(SilabsConfig::kConfigKey_Creds_KeyId)) - { - ReturnErrorOnFailure(SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_Creds_KeyId, kid)); - AttestationKey key(kid); - err = key.SignMessage(message, signature); - } -#ifdef SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS - else - { - // Example DAC key - err = Examples::GetExampleDACProvider()->SignWithDeviceAttestationKey(message, signature); - } -#endif - ChipLogProgress(DeviceLayer, "SignWithDeviceAttestationKey, kid:%u, msg_size:%u, sig_size:%u, err:0x%02x", (unsigned) kid, - (unsigned) message.size(), (unsigned) signature.size(), (unsigned) err.AsInteger()); - // ChipLogByteSpan(DeviceLayer, ByteSpan(signature.data(), signature.size() < kDebugLength ? signature.size() : kDebugLength)); - return err; -} -#endif // SLI_SI91X_MCU_INTERFACE && SL_MBEDTLS_USE_TINYCRYPT - -// -// Other -// - -CHIP_ERROR Storage::SetCredentialsBaseAddress(uint32_t addr) -{ - return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_Creds_Base_Addr, addr); -} - -CHIP_ERROR Storage::GetCredentialsBaseAddress(uint32_t & addr) -{ - return SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_Creds_Base_Addr, addr); -} - -CHIP_ERROR Storage::SetProvisionVersion(const char * value, size_t size) -{ - return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_Provision_Version, value, size); -} - -CHIP_ERROR Storage::GetProvisionVersion(char * value, size_t max, size_t & size) -{ - return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_Provision_Version, value, max, size); -} - -CHIP_ERROR Storage::SetSetupPayload(const uint8_t * value, size_t size) -{ - return SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_SetupPayloadBitSet, value, size); -} - -CHIP_ERROR Storage::GetSetupPayload(uint8_t * value, size_t max, size_t & size) -{ - return SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_SetupPayloadBitSet, value, max, size); -} - -CHIP_ERROR Storage::SetProvisionRequest(bool value) -{ - return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_Provision_Request, value); -} - -CHIP_ERROR Storage::GetProvisionRequest(bool & value) -{ - return SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_Provision_Request, value); -} - -#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION -CHIP_ERROR Storage::SetOtaTlvEncryptionKey(const ByteSpan & value) -{ -#if defined(SL_MBEDTLS_USE_TINYCRYPT) - // Tinycrypt doesn't support the key ID, so we need to store the key as a binary blob - return SilabsConfig::WriteConfigValueBin(SilabsConfig::kOtaTlvEncryption_KeyId, value.data(), value.size()); -#else // MBEDTLS_USE_PSA_CRYPTO - Silabs::OtaTlvEncryptionKey key; - ReturnErrorOnFailure(key.Import(value.data(), value.size())); - return SilabsConfig::WriteConfigValue(SilabsConfig::kOtaTlvEncryption_KeyId, key.GetId()); -#endif // SL_MBEDTLS_USE_TINYCRYPT -} - -CHIP_ERROR Storage::GetOtaTlvEncryptionKeyId(uint32_t & keyId) -{ -#if defined(SL_MBEDTLS_USE_TINYCRYPT) - // Tinycrypt doesn't support the key ID - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#else // MBEDTLS_USE_PSA_CRYPTO - // Read the key ID from the config - return SilabsConfig::ReadConfigValue(SilabsConfig::kOtaTlvEncryption_KeyId, keyId); -#endif // SL_MBEDTLS_USE_TINYCRYPT -} - -CHIP_ERROR Storage::DecryptUsingOtaTlvEncryptionKey(MutableByteSpan & block, uint32_t & ivOffset) -{ -#if defined(SL_MBEDTLS_USE_TINYCRYPT) - uint8_t keyBuffer[kOTAEncryptionKeyLength] = { 0 }; - size_t keyLen = 0; - - // Read the key from the provisioning storage - MutableByteSpan keySpan = MutableByteSpan(keyBuffer); - - SilabsConfig::ReadConfigValueBin(SilabsConfig::kOtaTlvEncryption_KeyId, keySpan.data(), keySpan.size()); - VerifyOrReturnError(keySpan.size() == kOTAEncryptionKeyLength, CHIP_ERROR_INVALID_ARGUMENT); - - Silabs::OtaTlvEncryptionKey::Decrypt((const ByteSpan) keySpan, block, ivOffset); - return CHIP_NO_ERROR; -#else // MBEDTLS_USE_PSA_CRYPTO - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#endif // SL_MBEDTLS_USE_TINYCRYPT -} -#else -CHIP_ERROR Storage::SetOtaTlvEncryptionKey(const ByteSpan & value) -{ - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -} - -CHIP_ERROR Storage::GetOtaTlvEncryptionKeyId(uint32_t & keyId) -{ - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -} - -CHIP_ERROR Storage::DecryptUsingOtaTlvEncryptionKey(MutableByteSpan & block, uint32_t & ivOffset) -{ - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -} -#endif // SL_MATTER_ENABLE_OTA_ENCRYPTION - -CHIP_ERROR Storage::SetTestEventTriggerKey(const ByteSpan & value) -{ -#ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLED - constexpr size_t kEnableKeyLength = 16; // Expected byte size of the EnableKey - - // Verify that the provided key has the correct length - VerifyOrReturnError(value.size() == kEnableKeyLength, CHIP_ERROR_INVALID_ARGUMENT); - - // Write the key to the configuration storage - ReturnErrorOnFailure( - SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_Test_Event_Trigger_Key, value.data(), value.size())); - - return CHIP_NO_ERROR; -#else - return CHIP_ERROR_NOT_IMPLEMENTED; -#endif // SL_MATTER_TEST_EVENT_TRIGGER_ENABLED -} - -CHIP_ERROR Storage::GetTestEventTriggerKey(MutableByteSpan & keySpan) -{ -#ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLED - constexpr size_t kEnableKeyLength = 16; // Expected byte size of the EnableKey - CHIP_ERROR err = CHIP_NO_ERROR; - size_t keyLength = 0; - - VerifyOrReturnError(keySpan.size() >= kEnableKeyLength, CHIP_ERROR_BUFFER_TOO_SMALL); - - err = SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_Test_Event_Trigger_Key, keySpan.data(), kEnableKeyLength, - keyLength); -#ifndef NDEBUG -#ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLE_KEY - if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) - { - - constexpr char enableKey[] = SL_MATTER_TEST_EVENT_TRIGGER_ENABLE_KEY; - if (Encoding::HexToBytes(enableKey, strlen(enableKey), keySpan.data(), kEnableKeyLength) != kEnableKeyLength) - { - // enableKey Hex String doesn't have the correct length - memset(keySpan.data(), 0, keySpan.size()); - ChipLogError(DeviceLayer, "Test Event Trigger EnableKey parsing failed"); - return CHIP_ERROR_INTERNAL; - } - err = CHIP_NO_ERROR; - } -#endif // SL_MATTER_TEST_EVENT_TRIGGER_ENABLE_KEY -#endif // NDEBUG - - keySpan.reduce_size(kEnableKeyLength); - return err; -#else - return CHIP_ERROR_NOT_IMPLEMENTED; -#endif // SL_MATTER_TEST_EVENT_TRIGGER_ENABLED -} - -} // namespace Provision -} // namespace Silabs -} // namespace DeviceLayer -} // namespace chip diff --git a/examples/platform/silabs/provision/ProvisionStorageFlash.cpp b/examples/platform/silabs/provision/ProvisionStorageFlash.cpp deleted file mode 100644 index e2401fcc68e..00000000000 --- a/examples/platform/silabs/provision/ProvisionStorageFlash.cpp +++ /dev/null @@ -1,856 +0,0 @@ -/* - * Copyright (c) 2024 Project CHIP Authors - * All rights reserved. - * - * 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. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef NDEBUG -#if defined(SL_MATTER_TEST_EVENT_TRIGGER_ENABLED) && (SL_MATTER_GN_BUILD == 0) -#include -#endif // defined(SL_MATTER_TEST_EVENT_TRIGGER_ENABLED) && (SL_MATTER_GN_BUILD == 0) -#endif // NDEBUG -#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION -#include -#endif // SL_MATTER_ENABLE_OTA_ENCRYPTION - -#include - -#if !(SL_MATTER_GN_BUILD || defined(SL_PROVISION_GENERATOR)) -#include -#endif - -using namespace chip::Credentials; - -#if SLI_SI91X_MCU_INTERFACE -// TODO: Remove this once the flash header integrates these definitions -#define FLASH_ERASE 1 // flash_sector_erase_enable value for erase operation -#define FLASH_WRITE 0 // flash_sector_erase_enable value for write operation - -#define NWP_FLASH_ADDRESS (0x0000000) -#define NWP_FLASH_SIZE (0x0004E20) - -#include -extern "C" { -#include -#include -#include -#include -} - -#else // SLI_SI91X_MCU_INTERFACE -#include -extern uint8_t linker_nvm_end[]; -#endif // SLI_SI91X_MCU_INTERFACE - -namespace { -constexpr size_t kPageSize = FLASH_PAGE_SIZE; -constexpr size_t kMaxBinaryValue = 1024; -constexpr size_t kArgumentBufferSize = 2 * sizeof(uint16_t) + kMaxBinaryValue; // ID(2) + Size(2) + Value(n) -} // namespace - -namespace chip { -namespace DeviceLayer { -namespace Silabs { -namespace Provision { -namespace Flash { - -#if SLI_SI91X_MCU_INTERFACE -static uint8_t * sReadOnlyPage = reinterpret_cast(NWP_FLASH_ADDRESS); -#else -static uint8_t * sReadOnlyPage = reinterpret_cast(linker_nvm_end); -#endif // SLI_SI91X_MCU_INTERFACE -uint8_t sTemporaryPage[kPageSize] = { 0 }; -uint8_t * sActivePage = sReadOnlyPage; - -CHIP_ERROR DecodeTotal(Encoding::Buffer & reader, uint16_t & total) -{ - uint16_t sz = 0; - ReturnErrorOnFailure(reader.Get(sz)); - total = (0xffff == sz) ? sizeof(uint16_t) : sz; - reader.in = reader.begin + total; - VerifyOrReturnError(reader.in <= reader.end, CHIP_ERROR_INTERNAL, ChipLogError(DeviceLayer, "Invalid page, or corrupted data")); - return CHIP_NO_ERROR; -} - -CHIP_ERROR ActivateWrite(uint8_t *& active) -{ -#if !(SLI_SI91X_MCU_INTERFACE) - if (sActivePage == sReadOnlyPage) - { - memcpy(sTemporaryPage, sReadOnlyPage, sizeof(sTemporaryPage)); - } - active = sActivePage = sTemporaryPage; -#endif - return CHIP_NO_ERROR; -} - -CHIP_ERROR Set(uint16_t id, Encoding::Buffer & in) -{ - uint8_t * page = sActivePage; - uint16_t total = 0; - Encoding::Buffer reader(page, kPageSize, true); - uint8_t temp[kArgumentBufferSize] = { 0 }; - Encoding::Version2::Argument found(temp, sizeof(temp)); - - // Decode total - ReturnErrorOnFailure(DecodeTotal(reader, total)); - // Search entry - CHIP_ERROR err = Encoding::Version2::Find(reader, id, found); - if ((CHIP_ERROR_NOT_FOUND != err) && (CHIP_NO_ERROR != err)) - { - // Memory corruption, write at the last correct address - return err; - } - ReturnErrorOnFailure(ActivateWrite(page)); - - Encoding::Buffer writer(page, kPageSize); - if (CHIP_ERROR_NOT_FOUND == err) - { - // New entry - size_t temp_total = found.offset; - VerifyOrReturnError(temp_total + in.Size() <= kPageSize, CHIP_ERROR_INVALID_ARGUMENT); - // Copy entry - ReturnErrorOnFailure(in.Get(page + temp_total, in.Size())); - // Update total - total = temp_total + in.Size(); - ReturnErrorOnFailure(writer.Add(total)); - } - else - { - // Existing entry - if (in.Size() == found.encoded_size) - { - // Same size, keep in place - memset(page + found.offset, 0xff, found.encoded_size); - ReturnErrorOnFailure(in.Get(page + found.offset, in.Size())); - } - else - { - // Size change, move to the end - uint16_t temp_total = total - found.encoded_size; - VerifyOrReturnError(temp_total + in.Size() <= kPageSize, CHIP_ERROR_INVALID_ARGUMENT); - // Remove the entry - memmove(page + found.offset, page + found.offset + found.encoded_size, temp_total); - // Add the entry - ReturnErrorOnFailure(in.Get(page + temp_total, in.Size())); - // Update total - total = temp_total + in.Size(); - ReturnErrorOnFailure(writer.Add(total)); - } - } - return CHIP_NO_ERROR; -} - -CHIP_ERROR Get(uint16_t id, Encoding::Version2::Argument & arg) -{ - uint16_t total = 0; - - Encoding::Buffer reader(sActivePage, kPageSize, true); - ReturnErrorOnFailure(DecodeTotal(reader, total)); - CHIP_ERROR err = Encoding::Version2::Find(reader, id, arg); - // ProvisionStorage expects CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND - VerifyOrReturnError(CHIP_ERROR_NOT_FOUND != err, CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); - return err; -} - -CHIP_ERROR Set(uint16_t id, uint8_t value) -{ - uint8_t temp[kArgumentBufferSize] = { 0 }; - Encoding::Version2::Argument arg(temp, sizeof(temp)); - ReturnErrorOnFailure(Encoding::Version2::Encode(id, &value, arg)); - return Set(id, arg); -} - -CHIP_ERROR Get(uint16_t id, uint8_t & value) -{ - uint8_t temp[kArgumentBufferSize] = { 0 }; - Encoding::Version2::Argument arg(temp, sizeof(temp)); - ReturnErrorOnFailure(Get(id, arg)); - VerifyOrReturnError(Encoding::Version2::Type_Int8u == arg.type, CHIP_ERROR_INVALID_ARGUMENT); - value = arg.value.u8; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Set(uint16_t id, uint16_t value) -{ - uint8_t temp[kArgumentBufferSize] = { 0 }; - Encoding::Version2::Argument arg(temp, sizeof(temp)); - ReturnErrorOnFailure(Encoding::Version2::Encode(id, &value, arg)); - return Set(id, arg); -} - -CHIP_ERROR Get(uint16_t id, uint16_t & value) -{ - uint8_t temp[kArgumentBufferSize] = { 0 }; - Encoding::Version2::Argument arg(temp, sizeof(temp)); - ReturnErrorOnFailure(Get(id, arg)); - VerifyOrReturnError(Encoding::Version2::Type_Int16u == arg.type, CHIP_ERROR_INVALID_ARGUMENT); - value = arg.value.u16; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Set(uint16_t id, uint32_t value) -{ - uint8_t temp[kArgumentBufferSize] = { 0 }; - Encoding::Version2::Argument arg(temp, sizeof(temp)); - ReturnErrorOnFailure(Encoding::Version2::Encode(id, &value, arg)); - return Set(id, arg); -} - -CHIP_ERROR Get(uint16_t id, uint32_t & value) -{ - uint8_t temp[kArgumentBufferSize] = { 0 }; - Encoding::Version2::Argument arg(temp, sizeof(temp)); - ReturnErrorOnFailure(Get(id, arg)); - VerifyOrReturnError(Encoding::Version2::Type_Int32u == arg.type, CHIP_ERROR_INVALID_ARGUMENT); - value = arg.value.u32; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Set(uint16_t id, const uint8_t * value, size_t size) -{ - uint8_t temp[kArgumentBufferSize] = { 0 }; - Encoding::Version2::Argument arg(temp, sizeof(temp)); - ReturnErrorOnFailure(Encoding::Version2::Encode(id, value, size, arg)); - return Set(id, arg); -} - -CHIP_ERROR Get(uint16_t id, uint8_t * value, size_t max_size, size_t & size) -{ - - uint8_t temp[kArgumentBufferSize] = { 0 }; - Encoding::Version2::Argument arg(temp, sizeof(temp)); - ReturnErrorOnFailure(Get(id, arg)); - VerifyOrReturnError(Encoding::Version2::Type_Binary == arg.type, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(arg.size <= max_size, CHIP_ERROR_BUFFER_TOO_SMALL); - memcpy(value, arg.value.b, arg.size); - size = arg.size; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Set(uint16_t id, const char * value, size_t size) -{ - return Set(id, (const uint8_t *) value, size); -} - -CHIP_ERROR Get(uint16_t id, char * value, size_t max_size, size_t & size) -{ - // No room for a NUL-terminated C string; reject before max_size - 1 (avoids underflow) and skip storage. - VerifyOrReturnError(max_size > 0, CHIP_ERROR_INVALID_ARGUMENT); - ReturnErrorOnFailure(Get(id, (uint8_t *) value, max_size - 1, size)); - // Binary Get does not NUL-terminate; DeviceInstanceInfoProvider requires it on success. - value[size] = '\0'; - return CHIP_NO_ERROR; -} - -} // namespace Flash - -// -// Initialization -// - -CHIP_ERROR Storage::Initialize(uint32_t flash_addr, uint32_t flash_size) -{ -#if SLI_SI91X_MCU_INTERFACE - sl_status_t status = sl_si91x_command_to_read_common_flash((uint32_t) (Flash::sReadOnlyPage), sizeof(Flash::sTemporaryPage), - Flash::sTemporaryPage); - VerifyOrReturnError(status == SL_STATUS_OK, CHIP_ERROR_INVALID_ARGUMENT); - Flash::sActivePage = Flash::sTemporaryPage; - -#else // SLI_SI91X_MCU_INTERFACE - if (flash_size > 0) - { - Flash::sReadOnlyPage = (uint8_t *) (flash_addr + flash_size - kPageSize); - } - Flash::sActivePage = Flash::sReadOnlyPage; - MSC_Init(); -#endif - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::Commit() -{ - if (Flash::sActivePage == Flash::sTemporaryPage) - { -#if SLI_SI91X_MCU_INTERFACE - // Erase page - sl_status_t status = sl_si91x_command_to_write_common_flash((uint32_t) (Flash::sReadOnlyPage), Flash::sTemporaryPage, - kPageSize, FLASH_ERASE); - VerifyOrReturnError(status == SL_STATUS_OK, CHIP_ERROR_WRITE_FAILED); - // Write to flash - status = sl_si91x_command_to_write_common_flash((uint32_t) (Flash::sReadOnlyPage), Flash::sTemporaryPage, kPageSize, - FLASH_WRITE); - VerifyOrReturnError(status == SL_STATUS_OK, CHIP_ERROR_WRITE_FAILED); -#else - // Erase page - MSC_ErasePage((uint32_t *) Flash::sReadOnlyPage); - // Write to flash - MSC_WriteWord((uint32_t *) Flash::sReadOnlyPage, Flash::sTemporaryPage, kPageSize); -#endif // SLI_SI91X_MCU_INTERFACE - } - return CHIP_NO_ERROR; -} - -// -// DeviceInstanceInfoProvider -// - -CHIP_ERROR Storage::SetSerialNumber(const char * value, size_t len) -{ - return Flash::Set(Parameters::ID::kSerialNumber, value, len); -} - -CHIP_ERROR Storage::GetSerialNumber(char * value, size_t max) -{ - size_t size = 0; - return Flash::Get(Parameters::ID::kSerialNumber, value, max, size); -} - -CHIP_ERROR Storage::SetVendorId(uint16_t value) -{ - return Flash::Set(Parameters::ID::kVendorId, value); -} - -CHIP_ERROR Storage::GetVendorId(uint16_t & value) -{ - CHIP_ERROR err = Flash::Get(Parameters::ID::kVendorId, value); -#if defined(CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID) && CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - value = CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID; - err = CHIP_NO_ERROR; - } -#endif - return err; -} - -CHIP_ERROR Storage::SetVendorName(const char * value, size_t len) -{ - return Flash::Set(Parameters::ID::kVendorName, value, len); -} - -CHIP_ERROR Storage::GetVendorName(char * value, size_t max) -{ - size_t size = 0; - CHIP_ERROR err = Flash::Get(Parameters::ID::kVendorName, value, max, size); -#if defined(CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME) - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - VerifyOrReturnError(value != nullptr, CHIP_ERROR_NO_MEMORY); - VerifyOrReturnError(max > strlen(CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME), CHIP_ERROR_BUFFER_TOO_SMALL); - Platform::CopyString(value, max, CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME); - err = CHIP_NO_ERROR; - } -#endif - return err; -} - -CHIP_ERROR Storage::SetProductId(uint16_t value) -{ - return Flash::Set(Parameters::ID::kProductId, value); -} - -CHIP_ERROR Storage::GetProductId(uint16_t & value) -{ - CHIP_ERROR err = Flash::Get(Parameters::ID::kProductId, value); -#if defined(CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID) && CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - value = CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID; - err = CHIP_NO_ERROR; - } -#endif - return err; -} - -CHIP_ERROR Storage::SetProductName(const char * value, size_t len) -{ - return Flash::Set(Parameters::ID::kProductName, value, len); -} - -CHIP_ERROR Storage::GetProductName(char * value, size_t max) -{ - size_t size = 0; - CHIP_ERROR err = Flash::Get(Parameters::ID::kProductName, value, max, size); -#if defined(CHIP_DEVICE_CONFIG_TEST_PRODUCT_NAME) - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - VerifyOrReturnError(value != nullptr, CHIP_ERROR_NO_MEMORY); - VerifyOrReturnError(max > strlen(CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME), CHIP_ERROR_BUFFER_TOO_SMALL); - Platform::CopyString(value, max, CHIP_DEVICE_CONFIG_TEST_PRODUCT_NAME); - err = CHIP_NO_ERROR; - } -#endif - return err; -} - -CHIP_ERROR Storage::SetProductLabel(const char * value, size_t len) -{ - return Flash::Set(Parameters::ID::kProductLabel, value, len); -} - -CHIP_ERROR Storage::GetProductLabel(char * value, size_t max) -{ - size_t size = 0; - return Flash::Get(Parameters::ID::kProductLabel, value, max, size); -} - -CHIP_ERROR Storage::SetProductURL(const char * value, size_t len) -{ - return Flash::Set(Parameters::ID::kProductUrl, value, len); -} -CHIP_ERROR Storage::GetProductURL(char * value, size_t max) -{ - size_t size = 0; - return Flash::Get(Parameters::ID::kProductUrl, value, max, size); -} - -CHIP_ERROR Storage::SetPartNumber(const char * value, size_t len) -{ - return Flash::Set(Parameters::ID::kPartNumber, value, len); -} - -CHIP_ERROR Storage::GetPartNumber(char * value, size_t max) -{ - size_t size = 0; - return Flash::Get(Parameters::ID::kPartNumber, value, max, size); -} - -CHIP_ERROR Storage::SetHardwareVersion(uint16_t value) -{ - return Flash::Set(Parameters::ID::kHwVersion, value); -} - -CHIP_ERROR Storage::GetHardwareVersion(uint16_t & value) -{ - CHIP_ERROR err = Flash::Get(Parameters::ID::kHwVersion, value); -#if defined(CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION) - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - value = CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION; - err = CHIP_NO_ERROR; - } -#endif // CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION - return err; -} - -CHIP_ERROR Storage::SetHardwareVersionString(const char * value, size_t len) -{ - return Flash::Set(Parameters::ID::kHwVersionStr, value, len); -} - -CHIP_ERROR Storage::GetHardwareVersionString(char * value, size_t max) -{ - size_t size = 0; - CHIP_ERROR err = Flash::Get(Parameters::ID::kHwVersionStr, value, max, size); -#if defined(CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING) - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - VerifyOrReturnError(value != nullptr, CHIP_ERROR_NO_MEMORY); - VerifyOrReturnError(max > strlen(CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING), CHIP_ERROR_BUFFER_TOO_SMALL); - Platform::CopyString(value, max, CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING); - err = CHIP_NO_ERROR; - } -#endif // CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING - return err; -} - -CHIP_ERROR Storage::SetManufacturingDate(const char * value, size_t len) -{ - return Flash::Set(Parameters::ID::kManufacturingDate, value, len); -} - -CHIP_ERROR Storage::GetManufacturingDate(uint8_t * value, size_t max, size_t & size) -{ - return Flash::Get(Parameters::ID::kManufacturingDate, value, max, size); -} - -CHIP_ERROR Storage::SetPersistentUniqueId(const uint8_t * value, size_t size) -{ - return Flash::Set(Parameters::ID::kPersistentUniqueId, value, size); -} - -CHIP_ERROR Storage::GetPersistentUniqueId(uint8_t * value, size_t max, size_t & size) -{ - return Flash::Get(Parameters::ID::kPersistentUniqueId, value, max, size); -} - -// -// CommissionableDataProvider -// - -CHIP_ERROR Storage::SetSetupDiscriminator(uint16_t value) -{ - return Flash::Set(Parameters::ID::kDiscriminator, value); -} - -CHIP_ERROR Storage::GetSetupDiscriminator(uint16_t & value) -{ - CHIP_ERROR err = Flash::Get(Parameters::ID::kDiscriminator, value); -#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR) && CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - value = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR; - err = CHIP_NO_ERROR; - } -#endif // CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR - ReturnErrorOnFailure(err); - VerifyOrReturnLogError(value <= kMaxDiscriminatorValue, CHIP_ERROR_INVALID_ARGUMENT); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetSpake2pIterationCount(uint32_t value) -{ - return Flash::Set(Parameters::ID::kSpake2pIterations, value); -} - -CHIP_ERROR Storage::GetSpake2pIterationCount(uint32_t & value) -{ - CHIP_ERROR err = Flash::Get(Parameters::ID::kSpake2pIterations, value); -#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT) && CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - value = CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT; - err = CHIP_NO_ERROR; - } -#endif // CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT - return err; -} - -CHIP_ERROR Storage::SetSetupPasscode(uint32_t value) -{ - return CHIP_ERROR_NOT_IMPLEMENTED; -} - -CHIP_ERROR Storage::GetSetupPasscode(uint32_t & value) -{ - return CHIP_ERROR_NOT_IMPLEMENTED; -} - -CHIP_ERROR Storage::SetSpake2pSalt(const char * value, size_t size) -{ - return Flash::Set(Parameters::ID::kSpake2pSalt, value, size); -} - -CHIP_ERROR Storage::GetSpake2pSalt(char * value, size_t max, size_t & size) -{ - return Flash::Get(Parameters::ID::kSpake2pSalt, value, max, size); -} - -CHIP_ERROR Storage::SetSpake2pVerifier(const char * value, size_t size) -{ - return Flash::Set(Parameters::ID::kSpake2pVerifier, value, size); -} - -CHIP_ERROR Storage::GetSpake2pVerifier(char * value, size_t max, size_t & size) -{ - return Flash::Get(Parameters::ID::kSpake2pVerifier, value, max, size); -} - -// -// DeviceAttestationCredentialsProvider -// - -CHIP_ERROR Storage::SetFirmwareInformation(const ByteSpan & value) -{ - (void) value; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::GetFirmwareInformation(MutableByteSpan & value) -{ - // TODO: We need a real example FirmwareInformation to be populated. - value.reduce_size(0); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetCertificationDeclaration(const ByteSpan & value) -{ - return Flash::Set(Parameters::ID::kCertification, value.data(), value.size()); -} - -CHIP_ERROR Storage::GetCertificationDeclaration(MutableByteSpan & value) -{ - size_t size = 0; - CHIP_ERROR err = (Flash::Get(Parameters::ID::kCertification, value.data(), value.size(), size)); -#ifdef SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - // Example CD - return Examples::GetExampleDACProvider()->GetCertificationDeclaration(value); - } -#endif // SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS - ReturnErrorOnFailure(err); - value.reduce_size(size); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetProductAttestationIntermediateCert(const ByteSpan & value) -{ - return Flash::Set(Parameters::ID::kPaiCert, value.data(), value.size()); -} - -CHIP_ERROR Storage::GetProductAttestationIntermediateCert(MutableByteSpan & value) -{ - size_t size = 0; - CHIP_ERROR err = (Flash::Get(Parameters::ID::kPaiCert, value.data(), value.size(), size)); -#ifdef SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - // Example PAI - return Examples::GetExampleDACProvider()->GetProductAttestationIntermediateCert(value); - } -#endif // SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS - ReturnErrorOnFailure(err); - value.reduce_size(size); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetDeviceAttestationCert(const ByteSpan & value) -{ - return Flash::Set(Parameters::ID::kDacCert, value.data(), value.size()); -} - -CHIP_ERROR Storage::GetDeviceAttestationCert(MutableByteSpan & value) -{ - size_t size = 0; - CHIP_ERROR err = (Flash::Get(Parameters::ID::kDacCert, value.data(), value.size(), size)); -#ifdef SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - // Example DAC - return Examples::GetExampleDACProvider()->GetDeviceAttestationCert(value); - } -#endif // SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS - ReturnErrorOnFailure(err); - value.reduce_size(size); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetDeviceAttestationKey(const ByteSpan & value) -{ - return Flash::Set(Parameters::ID::kDacKey, value.data(), value.size()); -} - -CHIP_ERROR Storage::GetDeviceAttestationCSR(uint16_t vid, uint16_t pid, const CharSpan & cn, MutableCharSpan & csr) -{ - AttestationKey key; - uint8_t temp[kDeviceAttestationKeySizeMax] = { 0 }; - size_t size = 0; - ReturnErrorOnFailure(key.GenerateCSR(vid, pid, cn, csr)); - ReturnErrorOnFailure(key.Export(temp, sizeof(temp), size)); - return Flash::Set(Parameters::ID::kDacKey, temp, size); -} - -CHIP_ERROR Storage::SignWithDeviceAttestationKey(const ByteSpan & message, MutableByteSpan & signature) -{ - uint8_t temp[kDeviceAttestationKeySizeMax] = { 0 }; - size_t size = 0; - CHIP_ERROR err = Flash::Get(Parameters::ID::kDacKey, temp, sizeof(temp), size); -#ifdef SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - // Example DAC key - return Examples::GetExampleDACProvider()->SignWithDeviceAttestationKey(message, signature); - } -#endif // SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS - ReturnErrorOnFailure(err); -#ifdef SL_MBEDTLS_USE_TINYCRYPT - uint8_t key_buffer[kDeviceAttestationKeySizeMax] = { 0 }; - MutableByteSpan private_key(key_buffer); - TEMPORARY_RETURN_IGNORED AttestationKey::Unwrap(temp, size, private_key); - return AttestationKey::SignMessageWithKey((const uint8_t *) key_buffer, message, signature); -#else - AttestationKey key; - ReturnErrorOnFailure(key.Import(temp, size)); - return key.SignMessage(message, signature); -#endif // SL_MBEDTLS_USE_TINYCRYPT -} - -// -// Other -// - -CHIP_ERROR Storage::SetCredentialsBaseAddress(uint32_t addr) -{ - Flash::sReadOnlyPage = (uint8_t *) addr; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::GetCredentialsBaseAddress(uint32_t & addr) -{ - addr = (uint32_t) Flash::sReadOnlyPage; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetProvisionVersion(const char * value, size_t size) -{ - return Flash::Set(Parameters::ID::kVersion, value, size); -} - -CHIP_ERROR Storage::GetProvisionVersion(char * value, size_t max, size_t & size) -{ - return Flash::Get(Parameters::ID::kVersion, value, max, size); -} - -CHIP_ERROR Storage::SetSetupPayload(const uint8_t * value, size_t size) -{ - return Flash::Set(Parameters::ID::kSetupPayload, value, size); -} - -CHIP_ERROR Storage::GetSetupPayload(uint8_t * value, size_t max, size_t & size) -{ - return Flash::Get(Parameters::ID::kSetupPayload, value, max, size); -} - -CHIP_ERROR Storage::SetProvisionRequest(bool value) -{ - // return Flash::Set(Parameters::ID::kProvisionRequest, value); - return CHIP_ERROR_NOT_IMPLEMENTED; -} - -CHIP_ERROR Storage::GetProvisionRequest(bool & value) -{ - // return Flash::Set(Parameters::ID::kProvisionRequest, value); - return CHIP_ERROR_NOT_IMPLEMENTED; -} - -#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION -CHIP_ERROR Storage::SetOtaTlvEncryptionKey(const ByteSpan & value) -{ -#if defined(SL_MBEDTLS_USE_TINYCRYPT) - // Tinycrypt doesn't support the key ID, so we need to store the key as a binary blob - return Flash::Set(Parameters::ID::kOtaTlvEncryptionKey, value.data(), value.size()); -#else // MBEDTLS_USE_PSA_CRYPTO - Silabs::OtaTlvEncryptionKey key; - ReturnErrorOnFailure(key.Import(value.data(), value.size())); - return Flash::Set(Parameters::ID::kOtaTlvEncryptionKey, key.GetId()); -#endif // SL_MBEDTLS_USE_TINYCRYPT -} - -CHIP_ERROR Storage::GetOtaTlvEncryptionKeyId(uint32_t & keyId) -{ -#if defined(SL_MBEDTLS_USE_TINYCRYPT) - // Tinycrypt doesn't support the key ID - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#else // MBEDTLS_USE_PSA_CRYPTO - return Flash::Get(Parameters::ID::kOtaTlvEncryptionKey, keyId); -#endif // SL_MBEDTLS_USE_TINYCRYPT -} - -CHIP_ERROR Storage::DecryptUsingOtaTlvEncryptionKey(MutableByteSpan & block, uint32_t & ivOffset) -{ -#if defined(SL_MBEDTLS_USE_TINYCRYPT) - uint8_t keyBuffer[Silabs::OtaTlvEncryptionKey::kOTAEncryptionKeyLength] = { 0 }; - size_t keyLen = 0; - - // Read the key from the provisioning storage - MutableByteSpan keySpan = MutableByteSpan(keyBuffer); - - ReturnErrorOnFailure(Flash::Get(Parameters::ID::kOtaTlvEncryptionKey, keySpan.data(), keySpan.size(), keyLen)); - keySpan.reduce_size(keyLen); - - VerifyOrReturnError(keySpan.size() == Silabs::OtaTlvEncryptionKey::kOTAEncryptionKeyLength, CHIP_ERROR_INVALID_ARGUMENT); - - ReturnErrorOnFailure(Silabs::OtaTlvEncryptionKey::Decrypt((const ByteSpan) keySpan, block, ivOffset)); - return CHIP_NO_ERROR; -#else // MBEDTLS_USE_PSA_CRYPTO - return CHIP_ERROR_NOT_IMPLEMENTED; -#endif // SL_MBEDTLS_USE_TINYCRYPT -} -#else -CHIP_ERROR Storage::SetOtaTlvEncryptionKey(const ByteSpan & value) -{ - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -} - -CHIP_ERROR Storage::GetOtaTlvEncryptionKeyId(uint32_t & keyId) -{ - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -} - -CHIP_ERROR Storage::DecryptUsingOtaTlvEncryptionKey(MutableByteSpan & block, uint32_t & ivOffset) -{ - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -} -#endif // SL_MATTER_ENABLE_OTA_ENCRYPTION - -#if defined(SL_MATTER_TEST_EVENT_TRIGGER_ENABLED) && SL_MATTER_TEST_EVENT_TRIGGER_ENABLED -CHIP_ERROR Storage::SetTestEventTriggerKey(const ByteSpan & value) -{ - // Verify that the provided key has the correct length - VerifyOrReturnError(value.size() == TestEventTriggerDelegate::kEnableKeyLength, CHIP_ERROR_INVALID_ARGUMENT); - - // Write the key to the configuration storage - return Flash::Set(Parameters::ID::kTestEventTriggerKey, value.data(), value.size()); -} - -CHIP_ERROR Storage::GetTestEventTriggerKey(MutableByteSpan & keySpan) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - size_t keyLength = 0; - - VerifyOrReturnError(keySpan.size() >= TestEventTriggerDelegate::kEnableKeyLength, CHIP_ERROR_BUFFER_TOO_SMALL); - - err = Flash::Get(Parameters::ID::kTestEventTriggerKey, keySpan.data(), TestEventTriggerDelegate::kEnableKeyLength, keyLength); - -#ifndef NDEBUG -#ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLE_KEY - if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) - { - constexpr char enableKey[] = SL_MATTER_TEST_EVENT_TRIGGER_ENABLE_KEY; - if (chip::Encoding::HexToBytes(enableKey, strlen(enableKey), keySpan.data(), TestEventTriggerDelegate::kEnableKeyLength) != - TestEventTriggerDelegate::kEnableKeyLength) - { - // enableKey Hex String doesn't have the correct length - memset(keySpan.data(), 0, keySpan.size()); - return CHIP_ERROR_INTERNAL; - } - } - return CHIP_NO_ERROR; -#endif // SL_MATTER_TEST_EVENT_TRIGGER_ENABLE_KEY -#endif // NDEBUG - - keySpan.reduce_size(TestEventTriggerDelegate::kEnableKeyLength); - return err; -} - -#else // SL_MATTER_TEST_EVENT_TRIGGER_ENABLED - -CHIP_ERROR Storage::SetTestEventTriggerKey(const ByteSpan & value) -{ - return CHIP_ERROR_NOT_IMPLEMENTED; -} -CHIP_ERROR Storage::GetTestEventTriggerKey(MutableByteSpan & keySpan) -{ - return CHIP_ERROR_NOT_IMPLEMENTED; -} - -#endif // SL_MATTER_TEST_EVENT_TRIGGER_ENABLED - -} // namespace Provision -} // namespace Silabs -} // namespace DeviceLayer -} // namespace chip diff --git a/examples/platform/silabs/provision/ProvisionStorageReader.h b/examples/platform/silabs/provision/ProvisionStorageReader.h new file mode 100644 index 00000000000..17760e59fae --- /dev/null +++ b/examples/platform/silabs/provision/ProvisionStorageReader.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + * + * 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. + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { + +/** + * Silicon Labs factory-data storage reader. + * + * The selected storage backend implements this class. It is both the read-only + * persistence capability consumed by Provision Core and the Matter-facing + * provider used by normal applications. + */ +class ProvisionStorageReader final : public IProvisionStorageReader, + public chip::DeviceLayer::DeviceInstanceInfoProvider, + public chip::DeviceLayer::CommissionableDataProvider, + public chip::Credentials::DeviceAttestationCredentialsProvider +{ +public: + static ProvisionStorageReader & GetInstance(); + + ProvisionStorageReader(const ProvisionStorageReader &) = delete; + ProvisionStorageReader & operator=(const ProvisionStorageReader &) = delete; + + // Methods whose signatures are shared by the persistence and Matter APIs. + CHIP_ERROR GetSerialNumber(char * value, size_t max) override; + CHIP_ERROR GetVendorId(uint16_t & value) override; + CHIP_ERROR GetVendorName(char * value, size_t max) override; + CHIP_ERROR GetProductId(uint16_t & value) override; + CHIP_ERROR GetProductName(char * value, size_t max) override; + CHIP_ERROR GetProductLabel(char * value, size_t max) override; + CHIP_ERROR GetProductURL(char * value, size_t max) override; + CHIP_ERROR GetPartNumber(char * value, size_t max) override; + CHIP_ERROR GetHardwareVersion(uint16_t & value) override; + CHIP_ERROR GetHardwareVersionString(char * value, size_t max) override; + CHIP_ERROR GetManufacturingDate(uint8_t * value, size_t max, size_t & size) override; + CHIP_ERROR GetPersistentUniqueId(uint8_t * value, size_t max, size_t & size) override; + + CHIP_ERROR GetSetupDiscriminator(uint16_t & value) override; + CHIP_ERROR GetSpake2pIterationCount(uint32_t & value) override; + CHIP_ERROR GetSpake2pSalt(char * value, size_t max, size_t & size) override; + CHIP_ERROR GetSpake2pVerifier(char * value, size_t max, size_t & size) override; + CHIP_ERROR GetSetupPayload(uint8_t * value, size_t max, size_t & size) override; + + CHIP_ERROR GetFirmwareInformation(MutableByteSpan & value) override; + CHIP_ERROR GetCertificationDeclaration(MutableByteSpan & value) override; + CHIP_ERROR GetProductAttestationIntermediateCert(MutableByteSpan & value) override; + CHIP_ERROR GetDeviceAttestationCert(MutableByteSpan & value) override; + + CHIP_ERROR GetProvisionVersion(char * value, size_t max, size_t & size) override; + + // Matter-facing interpretation of persisted factory data. + CHIP_ERROR GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) override; + CHIP_ERROR GetManufacturingDateSuffix(MutableCharSpan & suffixBuffer) override; + CHIP_ERROR GetRotatingDeviceIdUniqueId(MutableByteSpan & value) override; + CHIP_ERROR SetSetupDiscriminator(uint16_t value) override; + CHIP_ERROR GetSetupPasscode(uint32_t & value) override; + CHIP_ERROR SetSetupPasscode(uint32_t value) override; + CHIP_ERROR GetSpake2pSalt(MutableByteSpan & value) override; + CHIP_ERROR GetSpake2pVerifier(MutableByteSpan & value, size_t & size) override; + CHIP_ERROR SignWithDeviceAttestationKey(const ByteSpan & message, MutableByteSpan & signature) override; + + // Common method to read the setup payload as mutable byte span. + CHIP_ERROR GetSetupPayload(MutableCharSpan & value); + + // Silicon Labs provisioned-data access used by optional platform features. + CHIP_ERROR GetTestEventTriggerKey(MutableByteSpan & keySpan) override; + CHIP_ERROR GetOtaTlvEncryptionKeyId(uint32_t & value) override; + CHIP_ERROR DecryptUsingOtaTlvEncryptionKey(MutableByteSpan & block, uint32_t & ivOffset) override; + +private: + ProvisionStorageReader() = default; + + // Provisioning stores this as YYYYMMDD followed by an optional hhmmssxx suffix. + static constexpr size_t kManufacturingDateBufferSize = sizeof("yyyymmddhhmmssxx"); + static constexpr size_t kSpake2pSaltB64BufferSize = BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length) + 1; + static constexpr size_t kSpake2pVerifierB64BufferSize = + BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_VerifierSerialized_Length) + 1; + static constexpr size_t kSpake2pSaltDecodedBufferSize = BASE64_MAX_DECODED_LEN(kSpake2pSaltB64BufferSize); + static constexpr size_t kSpake2pVerifierDecodedBufferSize = BASE64_MAX_DECODED_LEN(kSpake2pVerifierB64BufferSize); +}; + +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/ProvisionStorageReaderCommon.cpp b/examples/platform/silabs/provision/ProvisionStorageReaderCommon.cpp new file mode 100644 index 00000000000..55625b18de2 --- /dev/null +++ b/examples/platform/silabs/provision/ProvisionStorageReaderCommon.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#include "ProvisionStorageReader.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { + +CHIP_ERROR ProvisionStorageReader::GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) +{ + constexpr size_t kDateLength = 8; // YYYYMMDD + constexpr size_t kLegacyDateLength = 10; // YYYY-MM-DD + char date[kManufacturingDateBufferSize] = { 0 }; + char normalized[kDateLength + 1] = { 0 }; + size_t dateLength = 0; + char * parseEnd = nullptr; + + ReturnErrorOnFailure(GetManufacturingDate(reinterpret_cast(date), sizeof(date), dateLength)); + const char * parsedDate = date; + if (dateLength == kLegacyDateLength && date[4] == '-' && date[7] == '-') + { + snprintf(normalized, sizeof(normalized), "%.4s%.2s%.2s", date, date + 5, date + 8); + parsedDate = normalized; + dateLength = kDateLength; + } + + VerifyOrReturnError(dateLength >= kDateLength, CHIP_ERROR_INVALID_ARGUMENT); + + char field[5] = { 0 }; + memcpy(field, parsedDate, 4); + year = static_cast(strtoul(field, &parseEnd, 10)); + VerifyOrReturnError(parseEnd == field + 4, CHIP_ERROR_INVALID_ARGUMENT); + + memcpy(field, parsedDate + 4, 2); + field[2] = 0; + month = static_cast(strtoul(field, &parseEnd, 10)); + VerifyOrReturnError(parseEnd == field + 2, CHIP_ERROR_INVALID_ARGUMENT); + + memcpy(field, parsedDate + 6, 2); + field[2] = 0; + day = static_cast(strtoul(field, &parseEnd, 10)); + VerifyOrReturnError(parseEnd == field + 2, CHIP_ERROR_INVALID_ARGUMENT); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetManufacturingDateSuffix(MutableCharSpan & suffixBuffer) +{ + char date[kManufacturingDateBufferSize] = { 0 }; + size_t dateLength = 0; + ReturnErrorOnFailure(GetManufacturingDate(reinterpret_cast(date), sizeof(date), dateLength)); + + if (dateLength == 10 && date[4] == '-' && date[7] == '-') + { + suffixBuffer.reduce_size(0); + return CHIP_NO_ERROR; + } + + const size_t suffixLength = dateLength > 8 ? dateLength - 8 : 0; + VerifyOrReturnError(suffixLength <= suffixBuffer.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + if (suffixLength > 0) + { + memcpy(suffixBuffer.data(), date + 8, suffixLength); + } + suffixBuffer.reduce_size(suffixLength); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetRotatingDeviceIdUniqueId(MutableByteSpan & value) +{ + size_t size = 0; + CHIP_ERROR err = GetPersistentUniqueId(value.data(), value.size(), size); +#if defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + constexpr uint8_t uniqueId[] = CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID; + VerifyOrReturnError(sizeof(uniqueId) <= value.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(value.data(), uniqueId, sizeof(uniqueId)); + size = sizeof(uniqueId); + err = CHIP_NO_ERROR; + } +#endif + ReturnErrorOnFailure(err); + value.reduce_size(size); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetSetupPasscode(uint32_t & value) +{ +#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE) && CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE + value = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE; + return CHIP_NO_ERROR; +#else + (void) value; + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif +} + +CHIP_ERROR ProvisionStorageReader::SetSetupDiscriminator(uint16_t value) +{ + (void) value; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR ProvisionStorageReader::SetSetupPasscode(uint32_t value) +{ + (void) value; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR ProvisionStorageReader::GetSpake2pSalt(MutableByteSpan & value) +{ + char encoded[kSpake2pSaltB64BufferSize] = { 0 }; + size_t encodedSize = 0; + CHIP_ERROR err = GetSpake2pSalt(encoded, sizeof(encoded), encodedSize); +#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT) + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + encodedSize = strlen(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT); + VerifyOrReturnError(encodedSize <= sizeof(encoded), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(encoded, CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT, encodedSize); + err = CHIP_NO_ERROR; + } +#endif + ReturnErrorOnFailure(err); + + uint8_t decoded[kSpake2pSaltDecodedBufferSize] = { 0 }; + VerifyOrReturnError(BASE64_MAX_DECODED_LEN(encodedSize) <= kSpake2pSaltDecodedBufferSize, CHIP_ERROR_INVALID_ARGUMENT); + const size_t decodedSize = chip::Base64Decode32(encoded, static_cast(encodedSize), decoded); + VerifyOrReturnError(decodedSize >= chip::Crypto::kSpake2p_Min_PBKDF_Salt_Length && + decodedSize <= chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length, + CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(decodedSize <= value.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(value.data(), decoded, decodedSize); + value.reduce_size(decodedSize); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetSpake2pVerifier(MutableByteSpan & value, size_t & size) +{ + VerifyOrReturnError(value.size() >= chip::Crypto::kSpake2p_VerifierSerialized_Length, CHIP_ERROR_BUFFER_TOO_SMALL); + char encoded[kSpake2pVerifierB64BufferSize] = { 0 }; + size_t encodedSize = 0; + CHIP_ERROR err = GetSpake2pVerifier(encoded, sizeof(encoded), encodedSize); +#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER) + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + encodedSize = strlen(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER); + VerifyOrReturnError(encodedSize <= sizeof(encoded), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(encoded, CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER, encodedSize); + err = CHIP_NO_ERROR; + } +#endif + ReturnErrorOnFailure(err); + + uint8_t decoded[kSpake2pVerifierDecodedBufferSize] = { 0 }; + VerifyOrReturnError(BASE64_MAX_DECODED_LEN(encodedSize) <= kSpake2pVerifierDecodedBufferSize, CHIP_ERROR_INVALID_ARGUMENT); + size = chip::Base64Decode32(encoded, static_cast(encodedSize), decoded); + VerifyOrReturnError(size == chip::Crypto::kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(size <= value.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(value.data(), decoded, size); + value.reduce_size(size); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetSetupPayload(MutableCharSpan & value) +{ + uint8_t payload[Storage::kSetupPayloadSizeMax] = { 0 }; + size_t size = 0; + + // Setup bits + size_t prefix_len = strlen(kQRCodePrefix); + VerifyOrReturnError(value.size() > prefix_len, CHIP_ERROR_BUFFER_TOO_SMALL); + + CHIP_ERROR err = GetSetupPayload(payload, sizeof(payload), size); +#if SL_MATTER_QR_CODE_ENABLED || SILABS_LOG_ENABLED +#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE) && CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + PayloadContents payloadContents; + + // Configure PayloadContents + payloadContents.version = 0; + payloadContents.rendezvousInformation.SetValue(chip::RendezvousInformationFlag::kBLE); + payloadContents.setUpPINCode = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE; + + uint16_t discriminator = 0; + ReturnErrorOnFailure(GetSetupDiscriminator(discriminator)); + payloadContents.discriminator.SetLongValue(discriminator); + + ReturnErrorOnFailure(GetVendorId(payloadContents.vendorID)); + ReturnErrorOnFailure(GetProductId(payloadContents.productID)); + + // Generate Setup payload byte array + ReturnErrorOnFailure(QRCodeBasicSetupPayloadGenerator(payloadContents).payloadBase38Representation(value)); + + return CHIP_NO_ERROR; + } +#endif // defined(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE) && CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#endif // SL_MATTER_QR_CODE_ENABLED || SILABS_LOG_ENABLED + + ReturnErrorOnFailure(err); + VerifyOrReturnError(size > 0, CHIP_ERROR_NOT_FOUND); + char * data = value.data(); + // Prefix + memcpy(data, kQRCodePrefix, prefix_len); + // Base38 + MutableCharSpan qr_code(data + prefix_len, value.size() - prefix_len); + ReturnErrorOnFailure(base38Encode(ByteSpan(payload, size), qr_code)); + value.reduce_size(prefix_len + qr_code.size()); + return CHIP_NO_ERROR; +} + +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/ProvisionStorageWriter.h b/examples/platform/silabs/provision/ProvisionStorageWriter.h new file mode 100644 index 00000000000..81e93e71423 --- /dev/null +++ b/examples/platform/silabs/provision/ProvisionStorageWriter.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + * + * 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. + */ +#pragma once + +#include +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { + +/** + * Silicon Labs factory-data storage writer. + * + * The selected storage backend implements this class. Provisioning + * applications such as GFW consume this writable capability. + */ +class ProvisionStorageWriter final : public IProvisionStorageWriter +{ +public: + static ProvisionStorageWriter & GetInstance(); + + ProvisionStorageWriter(const ProvisionStorageWriter &) = delete; + ProvisionStorageWriter & operator=(const ProvisionStorageWriter &) = delete; + + CHIP_ERROR Initialize(uint32_t flash_addr = 0, uint32_t flash_size = 0) override; + CHIP_ERROR Commit() override; + CHIP_ERROR GetFlashPageSize(uint32_t & size) override; + + CHIP_ERROR SetSerialNumber(const char * value, size_t len) override; + CHIP_ERROR SetVendorId(uint16_t value) override; + CHIP_ERROR SetVendorName(const char * value, size_t len) override; + CHIP_ERROR SetProductId(uint16_t value) override; + CHIP_ERROR SetProductName(const char * value, size_t len) override; + CHIP_ERROR SetProductLabel(const char * value, size_t len) override; + CHIP_ERROR SetProductURL(const char * value, size_t len) override; + CHIP_ERROR SetPartNumber(const char * value, size_t len) override; + CHIP_ERROR SetHardwareVersion(uint16_t value) override; + CHIP_ERROR SetHardwareVersionString(const char * value, size_t len) override; + CHIP_ERROR SetManufacturingDate(const char * value, size_t len) override; + CHIP_ERROR SetPersistentUniqueId(const uint8_t * value, size_t size) override; + + CHIP_ERROR SetSetupDiscriminator(uint16_t value) override; + CHIP_ERROR SetSpake2pIterationCount(uint32_t value) override; + CHIP_ERROR SetSpake2pSalt(const char * value, size_t size) override; + CHIP_ERROR SetSpake2pVerifier(const char * value, size_t size) override; + CHIP_ERROR SetSetupPayload(const uint8_t * value, size_t size) override; + + CHIP_ERROR SetFirmwareInformation(const ByteSpan & value) override; + CHIP_ERROR SetCertificationDeclaration(const ByteSpan & value) override; + CHIP_ERROR SetProductAttestationIntermediateCert(const ByteSpan & value) override; + CHIP_ERROR SetDeviceAttestationCert(const ByteSpan & value) override; + + CHIP_ERROR SetProvisionVersion(const char * value, size_t len) override; + CHIP_ERROR SetTestEventTriggerKey(const ByteSpan & value) override; + CHIP_ERROR SetOtaTlvEncryptionKey(const ByteSpan & value) override; + + // Provisioning/platform lifecycle controls. + CHIP_ERROR SetCredentialsBaseAddress(uint32_t addr) override; + CHIP_ERROR SetProvisionRequest(bool value) override; + CHIP_ERROR GetCredentialsBaseAddress(uint32_t & addr) override; + CHIP_ERROR GetProvisionRequest(bool & value) override; + +private: + ProvisionStorageWriter() = default; +}; + +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/ProvisionStorageZephyr.cpp b/examples/platform/silabs/provision/ProvisionStorageZephyr.cpp deleted file mode 100644 index 43ea0d40c38..00000000000 --- a/examples/platform/silabs/provision/ProvisionStorageZephyr.cpp +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Copyright (c) 2026 Project CHIP Authors - * All rights reserved. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if SL_PROVISION_GENERATOR -#include -#endif - -#include -#include - -namespace chip { -namespace DeviceLayer { -namespace Silabs { -namespace Provision { - -namespace { - -using chip::DeviceLayer::Internal::ZephyrConfig; - -#define CONFIG_KEY(key) \ - (key); \ - static_assert(sizeof(key) <= SETTINGS_MAX_NAME_LEN, "Config key too long: " key) - -#define NAMESPACE_SL_FACTORY CHIP_DEVICE_CONFIG_SETTINGS_KEY "-sl-fct/" - -const ZephyrConfig::Key kConfigKey_VendorId = CONFIG_KEY(NAMESPACE_SL_FACTORY "vendor-id"); -const ZephyrConfig::Key kConfigKey_ProductId = CONFIG_KEY(NAMESPACE_SL_FACTORY "product-id"); -const ZephyrConfig::Key kConfigKey_VendorName = CONFIG_KEY(NAMESPACE_SL_FACTORY "vendor-name"); -const ZephyrConfig::Key kConfigKey_ProductName = CONFIG_KEY(NAMESPACE_SL_FACTORY "product-name"); -const ZephyrConfig::Key kConfigKey_ProductLabel = CONFIG_KEY(NAMESPACE_SL_FACTORY "product-label"); -const ZephyrConfig::Key kConfigKey_ProductUrl = CONFIG_KEY(NAMESPACE_SL_FACTORY "product-url"); -const ZephyrConfig::Key kConfigKey_PartNumber = CONFIG_KEY(NAMESPACE_SL_FACTORY "part-number"); -const ZephyrConfig::Key kConfigKey_HardwareVersionString = CONFIG_KEY(NAMESPACE_SL_FACTORY "hardware-ver-str"); -const ZephyrConfig::Key kConfigKey_SetupPayload = CONFIG_KEY(NAMESPACE_SL_FACTORY "setup-payload"); - -constexpr psa_key_id_t kDacPsaKeyId = 2; - -static constexpr ZephyrConfig::Key kProvisionRequestKey = CONFIG_KEY(NAMESPACE_SL_FACTORY "provision-req"); -static constexpr ZephyrConfig::Key kProvisionVersionKey = CONFIG_KEY(NAMESPACE_SL_FACTORY "provision-ver"); - -CHIP_ERROR ReadConfigBin(ZephyrConfig::Key key, MutableByteSpan & buffer) -{ - size_t dataLen = 0; - ReturnErrorOnFailure(ZephyrConfig::ReadConfigValueBin(key, buffer.data(), buffer.size(), dataLen)); - buffer.reduce_size(dataLen); - return CHIP_NO_ERROR; -} - -bool DacPsaKeyExists() -{ - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - const psa_status_t status = psa_get_key_attributes(kDacPsaKeyId, &attributes); - psa_reset_key_attributes(&attributes); - return status == PSA_SUCCESS; -} - -bool sInitialized = false; - -} // namespace - -CHIP_ERROR Storage::Initialize(uint32_t flash_addr, uint32_t flash_size) -{ -#if SL_PROVISION_GENERATOR - // flash_addr is the offset to the start of the storage area, and flash_size is the total size of the storage area. - VerifyOrReturnError(settings_nvs_set_runtime_geometry(static_cast(flash_addr), flash_size) == 0, - CHIP_ERROR_PERSISTED_STORAGE_FAILED); - ReturnErrorOnFailure(ZephyrConfig::Init()); -#else - (void) flash_addr; - (void) flash_size; - ReturnErrorOnFailure(ZephyrConfig::Init()); - VerifyOrDo(DacPsaKeyExists(), ChipLogError(DeviceLayer, "DAC PSA key id %u missing", kDacPsaKeyId)); -#endif // SL_PROVISION_GENERATOR - sInitialized = true; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::Commit() -{ - // Zephyr settings writes are immediate - return CHIP_NO_ERROR; -} - -// -// DeviceInstanceInfoProvider -// - -CHIP_ERROR Storage::SetSerialNumber(const char * value, size_t len) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::WriteConfigValueStr(ZephyrConfig::kConfigKey_SerialNum, value, len); -} - -CHIP_ERROR Storage::GetSerialNumber(char * value, size_t max) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - size_t size = 0; - return ZephyrConfig::ReadConfigValueStr(ZephyrConfig::kConfigKey_SerialNum, value, max, size); -} - -CHIP_ERROR Storage::SetVendorId(uint16_t value) -{ - return ZephyrConfig::WriteConfigValue(kConfigKey_VendorId, static_cast(value)); -} - -CHIP_ERROR Storage::GetVendorId(uint16_t & value) -{ - uint32_t stored = 0; - ReturnErrorOnFailure(ZephyrConfig::ReadConfigValue(kConfigKey_VendorId, stored)); - value = static_cast(stored); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetVendorName(const char * value, size_t len) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::WriteConfigValueStr(kConfigKey_VendorName, value, len); -} - -CHIP_ERROR Storage::GetVendorName(char * value, size_t max) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - size_t name_len = 0; - - return ZephyrConfig::ReadConfigValueStr(kConfigKey_VendorName, value, max, name_len); -} - -CHIP_ERROR Storage::SetProductId(uint16_t value) -{ - return ZephyrConfig::WriteConfigValue(kConfigKey_ProductId, static_cast(value)); -} - -CHIP_ERROR Storage::GetProductId(uint16_t & value) -{ - uint32_t stored = 0; - ReturnErrorOnFailure(ZephyrConfig::ReadConfigValue(kConfigKey_ProductId, stored)); - value = static_cast(stored); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetProductName(const char * value, size_t len) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::WriteConfigValueStr(kConfigKey_ProductName, value, len); -} - -CHIP_ERROR Storage::GetProductName(char * value, size_t max) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - size_t size = 0; - - return ZephyrConfig::ReadConfigValueStr(kConfigKey_ProductName, value, max, size); -} - -CHIP_ERROR Storage::SetProductLabel(const char * value, size_t len) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::WriteConfigValueStr(kConfigKey_ProductLabel, value, len); -} - -CHIP_ERROR Storage::GetProductLabel(char * value, size_t max) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - size_t size = 0; - return ZephyrConfig::ReadConfigValueStr(kConfigKey_ProductLabel, value, max, size); -} - -CHIP_ERROR Storage::SetProductURL(const char * value, size_t len) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::WriteConfigValueStr(kConfigKey_ProductUrl, value, len); -} - -CHIP_ERROR Storage::GetProductURL(char * value, size_t max) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - size_t size = 0; - return ZephyrConfig::ReadConfigValueStr(kConfigKey_ProductUrl, value, max, size); -} - -CHIP_ERROR Storage::SetPartNumber(const char * value, size_t len) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::WriteConfigValueStr(kConfigKey_PartNumber, value, len); -} - -CHIP_ERROR Storage::GetPartNumber(char * value, size_t max) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - size_t size = 0; - return ZephyrConfig::ReadConfigValueStr(kConfigKey_PartNumber, value, max, size); -} - -CHIP_ERROR Storage::SetHardwareVersion(uint16_t value) -{ - return ZephyrConfig::WriteConfigValue(ZephyrConfig::kConfigKey_HardwareVersion, static_cast(value)); -} - -CHIP_ERROR Storage::GetHardwareVersion(uint16_t & value) -{ - uint32_t stored = 0; - ReturnErrorOnFailure(ZephyrConfig::ReadConfigValue(ZephyrConfig::kConfigKey_HardwareVersion, stored)); - value = static_cast(stored); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetHardwareVersionString(const char * value, size_t len) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::WriteConfigValueStr(kConfigKey_HardwareVersionString, value, len); -} - -CHIP_ERROR Storage::GetHardwareVersionString(char * value, size_t max) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - size_t size = 0; - return ZephyrConfig::ReadConfigValueStr(kConfigKey_HardwareVersionString, value, max, size); -} - -CHIP_ERROR Storage::SetManufacturingDate(const char * value, size_t len) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::WriteConfigValueStr(ZephyrConfig::kConfigKey_ManufacturingDate, value, len); -} - -CHIP_ERROR Storage::GetManufacturingDate(uint8_t * value, size_t max, size_t & size) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::ReadConfigValueStr(ZephyrConfig::kConfigKey_ManufacturingDate, reinterpret_cast(value), max, size); -} - -CHIP_ERROR Storage::SetPersistentUniqueId(const uint8_t * value, size_t size) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::WriteConfigValueBin(ZephyrConfig::kConfigKey_UniqueId, value, size); -} - -CHIP_ERROR Storage::GetPersistentUniqueId(uint8_t * value, size_t max, size_t & size) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::ReadConfigValueBin(ZephyrConfig::kConfigKey_UniqueId, value, max, size); -} - -// -// CommissionableDataProvider -// - -CHIP_ERROR Storage::SetSetupDiscriminator(uint16_t value) -{ - return ZephyrConfig::WriteConfigValue(ZephyrConfig::kConfigKey_SetupDiscriminator, static_cast(value)); -} - -CHIP_ERROR Storage::GetSetupDiscriminator(uint16_t & value) -{ - uint32_t stored = 0; - ReturnErrorOnFailure(ZephyrConfig::ReadConfigValue(ZephyrConfig::kConfigKey_SetupDiscriminator, stored)); - value = static_cast(stored); - VerifyOrReturnLogError(value <= kMaxDiscriminatorValue, CHIP_ERROR_INVALID_ARGUMENT); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetSpake2pIterationCount(uint32_t value) -{ - return ZephyrConfig::WriteConfigValue(ZephyrConfig::kConfigKey_Spake2pIterationCount, value); -} - -CHIP_ERROR Storage::GetSpake2pIterationCount(uint32_t & value) -{ - return ZephyrConfig::ReadConfigValue(ZephyrConfig::kConfigKey_Spake2pIterationCount, value); -} - -CHIP_ERROR Storage::SetSetupPasscode(uint32_t value) -{ - (void) value; - return CHIP_ERROR_NOT_IMPLEMENTED; -} - -CHIP_ERROR Storage::GetSetupPasscode(uint32_t & value) -{ - (void) value; - return CHIP_ERROR_NOT_IMPLEMENTED; -} - -CHIP_ERROR Storage::SetSpake2pSalt(const char * value, size_t size) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::WriteConfigValueStr(ZephyrConfig::kConfigKey_Spake2pSalt, value, size); -} - -CHIP_ERROR Storage::GetSpake2pSalt(char * value, size_t max, size_t & size) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::ReadConfigValueStr(ZephyrConfig::kConfigKey_Spake2pSalt, value, max, size); -} - -CHIP_ERROR Storage::SetSpake2pVerifier(const char * value, size_t size) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::WriteConfigValueStr(ZephyrConfig::kConfigKey_Spake2pVerifier, value, size); -} - -CHIP_ERROR Storage::GetSpake2pVerifier(char * value, size_t max, size_t & size) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::ReadConfigValueStr(ZephyrConfig::kConfigKey_Spake2pVerifier, value, max, size); -} - -// -// DeviceAttestationCredentialsProvider -// - -CHIP_ERROR Storage::SetFirmwareInformation(const ByteSpan & value) -{ - (void) value; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::GetFirmwareInformation(MutableByteSpan & value) -{ - value.reduce_size(0); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetCertificationDeclaration(const ByteSpan & value) -{ - return ZephyrConfig::WriteConfigValueBin(ZephyrConfig::kConfigKey_CertificationDeclaration, value.data(), value.size()); -} - -CHIP_ERROR Storage::GetCertificationDeclaration(MutableByteSpan & value) -{ - return ReadConfigBin(ZephyrConfig::kConfigKey_CertificationDeclaration, value); -} - -CHIP_ERROR Storage::SetProductAttestationIntermediateCert(const ByteSpan & value) -{ - return ZephyrConfig::WriteConfigValueBin(ZephyrConfig::kConfigKey_MfrDeviceICACerts, value.data(), value.size()); -} - -CHIP_ERROR Storage::GetProductAttestationIntermediateCert(MutableByteSpan & value) -{ - return ReadConfigBin(ZephyrConfig::kConfigKey_MfrDeviceICACerts, value); -} - -CHIP_ERROR Storage::SetDeviceAttestationCert(const ByteSpan & value) -{ - return ZephyrConfig::WriteConfigValueBin(ZephyrConfig::kConfigKey_MfrDeviceCert, value.data(), value.size()); -} - -CHIP_ERROR Storage::GetDeviceAttestationCert(MutableByteSpan & value) -{ - return ReadConfigBin(ZephyrConfig::kConfigKey_MfrDeviceCert, value); -} - -CHIP_ERROR Storage::SetDeviceAttestationKey(const ByteSpan & value) -{ - AttestationKey key; - ReturnErrorOnFailure(key.Import(value.data(), value.size())); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::GetDeviceAttestationCSR(uint16_t vid, uint16_t pid, const CharSpan & cn, MutableCharSpan & csr) -{ - AttestationKey key; - ReturnErrorOnFailure(key.GenerateCSR(vid, pid, cn, csr)); - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SignWithDeviceAttestationKey(const ByteSpan & message, MutableByteSpan & signature) -{ - VerifyOrReturnError(DacPsaKeyExists(), CHIP_ERROR_NOT_FOUND, - ChipLogError(DeviceLayer, "DAC PSA key id %u missing", kDacPsaKeyId)); - - Crypto::P256ECDSASignature rawSignature; - VerifyOrReturnError(signature.size() >= rawSignature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); - - size_t outputLen = 0; - const psa_status_t status = psa_sign_message(kDacPsaKeyId, PSA_ALG_ECDSA(PSA_ALG_SHA_256), message.data(), message.size(), - rawSignature.Bytes(), rawSignature.Capacity(), &outputLen); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL, - ChipLogError(DeviceLayer, "psa_sign_message failed: %" PRId32, status)); - VerifyOrReturnError(outputLen == Crypto::kP256_ECDSA_Signature_Length_Raw, CHIP_ERROR_INTERNAL); - - ReturnErrorOnFailure(rawSignature.SetLength(outputLen)); - return CopySpanToMutableSpan(ByteSpan{ rawSignature.ConstBytes(), rawSignature.Length() }, signature); -} - -CHIP_ERROR Storage::SetCredentialsBaseAddress(uint32_t addr) -{ - (void) addr; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::GetCredentialsBaseAddress(uint32_t & addr) -{ - addr = 0; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetProvisionVersion(const char * value, size_t size) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::WriteConfigValueStr(kProvisionVersionKey, value, size); -} - -CHIP_ERROR Storage::GetProvisionVersion(char * value, size_t max, size_t & size) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::ReadConfigValueStr(kProvisionVersionKey, value, max, size); -} - -CHIP_ERROR Storage::SetSetupPayload(const uint8_t * value, size_t size) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::WriteConfigValueBin(kConfigKey_SetupPayload, value, size); -} - -CHIP_ERROR Storage::GetSetupPayload(uint8_t * value, size_t max, size_t & size) -{ - VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - return ZephyrConfig::ReadConfigValueBin(kConfigKey_SetupPayload, value, max, size); -} - -CHIP_ERROR Storage::SetProvisionRequest(bool value) -{ - return sInitialized ? ZephyrConfig::WriteConfigValue(kProvisionRequestKey, static_cast(value ? 1 : 0)) - : CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::GetProvisionRequest(bool & value) -{ - if (!sInitialized) - { - // Generator firmware hasn't initialized the NVS yet, so assume provisioning is required. - value = true; - return CHIP_NO_ERROR; - } - uint32_t stored = 0; - ReturnErrorOnFailure(ZephyrConfig::ReadConfigValue(kProvisionRequestKey, stored)); - value = stored != 0; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::SetOtaTlvEncryptionKey(const ByteSpan & value) -{ - (void) value; - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -} - -CHIP_ERROR Storage::GetOtaTlvEncryptionKeyId(uint32_t & keyId) -{ - (void) keyId; - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -} - -CHIP_ERROR Storage::DecryptUsingOtaTlvEncryptionKey(MutableByteSpan & block, uint32_t & ivOffset) -{ - (void) block; - (void) ivOffset; - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -} - -CHIP_ERROR Storage::SetTestEventTriggerKey(const ByteSpan & value) -{ - (void) value; - return CHIP_NO_ERROR; -} - -CHIP_ERROR Storage::GetTestEventTriggerKey(MutableByteSpan & keySpan) -{ - (void) keySpan; - return CHIP_ERROR_NOT_IMPLEMENTED; -} - -// ProvisionStorage functions for Zephyr settings backend, provided by provision libraries for other ProvisionStorage backends. -#if !SL_PROVISION_GENERATOR - -CHIP_ERROR Storage::Set(uint16_t id, const uint8_t * value) -{ - (void) id; - (void) value; - return CHIP_ERROR_UNKNOWN_RESOURCE_ID; -} - -CHIP_ERROR Storage::Get(uint16_t id, uint8_t & value) -{ - (void) id; - (void) value; - return CHIP_ERROR_UNKNOWN_RESOURCE_ID; -} - -CHIP_ERROR Storage::Set(uint16_t id, const uint16_t * value) -{ - (void) id; - (void) value; - return CHIP_ERROR_UNKNOWN_RESOURCE_ID; -} - -CHIP_ERROR Storage::Get(uint16_t id, uint16_t & value) -{ - (void) id; - (void) value; - return CHIP_ERROR_UNKNOWN_RESOURCE_ID; -} - -CHIP_ERROR Storage::Set(uint16_t id, const uint32_t * value) -{ - (void) id; - (void) value; - return CHIP_ERROR_UNKNOWN_RESOURCE_ID; -} - -CHIP_ERROR Storage::Get(uint16_t id, uint32_t & value) -{ - (void) id; - (void) value; - return CHIP_ERROR_UNKNOWN_RESOURCE_ID; -} - -CHIP_ERROR Storage::Set(uint16_t id, const uint64_t * value) -{ - (void) id; - (void) value; - return CHIP_ERROR_UNKNOWN_RESOURCE_ID; -} - -CHIP_ERROR Storage::Get(uint16_t id, uint64_t & value) -{ - (void) id; - (void) value; - return CHIP_ERROR_UNKNOWN_RESOURCE_ID; -} - -CHIP_ERROR Storage::Get(uint16_t id, uint8_t * value, size_t max_size, size_t & size) -{ - (void) id; - (void) value; - (void) max_size; - (void) size; - return CHIP_ERROR_UNKNOWN_RESOURCE_ID; -} - -CHIP_ERROR Storage::Set(uint16_t id, const uint8_t * value, size_t size) -{ - (void) id; - (void) value; - (void) size; - return CHIP_ERROR_UNKNOWN_RESOURCE_ID; -} - -#endif // !SL_PROVISION_GENERATOR - -} // namespace Provision -} // namespace Silabs -} // namespace DeviceLayer -} // namespace chip diff --git a/examples/platform/silabs/provision/default/ProvisionStorageReader.cpp b/examples/platform/silabs/provision/default/ProvisionStorageReader.cpp new file mode 100644 index 00000000000..e94e4b5cf70 --- /dev/null +++ b/examples/platform/silabs/provision/default/ProvisionStorageReader.cpp @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2024-2026 Project CHIP Authors + * All rights reserved. + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION +#include +#endif // SL_MATTER_ENABLE_OTA_ENCRYPTION && SL_MATTER_ENABLE_OTA_ENCRYPTION + +#if !SL_MATTER_GN_BUILD +#include + +#ifndef NDEBUG +#if defined(SL_MATTER_TEST_EVENT_TRIGGER_ENABLED) +#include +#endif // defined(SL_MATTER_TEST_EVENT_TRIGGER_ENABLED) +#endif // NDEBUG +#endif // !SL_MATTER_GN_BUILD + +#include + +using SilabsConfig = chip::DeviceLayer::Internal::SilabsConfig; + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { + +ProvisionStorageReader & ProvisionStorageReader::GetInstance() +{ + static ProvisionStorageReader instance; + return instance; +} + +namespace { + +CHIP_ERROR ReadFileByOffset(const char * description, uint32_t offset, uint32_t size, MutableByteSpan & value) +{ + uint32_t base_addr = 0; + ReturnErrorOnFailure(SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_Creds_Base_Addr, base_addr)); + + uint8_t * address = reinterpret_cast(static_cast(base_addr + offset)); + ByteSpan span(address, size); + ChipLogProgress(DeviceLayer, "%s, addr:0x%06x+%03u, size:%u", description, (unsigned) base_addr, (unsigned) offset, + (unsigned) size); + return CopySpanToMutableSpan(span, value); +} + +CHIP_ERROR ReadFileByKey(const char * description, uint32_t offset_key, uint32_t size_key, MutableByteSpan & value) +{ + uint32_t offset = 0; + uint32_t size = 0; + + // Offset + VerifyOrReturnError(SilabsConfig::ConfigValueExists(offset_key), CHIP_ERROR_NOT_FOUND); + ReturnErrorOnFailure(SilabsConfig::ReadConfigValue(offset_key, offset)); + + // Size + VerifyOrReturnError(SilabsConfig::ConfigValueExists(size_key), CHIP_ERROR_NOT_FOUND); + ReturnErrorOnFailure(SilabsConfig::ReadConfigValue(size_key, size)); + + return ReadFileByOffset(description, offset, size, value); +} + +} // namespace + +// +// DeviceInstanceInfoProvider +// + +CHIP_ERROR ProvisionStorageReader::GetSerialNumber(char * value, size_t max) +{ + size_t size = 0; + return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_SerialNum, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetVendorId(uint16_t & value) +{ + CHIP_ERROR err = SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_VendorId, value); +#if defined(CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID) && CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + value = CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID; + err = CHIP_NO_ERROR; + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetVendorName(char * value, size_t max) +{ + size_t name_len = 0; // Without counting null-terminator + + CHIP_ERROR err = SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_VendorName, value, max, name_len); +#if defined(CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME) + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + VerifyOrReturnError(value != nullptr, CHIP_ERROR_NO_MEMORY); + VerifyOrReturnError(max > strlen(CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME), CHIP_ERROR_BUFFER_TOO_SMALL); + Platform::CopyString(value, max, CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME); + err = CHIP_NO_ERROR; + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetProductId(uint16_t & value) +{ + CHIP_ERROR err = SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_ProductId, value); + +#if defined(CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID) && CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + value = CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID; + err = CHIP_NO_ERROR; + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetProductName(char * value, size_t max) +{ + size_t name_len = 0; // Without counting null-terminator + + CHIP_ERROR err = SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_ProductName, value, max, name_len); +#if defined(CHIP_DEVICE_CONFIG_TEST_PRODUCT_NAME) + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + VerifyOrReturnError(value != nullptr, CHIP_ERROR_NO_MEMORY); + VerifyOrReturnError(max > strlen(CHIP_DEVICE_CONFIG_TEST_PRODUCT_NAME), CHIP_ERROR_BUFFER_TOO_SMALL); + Platform::CopyString(value, max, CHIP_DEVICE_CONFIG_TEST_PRODUCT_NAME); + err = CHIP_NO_ERROR; + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetProductLabel(char * value, size_t max) +{ + size_t size = 0; + return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_ProductLabel, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetProductURL(char * value, size_t max) +{ + size_t size = 0; + return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_ProductURL, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetPartNumber(char * value, size_t max) +{ + size_t size = 0; + return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_PartNumber, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetHardwareVersion(uint16_t & value) +{ + CHIP_ERROR err = SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_HardwareVersion, value); +#if defined(CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION) + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + value = CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION; + err = CHIP_NO_ERROR; + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetHardwareVersionString(char * value, size_t max) +{ + size_t hw_version_len = 0; // Without counting null-terminator + + CHIP_ERROR err = SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_HardwareVersionString, value, max, hw_version_len); +#if defined(CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING) + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + VerifyOrReturnError(value != nullptr, CHIP_ERROR_NO_MEMORY); + VerifyOrReturnError(max > strlen(CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING), CHIP_ERROR_BUFFER_TOO_SMALL); + Platform::CopyString(value, max, CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING); + err = CHIP_NO_ERROR; + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetManufacturingDate(uint8_t * value, size_t max, size_t & size) +{ + return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_ManufacturingDate, (char *) value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetPersistentUniqueId(uint8_t * value, size_t max, size_t & size) +{ + return SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_PersistentUniqueId, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetSetupDiscriminator(uint16_t & value) +{ + CHIP_ERROR err = SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_SetupDiscriminator, value); +#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR) && CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + value = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR; + err = CHIP_NO_ERROR; + } +#endif + ReturnErrorOnFailure(err); + VerifyOrReturnLogError(value <= kMaxDiscriminatorValue, CHIP_ERROR_INVALID_ARGUMENT); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetSpake2pIterationCount(uint32_t & value) +{ + CHIP_ERROR err = SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_Spake2pIterationCount, value); +#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT) && CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + value = CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT; + err = CHIP_NO_ERROR; + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetSpake2pSalt(char * value, size_t max, size_t & size) +{ + return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_Spake2pSalt, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetSpake2pVerifier(char * value, size_t max, size_t & size) +{ + return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_Spake2pVerifier, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetFirmwareInformation(MutableByteSpan & value) +{ + // TODO: We need a real example FirmwareInformation to be populated. + value.reduce_size(0); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetCertificationDeclaration(MutableByteSpan & value) +{ + CHIP_ERROR err = ReadFileByKey("GetCertificationDeclaration", SilabsConfig::kConfigKey_Creds_CD_Offset, + SilabsConfig::kConfigKey_Creds_CD_Size, value); +#if defined(SL_PROVISION_VERSION_1_0) && SL_PROVISION_VERSION_1_0 + if (CHIP_ERROR_NOT_FOUND == err) + { + // Reading from the old script's location. + err = ReadFileByOffset("GetCertificationDeclaration", SL_CREDENTIALS_CD_OFFSET, SL_CREDENTIALS_CD_SIZE, value); + } +#endif +#if SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS + if (CHIP_ERROR_NOT_FOUND == err) + { + err = chip::Credentials::Examples::GetExampleDACProvider()->GetCertificationDeclaration(value); + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetProductAttestationIntermediateCert(MutableByteSpan & value) +{ + CHIP_ERROR err = ReadFileByKey("GetProductAttestationIntermediateCert", SilabsConfig::kConfigKey_Creds_PAI_Offset, + SilabsConfig::kConfigKey_Creds_PAI_Size, value); +#if defined(SL_PROVISION_VERSION_1_0) && SL_PROVISION_VERSION_1_0 + if (CHIP_ERROR_NOT_FOUND == err) + { + // Reading from the old script's location. + err = ReadFileByOffset("GetProductAttestationIntermediateCert", SL_CREDENTIALS_PAI_OFFSET, SL_CREDENTIALS_PAI_SIZE, value); + } +#endif +#if SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS + if (CHIP_ERROR_NOT_FOUND == err) + { + err = chip::Credentials::Examples::GetExampleDACProvider()->GetProductAttestationIntermediateCert(value); + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetDeviceAttestationCert(MutableByteSpan & value) +{ + CHIP_ERROR err = ReadFileByKey("GetDeviceAttestationCert", SilabsConfig::kConfigKey_Creds_DAC_Offset, + SilabsConfig::kConfigKey_Creds_DAC_Size, value); +#if defined(SL_PROVISION_VERSION_1_0) && SL_PROVISION_VERSION_1_0 + if (CHIP_ERROR_NOT_FOUND == err) + { + // Reading from the old script's location. + err = ReadFileByOffset("GetDeviceAttestationCert", SL_CREDENTIALS_DAC_OFFSET, SL_CREDENTIALS_DAC_SIZE, value); + } +#endif +#if SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS + if (CHIP_ERROR_NOT_FOUND == err) + { + return chip::Credentials::Examples::GetExampleDACProvider()->GetDeviceAttestationCert(value); + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetProvisionVersion(char * value, size_t max, size_t & size) +{ + return SilabsConfig::ReadConfigValueStr(SilabsConfig::kConfigKey_Provision_Version, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetSetupPayload(uint8_t * value, size_t max, size_t & size) +{ + return SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_SetupPayloadBitSet, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::SignWithDeviceAttestationKey(const ByteSpan & message, MutableByteSpan & signature) +{ + CHIP_ERROR error = ProvisionCrypto::GetInstance().SignWithDeviceAttestationKey(message, signature); +#if SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS + if (error == CHIP_ERROR_NOT_FOUND || error == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + return chip::Credentials::Examples::GetExampleDACProvider()->SignWithDeviceAttestationKey(message, signature); + } +#endif + return error; +} + +CHIP_ERROR ProvisionStorageReader::GetTestEventTriggerKey(MutableByteSpan & keySpan) +{ +#ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLED + constexpr size_t kEnableKeyLength = 16; + size_t keyLength = 0; + VerifyOrReturnError(keySpan.size() >= kEnableKeyLength, CHIP_ERROR_BUFFER_TOO_SMALL); + CHIP_ERROR err = SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_Test_Event_Trigger_Key, keySpan.data(), + kEnableKeyLength, keyLength); +#ifndef NDEBUG +#ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLE_KEY + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + constexpr char enableKey[] = SL_MATTER_TEST_EVENT_TRIGGER_ENABLE_KEY; + VerifyOrReturnError(Encoding::HexToBytes(enableKey, strlen(enableKey), keySpan.data(), kEnableKeyLength) == + kEnableKeyLength, + CHIP_ERROR_INTERNAL); + err = CHIP_NO_ERROR; + } +#endif +#endif + ReturnErrorOnFailure(err); + keySpan.reduce_size(kEnableKeyLength); + return CHIP_NO_ERROR; +#else + (void) keySpan; + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif +} + +CHIP_ERROR ProvisionStorageReader::GetOtaTlvEncryptionKeyId(uint32_t & value) +{ +#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION && !defined(SL_MBEDTLS_USE_TINYCRYPT) + return SilabsConfig::ReadConfigValue(SilabsConfig::kOtaTlvEncryption_KeyId, value); +#else + (void) value; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif +} + +CHIP_ERROR ProvisionStorageReader::DecryptUsingOtaTlvEncryptionKey(MutableByteSpan & block, uint32_t & ivOffset) +{ +#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION && defined(SL_MBEDTLS_USE_TINYCRYPT) && \ + SL_MBEDTLS_USE_TINYCRYPT + uint8_t keyBuffer[Silabs::OtaTlvEncryptionKey::kOTAEncryptionKeyLength] = { 0 }; + size_t keyLength = 0; + ReturnErrorOnFailure( + SilabsConfig::ReadConfigValueBin(SilabsConfig::kOtaTlvEncryption_KeyId, keyBuffer, sizeof(keyBuffer), keyLength)); + VerifyOrReturnError(keyLength == sizeof(keyBuffer), CHIP_ERROR_INVALID_ARGUMENT); + return Silabs::OtaTlvEncryptionKey::Decrypt(ByteSpan(keyBuffer), block, ivOffset); +#else + (void) block; + (void) ivOffset; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif +} + +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/default/ProvisionStorageWriter.cpp b/examples/platform/silabs/provision/default/ProvisionStorageWriter.cpp new file mode 100644 index 00000000000..774e0896bbc --- /dev/null +++ b/examples/platform/silabs/provision/default/ProvisionStorageWriter.cpp @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2024-2026 Project CHIP Authors + * All rights reserved. + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION +#include +#endif + +using SilabsConfig = chip::DeviceLayer::Internal::SilabsConfig; + +#if defined(SL_PROVISION_GENERATOR) && SL_PROVISION_GENERATOR +extern void setNvm3End(uint32_t addr); +#endif // SL_PROVISION_GENERATOR +extern uint8_t linker_nvm_end[]; +#ifdef _SILICON_LABS_32B_SERIES_3 +extern uint8_t linker_static_secure_tokens_begin; +#endif + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { + +ProvisionStorageWriter & ProvisionStorageWriter::GetInstance() +{ + static ProvisionStorageWriter instance; + return instance; +} + +namespace { +size_t sCredentialsOffset = 0; + +CHIP_ERROR ErasePage(uint32_t addr) +{ + return chip::DeviceLayer::Silabs::GetPlatform().FlashErasePage(addr); +} + +size_t RoundNearest(size_t n, size_t multiple) +{ + return (n % multiple) > 0 ? n + (multiple - n % multiple) : n; +} + +/** + * Writes "size" bytes to the flash page. The data is padded with 0xff + * up to the nearest 32-bit boundary. + */ +CHIP_ERROR WritePage(uint32_t addr, const uint8_t * data, size_t size) +{ + // The flash driver fails if the size is not a multiple of 4 (32-bits) + size_t size_32 = RoundNearest(size, 4); + if (size_32 == size) + { + return chip::DeviceLayer::Silabs::GetPlatform().FlashWritePage(addr, data, size); + } + + // Create a temporary buffer, and pad it with "0xff" + uint8_t * p = static_cast(chip::Platform::MemoryAlloc(size_32)); + VerifyOrReturnError(p != nullptr, CHIP_ERROR_INTERNAL); + memcpy(p, data, size); + memset(p + size, 0xff, size_32 - size); + CHIP_ERROR err = chip::DeviceLayer::Silabs::GetPlatform().FlashWritePage(addr, p, size_32); + chip::Platform::MemoryFree(p); + return err; +} + +CHIP_ERROR WriteFile(ProvisionStorageWriter & store, size_t & credentialsOffset, SilabsConfig::Key offset_key, + SilabsConfig::Key size_key, const ByteSpan & value) +{ + uint32_t base_addr = 0; + ReturnErrorOnFailure(store.GetCredentialsBaseAddress(base_addr)); + if (0 == credentialsOffset) + { + ReturnErrorOnFailure(ErasePage(base_addr)); + } + + ReturnErrorOnFailure(WritePage(base_addr + credentialsOffset, value.data(), value.size())); + + // Store file offset + ReturnErrorOnFailure(SilabsConfig::WriteConfigValue(offset_key, (uint32_t) credentialsOffset)); + // Store file size + ReturnErrorOnFailure(SilabsConfig::WriteConfigValue(size_key, (uint32_t) value.size())); + // Calculate offset for the next file + credentialsOffset = RoundNearest(credentialsOffset + value.size(), 64); + return CHIP_NO_ERROR; +} + +} // namespace + +// +// DeviceInstanceInfoProvider +// + +CHIP_ERROR ProvisionStorageWriter::SetSerialNumber(const char * value, size_t len) +{ + return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_SerialNum, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetVendorId(uint16_t value) +{ + return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_VendorId, value); +} + +CHIP_ERROR ProvisionStorageWriter::SetVendorName(const char * value, size_t len) +{ + return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_VendorName, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductId(uint16_t value) +{ + return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_ProductId, value); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductName(const char * value, size_t len) +{ + return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_ProductName, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductLabel(const char * value, size_t len) +{ + return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_ProductLabel, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductURL(const char * value, size_t len) +{ + return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_ProductURL, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetPartNumber(const char * value, size_t len) +{ + return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_PartNumber, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetHardwareVersion(uint16_t value) +{ + return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_HardwareVersion, value); +} + +CHIP_ERROR ProvisionStorageWriter::SetHardwareVersionString(const char * value, size_t len) +{ + return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_HardwareVersionString, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetManufacturingDate(const char * value, size_t len) +{ + return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_ManufacturingDate, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetPersistentUniqueId(const uint8_t * value, size_t size) +{ + return SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_PersistentUniqueId, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetSetupDiscriminator(uint16_t value) +{ + return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_SetupDiscriminator, value); +} + +CHIP_ERROR ProvisionStorageWriter::SetSpake2pIterationCount(uint32_t value) +{ + return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_Spake2pIterationCount, value); +} + +CHIP_ERROR ProvisionStorageWriter::SetSpake2pSalt(const char * value, size_t size) +{ + return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_Spake2pSalt, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetSpake2pVerifier(const char * value, size_t size) +{ + return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_Spake2pVerifier, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetFirmwareInformation(const ByteSpan & value) +{ + (void) value; + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageWriter::SetCertificationDeclaration(const ByteSpan & value) +{ + return WriteFile(*this, sCredentialsOffset, SilabsConfig::kConfigKey_Creds_CD_Offset, SilabsConfig::kConfigKey_Creds_CD_Size, + value); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductAttestationIntermediateCert(const ByteSpan & value) +{ + return WriteFile(*this, sCredentialsOffset, SilabsConfig::kConfigKey_Creds_PAI_Offset, SilabsConfig::kConfigKey_Creds_PAI_Size, + value); +} + +CHIP_ERROR ProvisionStorageWriter::SetDeviceAttestationCert(const ByteSpan & value) +{ + return WriteFile(*this, sCredentialsOffset, SilabsConfig::kConfigKey_Creds_DAC_Offset, SilabsConfig::kConfigKey_Creds_DAC_Size, + value); +} + +CHIP_ERROR ProvisionStorageWriter::SetProvisionVersion(const char * value, size_t size) +{ + return SilabsConfig::WriteConfigValueStr(SilabsConfig::kConfigKey_Provision_Version, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetTestEventTriggerKey(const ByteSpan & value) +{ +#if defined(SL_MATTER_TEST_EVENT_TRIGGER_ENABLED) && SL_MATTER_TEST_EVENT_TRIGGER_ENABLED + constexpr size_t kEnableKeyLength = 16; + VerifyOrReturnError(value.size() == kEnableKeyLength, CHIP_ERROR_INVALID_ARGUMENT); + return SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_Test_Event_Trigger_Key, value.data(), value.size()); +#else + (void) value; + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif // SL_MATTER_TEST_EVENT_TRIGGER_ENABLED +} + +CHIP_ERROR ProvisionStorageWriter::SetOtaTlvEncryptionKey(const ByteSpan & value) +{ +#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION +#if defined(SL_MBEDTLS_USE_TINYCRYPT) && SL_MBEDTLS_USE_TINYCRYPT + return SilabsConfig::WriteConfigValueBin(SilabsConfig::kOtaTlvEncryption_KeyId, value.data(), value.size()); +#else + Silabs::OtaTlvEncryptionKey key; + ReturnErrorOnFailure(key.Import(value.data(), value.size())); + return SilabsConfig::WriteConfigValue(SilabsConfig::kOtaTlvEncryption_KeyId, key.GetId()); +#endif +#else + (void) value; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif +} + +CHIP_ERROR ProvisionStorageWriter::SetSetupPayload(const uint8_t * value, size_t size) +{ + return SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_SetupPayloadBitSet, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::Initialize(uint32_t flash_addr, uint32_t flash_size) +{ + sCredentialsOffset = 0; + + uint32_t base_addr = static_cast(reinterpret_cast(linker_nvm_end)); + if (flash_size > 0) + { +#ifndef SLI_SI91X_MCU_INTERFACE + base_addr = (flash_addr + flash_size - FLASH_PAGE_SIZE); +#endif +#ifdef _SILICON_LABS_32B_SERIES_3 + uint32_t tokenStartAddr = static_cast(reinterpret_cast(&linker_static_secure_tokens_begin)); + base_addr = tokenStartAddr + FLASH_PAGE_SIZE; +#endif + TEMPORARY_RETURN_IGNORED chip::DeviceLayer::Silabs::GetPlatform().FlashInit(); +#if defined(SL_PROVISION_GENERATOR) && SL_PROVISION_GENERATOR + // TODO: Might be ok to move this to gfw only using Reader.GetCredentialsBaseAddress(). + setNvm3End(base_addr); +#endif // SL_PROVISION_GENERATOR + } + return SetCredentialsBaseAddress(base_addr); +} + +CHIP_ERROR ProvisionStorageWriter::Commit() +{ + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageWriter::GetFlashPageSize(uint32_t & size) +{ + size = FLASH_PAGE_SIZE; + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageWriter::SetCredentialsBaseAddress(uint32_t addr) +{ + return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_Creds_Base_Addr, addr); +} + +CHIP_ERROR ProvisionStorageWriter::GetCredentialsBaseAddress(uint32_t & addr) +{ + return SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_Creds_Base_Addr, addr); +} + +CHIP_ERROR ProvisionStorageWriter::SetProvisionRequest(bool value) +{ + return SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_Provision_Request, value); +} + +CHIP_ERROR ProvisionStorageWriter::GetProvisionRequest(bool & value) +{ + return SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_Provision_Request, value); +} + +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/flash/ProvisionStorageFlash.cpp b/examples/platform/silabs/provision/flash/ProvisionStorageFlash.cpp new file mode 100644 index 00000000000..0cdfb9d7766 --- /dev/null +++ b/examples/platform/silabs/provision/flash/ProvisionStorageFlash.cpp @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * 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. + */ +#include + +#include +#include +#include +#include +#include + +#include + +#if SLI_SI91X_MCU_INTERFACE +#define FLASH_ERASE 1 +#define FLASH_WRITE 0 +#define NWP_FLASH_ADDRESS (0x0000000) +#include +extern "C" { +#include +#include +#include +#include +} +#else +#include +extern uint8_t linker_nvm_end[]; +#endif + +namespace { +constexpr size_t kPageSize = FLASH_PAGE_SIZE; +constexpr size_t kMaxBinaryValue = 1024; +constexpr size_t kArgumentBufferSize = 2 * sizeof(uint16_t) + kMaxBinaryValue; +} // namespace + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { +namespace Flash { + +#if SLI_SI91X_MCU_INTERFACE +static uint8_t * sReadOnlyPage = reinterpret_cast(NWP_FLASH_ADDRESS); +#else +static uint8_t * sReadOnlyPage = reinterpret_cast(linker_nvm_end); +#endif // SLI_SI91X_MCU_INTERFACE +uint8_t sTemporaryPage[kPageSize] = { 0 }; +uint8_t * sActivePage = sReadOnlyPage; +bool sInitialized = false; + +CHIP_ERROR EnsureInitialized() +{ + if (sInitialized) + { + return CHIP_NO_ERROR; + } +#if SLI_SI91X_MCU_INTERFACE + const uint32_t address = static_cast(reinterpret_cast(sReadOnlyPage)); + const sl_status_t status = sl_si91x_command_to_read_common_flash(address, sizeof(sTemporaryPage), sTemporaryPage); + VerifyOrReturnError(status == SL_STATUS_OK, CHIP_ERROR_READ_FAILED); + sActivePage = sTemporaryPage; +#else + sActivePage = sReadOnlyPage; +#endif + sInitialized = true; + return CHIP_NO_ERROR; +} + +CHIP_ERROR DecodeTotal(Encoding::Buffer & reader, uint16_t & total) +{ + uint16_t sz = 0; + ReturnErrorOnFailure(reader.Get(sz)); + total = (0xffff == sz) ? sizeof(uint16_t) : sz; + reader.pIn = reader.pBegin + total; + VerifyOrReturnError(reader.pIn <= reader.pEnd, CHIP_ERROR_INTERNAL, + ChipLogError(DeviceLayer, "Invalid page, or corrupted data")); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ActivateWrite(uint8_t *& active) +{ +#if !(SLI_SI91X_MCU_INTERFACE) + if (sActivePage == sReadOnlyPage) + { + memcpy(sTemporaryPage, sReadOnlyPage, sizeof(sTemporaryPage)); + } + active = sActivePage = sTemporaryPage; +#endif + return CHIP_NO_ERROR; +} + +CHIP_ERROR Set(uint16_t id, Encoding::Buffer & in) +{ + ReturnErrorOnFailure(EnsureInitialized()); + uint8_t * page = sActivePage; + uint16_t total = 0; + Encoding::Buffer reader(page, kPageSize, true); + uint8_t temp[kArgumentBufferSize] = { 0 }; + Encoding::Version2::Argument found(temp, sizeof(temp)); + + // Decode total + ReturnErrorOnFailure(DecodeTotal(reader, total)); + // Search entry + CHIP_ERROR err = Encoding::Version2::Find(reader, id, found); + if ((CHIP_ERROR_NOT_FOUND != err) && (CHIP_NO_ERROR != err)) + { + // Memory corruption, write at the last correct address + return err; + } + ReturnErrorOnFailure(ActivateWrite(page)); + + Encoding::Buffer writer(page, kPageSize); + if (CHIP_ERROR_NOT_FOUND == err) + { + // New entry + size_t temp_total = found.offset; + VerifyOrReturnError(temp_total + in.Size() <= kPageSize, CHIP_ERROR_INVALID_ARGUMENT); + // Copy entry + ReturnErrorOnFailure(in.Get(page + temp_total, in.Size())); + // Update total + total = temp_total + in.Size(); + ReturnErrorOnFailure(writer.Add(total)); + } + else + { + // Existing entry + if (in.Size() == found.encoded_size) + { + // Same size, keep in place + memset(page + found.offset, 0xff, found.encoded_size); + ReturnErrorOnFailure(in.Get(page + found.offset, in.Size())); + } + else + { + // Size change, move to the end + uint16_t temp_total = total - found.encoded_size; + VerifyOrReturnError(temp_total + in.Size() <= kPageSize, CHIP_ERROR_INVALID_ARGUMENT); + // Remove the entry by shifting only the bytes that follow it + memmove(page + found.offset, page + found.offset + found.encoded_size, total - found.offset - found.encoded_size); + // Add the entry + ReturnErrorOnFailure(in.Get(page + temp_total, in.Size())); + // Update total + total = temp_total + in.Size(); + ReturnErrorOnFailure(writer.Add(total)); + } + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR Get(uint16_t id, Encoding::Version2::Argument & arg) +{ + ReturnErrorOnFailure(EnsureInitialized()); + uint16_t total = 0; + + Encoding::Buffer reader(sActivePage, kPageSize, true); + ReturnErrorOnFailure(DecodeTotal(reader, total)); + CHIP_ERROR err = Encoding::Version2::Find(reader, id, arg); + // ProvisionStorage expects CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND + VerifyOrReturnError(CHIP_ERROR_NOT_FOUND != err, CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); + return err; +} + +CHIP_ERROR Set(uint16_t id, uint8_t value) +{ + uint8_t temp[kArgumentBufferSize] = { 0 }; + Encoding::Version2::Argument arg(temp, sizeof(temp)); + ReturnErrorOnFailure(Encoding::Version2::Encode(id, &value, arg)); + return Set(id, arg); +} + +CHIP_ERROR Get(uint16_t id, uint8_t & value) +{ + uint8_t temp[kArgumentBufferSize] = { 0 }; + Encoding::Version2::Argument arg(temp, sizeof(temp)); + ReturnErrorOnFailure(Get(id, arg)); + VerifyOrReturnError(Encoding::Version2::Type_Int8u == arg.type, CHIP_ERROR_INVALID_ARGUMENT); + value = arg.value.u8; + return CHIP_NO_ERROR; +} + +CHIP_ERROR Set(uint16_t id, uint16_t value) +{ + uint8_t temp[kArgumentBufferSize] = { 0 }; + Encoding::Version2::Argument arg(temp, sizeof(temp)); + ReturnErrorOnFailure(Encoding::Version2::Encode(id, &value, arg)); + return Set(id, arg); +} + +CHIP_ERROR Get(uint16_t id, uint16_t & value) +{ + uint8_t temp[kArgumentBufferSize] = { 0 }; + Encoding::Version2::Argument arg(temp, sizeof(temp)); + ReturnErrorOnFailure(Get(id, arg)); + VerifyOrReturnError(Encoding::Version2::Type_Int16u == arg.type, CHIP_ERROR_INVALID_ARGUMENT); + value = arg.value.u16; + return CHIP_NO_ERROR; +} + +CHIP_ERROR Set(uint16_t id, uint32_t value) +{ + uint8_t temp[kArgumentBufferSize] = { 0 }; + Encoding::Version2::Argument arg(temp, sizeof(temp)); + ReturnErrorOnFailure(Encoding::Version2::Encode(id, &value, arg)); + return Set(id, arg); +} + +CHIP_ERROR Get(uint16_t id, uint32_t & value) +{ + uint8_t temp[kArgumentBufferSize] = { 0 }; + Encoding::Version2::Argument arg(temp, sizeof(temp)); + ReturnErrorOnFailure(Get(id, arg)); + VerifyOrReturnError(Encoding::Version2::Type_Int32u == arg.type, CHIP_ERROR_INVALID_ARGUMENT); + value = arg.value.u32; + return CHIP_NO_ERROR; +} + +CHIP_ERROR Set(uint16_t id, const uint8_t * value, size_t size) +{ + uint8_t temp[kArgumentBufferSize] = { 0 }; + Encoding::Version2::Argument arg(temp, sizeof(temp)); + ReturnErrorOnFailure(Encoding::Version2::Encode(id, value, size, arg)); + return Set(id, arg); +} + +CHIP_ERROR Get(uint16_t id, uint8_t * value, size_t max_size, size_t & size) +{ + + uint8_t temp[kArgumentBufferSize] = { 0 }; + Encoding::Version2::Argument arg(temp, sizeof(temp)); + ReturnErrorOnFailure(Get(id, arg)); + VerifyOrReturnError(Encoding::Version2::Type_Binary == arg.type, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(arg.size <= max_size, CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(value, arg.value.b, arg.size); + size = arg.size; + return CHIP_NO_ERROR; +} + +CHIP_ERROR Set(uint16_t id, const char * value, size_t size) +{ + return Set(id, (const uint8_t *) value, size); +} + +CHIP_ERROR Get(uint16_t id, char * value, size_t max_size, size_t & size) +{ + // No room for a NUL-terminated C string; reject before max_size - 1 (avoids underflow) and skip storage. + VerifyOrReturnError(max_size > 0, CHIP_ERROR_INVALID_ARGUMENT); + ReturnErrorOnFailure(Get(id, (uint8_t *) value, max_size - 1, size)); + // Binary Get does not NUL-terminate; DeviceInstanceInfoProvider requires it on success. + value[size] = '\0'; + return CHIP_NO_ERROR; +} + +CHIP_ERROR Initialize(uint32_t flash_addr, uint32_t flash_size) +{ +#if SLI_SI91X_MCU_INTERFACE + (void) flash_addr; + (void) flash_size; + Flash::sInitialized = false; + ReturnErrorOnFailure(Flash::EnsureInitialized()); +#else // SLI_SI91X_MCU_INTERFACE + if (flash_size > 0) + { + Flash::sReadOnlyPage = (uint8_t *) (flash_addr + flash_size - kPageSize); + } + Flash::sActivePage = Flash::sReadOnlyPage; + Flash::sInitialized = true; + MSC_Init(); +#endif + return CHIP_NO_ERROR; +} + +CHIP_ERROR Commit() +{ + if (Flash::sActivePage == Flash::sTemporaryPage) + { +#if SLI_SI91X_MCU_INTERFACE + // Erase page + sl_status_t status = sl_si91x_command_to_write_common_flash((uint32_t) (Flash::sReadOnlyPage), Flash::sTemporaryPage, + kPageSize, FLASH_ERASE); + VerifyOrReturnError(status == SL_STATUS_OK, CHIP_ERROR_WRITE_FAILED); + // Write to flash + status = sl_si91x_command_to_write_common_flash((uint32_t) (Flash::sReadOnlyPage), Flash::sTemporaryPage, kPageSize, + FLASH_WRITE); + VerifyOrReturnError(status == SL_STATUS_OK, CHIP_ERROR_WRITE_FAILED); +#else + // Erase page + MSC_ErasePage((uint32_t *) Flash::sReadOnlyPage); + // Write to flash + MSC_WriteWord((uint32_t *) Flash::sReadOnlyPage, Flash::sTemporaryPage, kPageSize); +#endif // SLI_SI91X_MCU_INTERFACE + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR GetFlashPageSize(uint32_t & size) +{ + size = kPageSize; + return CHIP_NO_ERROR; +} + +CHIP_ERROR SetCredentialsBaseAddress(uint32_t addr) +{ + Flash::sReadOnlyPage = (uint8_t *) addr; + return CHIP_NO_ERROR; +} + +CHIP_ERROR GetCredentialsBaseAddress(uint32_t & addr) +{ + addr = (uint32_t) Flash::sReadOnlyPage; + return CHIP_NO_ERROR; +} + +} // namespace Flash +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/flash/ProvisionStorageFlash.h b/examples/platform/silabs/provision/flash/ProvisionStorageFlash.h new file mode 100644 index 00000000000..63f2b38be3c --- /dev/null +++ b/examples/platform/silabs/provision/flash/ProvisionStorageFlash.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * 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. + */ +#pragma once + +#include +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { +namespace Flash { +CHIP_ERROR Initialize(uint32_t flashAddress, uint32_t flashSize); +CHIP_ERROR Commit(); +CHIP_ERROR GetFlashPageSize(uint32_t & size); +CHIP_ERROR Set(uint16_t id, uint8_t value); +CHIP_ERROR Set(uint16_t id, uint16_t value); +CHIP_ERROR Set(uint16_t id, uint32_t value); +CHIP_ERROR Set(uint16_t id, const uint8_t * value, size_t size); +CHIP_ERROR Set(uint16_t id, const char * value, size_t size); +CHIP_ERROR Get(uint16_t id, uint8_t & value); +CHIP_ERROR Get(uint16_t id, uint16_t & value); +CHIP_ERROR Get(uint16_t id, uint32_t & value); +CHIP_ERROR Get(uint16_t id, uint8_t * value, size_t maxSize, size_t & size); +CHIP_ERROR Get(uint16_t id, char * value, size_t maxSize, size_t & size); +CHIP_ERROR SetCredentialsBaseAddress(uint32_t address); +CHIP_ERROR GetCredentialsBaseAddress(uint32_t & address); +} // namespace Flash +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/flash/ProvisionStorageReader.cpp b/examples/platform/silabs/provision/flash/ProvisionStorageReader.cpp new file mode 100644 index 00000000000..7d06c1e32eb --- /dev/null +++ b/examples/platform/silabs/provision/flash/ProvisionStorageReader.cpp @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION +#include +#endif // defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION + +#if !SL_MATTER_GN_BUILD +#include + +#ifndef NDEBUG +#if defined(SL_MATTER_TEST_EVENT_TRIGGER_ENABLED) +#include +#endif // defined(SL_MATTER_TEST_EVENT_TRIGGER_ENABLED) +#endif // NDEBUG +#endif // !SL_MATTER_GN_BUILD + +#include +using namespace chip::Credentials; +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { +ProvisionStorageReader & ProvisionStorageReader::GetInstance() +{ + static ProvisionStorageReader instance; + return instance; +} + +CHIP_ERROR ProvisionStorageReader::GetSerialNumber(char * value, size_t max) +{ + size_t size = 0; + return Flash::Get(Parameters::ID::kSerialNumber, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetVendorId(uint16_t & value) +{ + CHIP_ERROR err = Flash::Get(Parameters::ID::kVendorId, value); +#if defined(CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID) && CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + value = CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID; + err = CHIP_NO_ERROR; + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetVendorName(char * value, size_t max) +{ + size_t size = 0; + CHIP_ERROR err = Flash::Get(Parameters::ID::kVendorName, value, max, size); +#if defined(CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME) + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + VerifyOrReturnError(value != nullptr, CHIP_ERROR_NO_MEMORY); + VerifyOrReturnError(max > strlen(CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME), CHIP_ERROR_BUFFER_TOO_SMALL); + Platform::CopyString(value, max, CHIP_DEVICE_CONFIG_TEST_VENDOR_NAME); + err = CHIP_NO_ERROR; + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetProductId(uint16_t & value) +{ + CHIP_ERROR err = Flash::Get(Parameters::ID::kProductId, value); +#if defined(CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID) && CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + value = CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID; + err = CHIP_NO_ERROR; + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetProductName(char * value, size_t max) +{ + size_t size = 0; + CHIP_ERROR err = Flash::Get(Parameters::ID::kProductName, value, max, size); +#if defined(CHIP_DEVICE_CONFIG_TEST_PRODUCT_NAME) + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + VerifyOrReturnError(value != nullptr, CHIP_ERROR_NO_MEMORY); + VerifyOrReturnError(max > strlen(CHIP_DEVICE_CONFIG_TEST_PRODUCT_NAME), CHIP_ERROR_BUFFER_TOO_SMALL); + Platform::CopyString(value, max, CHIP_DEVICE_CONFIG_TEST_PRODUCT_NAME); + err = CHIP_NO_ERROR; + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetProductLabel(char * value, size_t max) +{ + size_t size = 0; + return Flash::Get(Parameters::ID::kProductLabel, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetProductURL(char * value, size_t max) +{ + size_t size = 0; + return Flash::Get(Parameters::ID::kProductUrl, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetPartNumber(char * value, size_t max) +{ + size_t size = 0; + return Flash::Get(Parameters::ID::kPartNumber, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetHardwareVersion(uint16_t & value) +{ + CHIP_ERROR err = Flash::Get(Parameters::ID::kHwVersion, value); +#if defined(CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION) + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + value = CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION; + err = CHIP_NO_ERROR; + } +#endif // CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetHardwareVersionString(char * value, size_t max) +{ + size_t size = 0; + CHIP_ERROR err = Flash::Get(Parameters::ID::kHwVersionStr, value, max, size); +#if defined(CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING) + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + VerifyOrReturnError(value != nullptr, CHIP_ERROR_NO_MEMORY); + VerifyOrReturnError(max > strlen(CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING), CHIP_ERROR_BUFFER_TOO_SMALL); + Platform::CopyString(value, max, CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING); + err = CHIP_NO_ERROR; + } +#endif // CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetManufacturingDate(uint8_t * value, size_t max, size_t & size) +{ + return Flash::Get(Parameters::ID::kManufacturingDate, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetPersistentUniqueId(uint8_t * value, size_t max, size_t & size) +{ + return Flash::Get(Parameters::ID::kPersistentUniqueId, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetSetupDiscriminator(uint16_t & value) +{ + CHIP_ERROR err = Flash::Get(Parameters::ID::kDiscriminator, value); +#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR) && CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + value = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR; + err = CHIP_NO_ERROR; + } +#endif // CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR + ReturnErrorOnFailure(err); + VerifyOrReturnLogError(value <= kMaxDiscriminatorValue, CHIP_ERROR_INVALID_ARGUMENT); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetSpake2pIterationCount(uint32_t & value) +{ + CHIP_ERROR err = Flash::Get(Parameters::ID::kSpake2pIterations, value); +#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT) && CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + value = CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT; + err = CHIP_NO_ERROR; + } +#endif // CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetSpake2pSalt(char * value, size_t max, size_t & size) +{ + return Flash::Get(Parameters::ID::kSpake2pSalt, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetSpake2pVerifier(char * value, size_t max, size_t & size) +{ + return Flash::Get(Parameters::ID::kSpake2pVerifier, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetFirmwareInformation(MutableByteSpan & value) +{ + // TODO: We need a real example FirmwareInformation to be populated. + value.reduce_size(0); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetCertificationDeclaration(MutableByteSpan & value) +{ + size_t size = 0; + CHIP_ERROR err = (Flash::Get(Parameters::ID::kCertification, value.data(), value.size(), size)); +#if SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + // Example CD + return Examples::GetExampleDACProvider()->GetCertificationDeclaration(value); + } +#endif // SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS + ReturnErrorOnFailure(err); + value.reduce_size(size); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetProductAttestationIntermediateCert(MutableByteSpan & value) +{ + size_t size = 0; + CHIP_ERROR err = (Flash::Get(Parameters::ID::kPaiCert, value.data(), value.size(), size)); +#if SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + // Example PAI + return Examples::GetExampleDACProvider()->GetProductAttestationIntermediateCert(value); + } +#endif // SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS + ReturnErrorOnFailure(err); + value.reduce_size(size); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetDeviceAttestationCert(MutableByteSpan & value) +{ + size_t size = 0; + CHIP_ERROR err = (Flash::Get(Parameters::ID::kDacCert, value.data(), value.size(), size)); +#if SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS + if (CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND == err) + { + // Example DAC + return Examples::GetExampleDACProvider()->GetDeviceAttestationCert(value); + } +#endif // SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS + ReturnErrorOnFailure(err); + value.reduce_size(size); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::SignWithDeviceAttestationKey(const ByteSpan & message, MutableByteSpan & signature) +{ + CHIP_ERROR err = ProvisionCrypto::GetInstance().SignWithDeviceAttestationKey(message, signature); +#if SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS + if (err == CHIP_ERROR_NOT_FOUND || err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + return Examples::GetExampleDACProvider()->SignWithDeviceAttestationKey(message, signature); + } +#endif + return err; +} + +CHIP_ERROR ProvisionStorageReader::GetProvisionVersion(char * value, size_t max, size_t & size) +{ + return Flash::Get(Parameters::ID::kVersion, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetSetupPayload(uint8_t * value, size_t max, size_t & size) +{ + return Flash::Get(Parameters::ID::kSetupPayload, value, max, size); +} + +#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION +CHIP_ERROR ProvisionStorageReader::GetOtaTlvEncryptionKeyId(uint32_t & keyId) +{ +#if defined(SL_MBEDTLS_USE_TINYCRYPT) && SL_MBEDTLS_USE_TINYCRYPT + (void) keyId; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#else + return Flash::Get(Parameters::ID::kOtaTlvEncryptionKey, keyId); +#endif +} +CHIP_ERROR ProvisionStorageReader::DecryptUsingOtaTlvEncryptionKey(MutableByteSpan & block, uint32_t & ivOffset) +{ +#if defined(SL_MBEDTLS_USE_TINYCRYPT) && SL_MBEDTLS_USE_TINYCRYPT + uint8_t keyBuffer[Silabs::OtaTlvEncryptionKey::kOTAEncryptionKeyLength] = { 0 }; + size_t keyLength = 0; + ReturnErrorOnFailure(Flash::Get(Parameters::ID::kOtaTlvEncryptionKey, keyBuffer, sizeof(keyBuffer), keyLength)); + VerifyOrReturnError(keyLength == sizeof(keyBuffer), CHIP_ERROR_INVALID_ARGUMENT); + return Silabs::OtaTlvEncryptionKey::Decrypt(ByteSpan(keyBuffer), block, ivOffset); +#else + (void) block; + (void) ivOffset; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif +} +#else +CHIP_ERROR ProvisionStorageReader::GetOtaTlvEncryptionKeyId(uint32_t & keyId) +{ + (void) keyId; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} +CHIP_ERROR ProvisionStorageReader::DecryptUsingOtaTlvEncryptionKey(MutableByteSpan & block, uint32_t & ivOffset) +{ + (void) block; + (void) ivOffset; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} +#endif +CHIP_ERROR ProvisionStorageReader::GetTestEventTriggerKey(MutableByteSpan & keySpan) +{ +#ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLED + constexpr size_t kEnableKeyLength = TestEventTriggerDelegate::kEnableKeyLength; + size_t keyLength = 0; + VerifyOrReturnError(keySpan.size() >= kEnableKeyLength, CHIP_ERROR_BUFFER_TOO_SMALL); + CHIP_ERROR err = Flash::Get(Parameters::ID::kTestEventTriggerKey, keySpan.data(), kEnableKeyLength, keyLength); +#ifndef NDEBUG +#ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLE_KEY + if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + constexpr char enableKey[] = SL_MATTER_TEST_EVENT_TRIGGER_ENABLE_KEY; + VerifyOrReturnError(Encoding::HexToBytes(enableKey, strlen(enableKey), keySpan.data(), kEnableKeyLength) == + kEnableKeyLength, + CHIP_ERROR_INTERNAL); + keyLength = kEnableKeyLength; + err = CHIP_NO_ERROR; + } +#endif // SL_MATTER_TEST_EVENT_TRIGGER_ENABLE_KEY +#endif // NDEBUG + ReturnErrorOnFailure(err); + VerifyOrReturnError(keyLength == kEnableKeyLength, CHIP_ERROR_INVALID_ARGUMENT); + keySpan.reduce_size(keyLength); + return CHIP_NO_ERROR; +#else + (void) keySpan; + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif // SL_MATTER_TEST_EVENT_TRIGGER_ENABLED +} +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/flash/ProvisionStorageWriter.cpp b/examples/platform/silabs/provision/flash/ProvisionStorageWriter.cpp new file mode 100644 index 00000000000..b686c7ed395 --- /dev/null +++ b/examples/platform/silabs/provision/flash/ProvisionStorageWriter.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * 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. + */ +#include +#include +#include +#include +#include + +#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION +#include +#endif + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { +ProvisionStorageWriter & ProvisionStorageWriter::GetInstance() +{ + static ProvisionStorageWriter instance; + return instance; +} +CHIP_ERROR ProvisionStorageWriter::Initialize(uint32_t flashAddress, uint32_t flashSize) +{ + return Flash::Initialize(flashAddress, flashSize); +} +CHIP_ERROR ProvisionStorageWriter::Commit() +{ + return Flash::Commit(); +} +CHIP_ERROR ProvisionStorageWriter::GetFlashPageSize(uint32_t & size) +{ + return Flash::GetFlashPageSize(size); +} +CHIP_ERROR ProvisionStorageWriter::SetCredentialsBaseAddress(uint32_t address) +{ + return Flash::SetCredentialsBaseAddress(address); +} +CHIP_ERROR ProvisionStorageWriter::GetCredentialsBaseAddress(uint32_t & address) +{ + return Flash::GetCredentialsBaseAddress(address); +} + +CHIP_ERROR ProvisionStorageWriter::SetSerialNumber(const char * value, size_t len) +{ + return Flash::Set(Parameters::ID::kSerialNumber, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetVendorId(uint16_t value) +{ + return Flash::Set(Parameters::ID::kVendorId, value); +} + +CHIP_ERROR ProvisionStorageWriter::SetVendorName(const char * value, size_t len) +{ + return Flash::Set(Parameters::ID::kVendorName, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductId(uint16_t value) +{ + return Flash::Set(Parameters::ID::kProductId, value); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductName(const char * value, size_t len) +{ + return Flash::Set(Parameters::ID::kProductName, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductLabel(const char * value, size_t len) +{ + return Flash::Set(Parameters::ID::kProductLabel, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductURL(const char * value, size_t len) +{ + return Flash::Set(Parameters::ID::kProductUrl, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetPartNumber(const char * value, size_t len) +{ + return Flash::Set(Parameters::ID::kPartNumber, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetHardwareVersion(uint16_t value) +{ + return Flash::Set(Parameters::ID::kHwVersion, value); +} + +CHIP_ERROR ProvisionStorageWriter::SetHardwareVersionString(const char * value, size_t len) +{ + return Flash::Set(Parameters::ID::kHwVersionStr, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetManufacturingDate(const char * value, size_t len) +{ + return Flash::Set(Parameters::ID::kManufacturingDate, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetPersistentUniqueId(const uint8_t * value, size_t size) +{ + return Flash::Set(Parameters::ID::kPersistentUniqueId, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetSetupDiscriminator(uint16_t value) +{ + return Flash::Set(Parameters::ID::kDiscriminator, value); +} + +CHIP_ERROR ProvisionStorageWriter::SetSpake2pIterationCount(uint32_t value) +{ + return Flash::Set(Parameters::ID::kSpake2pIterations, value); +} + +CHIP_ERROR ProvisionStorageWriter::SetSpake2pSalt(const char * value, size_t size) +{ + return Flash::Set(Parameters::ID::kSpake2pSalt, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetSpake2pVerifier(const char * value, size_t size) +{ + return Flash::Set(Parameters::ID::kSpake2pVerifier, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetFirmwareInformation(const ByteSpan & value) +{ + (void) value; + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageWriter::SetCertificationDeclaration(const ByteSpan & value) +{ + return Flash::Set(Parameters::ID::kCertification, value.data(), value.size()); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductAttestationIntermediateCert(const ByteSpan & value) +{ + return Flash::Set(Parameters::ID::kPaiCert, value.data(), value.size()); +} + +CHIP_ERROR ProvisionStorageWriter::SetDeviceAttestationCert(const ByteSpan & value) +{ + return Flash::Set(Parameters::ID::kDacCert, value.data(), value.size()); +} + +CHIP_ERROR ProvisionStorageWriter::SetProvisionVersion(const char * value, size_t size) +{ + return Flash::Set(Parameters::ID::kVersion, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetSetupPayload(const uint8_t * value, size_t size) +{ + return Flash::Set(Parameters::ID::kSetupPayload, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetProvisionRequest(bool value) +{ + // return Flash::Set(Parameters::ID::kProvisionRequest, value); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageWriter::GetProvisionRequest(bool & value) +{ + // return Flash::Set(Parameters::ID::kProvisionRequest, value); + return CHIP_ERROR_NOT_FOUND; +} + +CHIP_ERROR ProvisionStorageWriter::SetOtaTlvEncryptionKey(const ByteSpan & value) +{ +#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION +#if defined(SL_MBEDTLS_USE_TINYCRYPT) && SL_MBEDTLS_USE_TINYCRYPT + return Flash::Set(Parameters::ID::kOtaTlvEncryptionKey, value.data(), value.size()); +#else + Silabs::OtaTlvEncryptionKey key; + ReturnErrorOnFailure(key.Import(value.data(), value.size())); + return Flash::Set(Parameters::ID::kOtaTlvEncryptionKey, key.GetId()); +#endif +#else + (void) value; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif +} +CHIP_ERROR ProvisionStorageWriter::SetTestEventTriggerKey(const ByteSpan & value) +{ +#ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLED + VerifyOrReturnError(value.size() == TestEventTriggerDelegate::kEnableKeyLength, CHIP_ERROR_INVALID_ARGUMENT); + return Flash::Set(Parameters::ID::kTestEventTriggerKey, value.data(), value.size()); +#else + (void) value; + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif // SL_MATTER_TEST_EVENT_TRIGGER_ENABLED +} +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/zephyr/ProvisionStorageReader.cpp b/examples/platform/silabs/provision/zephyr/ProvisionStorageReader.cpp new file mode 100644 index 00000000000..333406d5313 --- /dev/null +++ b/examples/platform/silabs/provision/zephyr/ProvisionStorageReader.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { +using chip::DeviceLayer::Internal::ZephyrConfig; + +namespace { + +CHIP_ERROR ReadConfigBin(ZephyrConfig::Key key, MutableByteSpan & buffer) +{ + size_t dataLength = 0; + ReturnErrorOnFailure(ZephyrConfig::ReadConfigValueBin(key, buffer.data(), buffer.size(), dataLength)); + buffer.reduce_size(dataLength); + return CHIP_NO_ERROR; +} + +} // namespace + +ProvisionStorageReader & ProvisionStorageReader::GetInstance() +{ + static ProvisionStorageReader instance; + return instance; +} + +CHIP_ERROR ProvisionStorageReader::GetSerialNumber(char * value, size_t max) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + size_t size = 0; + return ZephyrConfig::ReadConfigValueStr(ZephyrConfig::kConfigKey_SerialNum, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetVendorId(uint16_t & value) +{ + uint32_t stored = 0; + ReturnErrorOnFailure(ZephyrConfig::ReadConfigValue(ZephyrStorage::kConfigKeyVendorId, stored)); + value = static_cast(stored); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetVendorName(char * value, size_t max) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + size_t name_len = 0; + + return ZephyrConfig::ReadConfigValueStr(ZephyrStorage::kConfigKeyVendorName, value, max, name_len); +} + +CHIP_ERROR ProvisionStorageReader::GetProductId(uint16_t & value) +{ + uint32_t stored = 0; + ReturnErrorOnFailure(ZephyrConfig::ReadConfigValue(ZephyrStorage::kConfigKeyProductId, stored)); + value = static_cast(stored); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetProductName(char * value, size_t max) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + size_t size = 0; + + return ZephyrConfig::ReadConfigValueStr(ZephyrStorage::kConfigKeyProductName, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetProductLabel(char * value, size_t max) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + size_t size = 0; + return ZephyrConfig::ReadConfigValueStr(ZephyrStorage::kConfigKeyProductLabel, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetProductURL(char * value, size_t max) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + size_t size = 0; + return ZephyrConfig::ReadConfigValueStr(ZephyrStorage::kConfigKeyProductUrl, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetPartNumber(char * value, size_t max) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + size_t size = 0; + return ZephyrConfig::ReadConfigValueStr(ZephyrStorage::kConfigKeyPartNumber, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetHardwareVersion(uint16_t & value) +{ + uint32_t stored = 0; + ReturnErrorOnFailure(ZephyrConfig::ReadConfigValue(ZephyrConfig::kConfigKey_HardwareVersion, stored)); + value = static_cast(stored); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetHardwareVersionString(char * value, size_t max) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + size_t size = 0; + return ZephyrConfig::ReadConfigValueStr(ZephyrStorage::kConfigKeyHardwareVersionString, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetManufacturingDate(uint8_t * value, size_t max, size_t & size) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::ReadConfigValueStr(ZephyrConfig::kConfigKey_ManufacturingDate, reinterpret_cast(value), max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetPersistentUniqueId(uint8_t * value, size_t max, size_t & size) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::ReadConfigValueBin(ZephyrConfig::kConfigKey_UniqueId, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetSetupDiscriminator(uint16_t & value) +{ + uint32_t stored = 0; + ReturnErrorOnFailure(ZephyrConfig::ReadConfigValue(ZephyrConfig::kConfigKey_SetupDiscriminator, stored)); + value = static_cast(stored); + VerifyOrReturnLogError(value <= kMaxDiscriminatorValue, CHIP_ERROR_INVALID_ARGUMENT); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetSpake2pIterationCount(uint32_t & value) +{ + return ZephyrConfig::ReadConfigValue(ZephyrConfig::kConfigKey_Spake2pIterationCount, value); +} + +CHIP_ERROR ProvisionStorageReader::GetSpake2pSalt(char * value, size_t max, size_t & size) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::ReadConfigValueStr(ZephyrConfig::kConfigKey_Spake2pSalt, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetSpake2pVerifier(char * value, size_t max, size_t & size) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::ReadConfigValueStr(ZephyrConfig::kConfigKey_Spake2pVerifier, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetFirmwareInformation(MutableByteSpan & value) +{ + value.reduce_size(0); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageReader::GetCertificationDeclaration(MutableByteSpan & value) +{ + return ReadConfigBin(ZephyrConfig::kConfigKey_CertificationDeclaration, value); +} + +CHIP_ERROR ProvisionStorageReader::GetProductAttestationIntermediateCert(MutableByteSpan & value) +{ + return ReadConfigBin(ZephyrConfig::kConfigKey_MfrDeviceICACerts, value); +} + +CHIP_ERROR ProvisionStorageReader::GetDeviceAttestationCert(MutableByteSpan & value) +{ + return ReadConfigBin(ZephyrConfig::kConfigKey_MfrDeviceCert, value); +} + +CHIP_ERROR ProvisionStorageReader::SignWithDeviceAttestationKey(const ByteSpan & message, MutableByteSpan & signature) +{ + const uint32_t keyId = ZephyrStorage::GetDacPsaKeyId(); + VerifyOrReturnError(ZephyrStorage::DacPsaKeyExists(), CHIP_ERROR_NOT_FOUND, + ChipLogError(DeviceLayer, "DAC PSA key id %u missing", keyId)); + + Crypto::P256ECDSASignature rawSignature; + VerifyOrReturnError(signature.size() >= rawSignature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); + + size_t outputLen = 0; + const psa_status_t status = psa_sign_message(static_cast(keyId), PSA_ALG_ECDSA(PSA_ALG_SHA_256), message.data(), + message.size(), rawSignature.Bytes(), rawSignature.Capacity(), &outputLen); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL, + ChipLogError(DeviceLayer, "psa_sign_message failed: %" PRId32, status)); + VerifyOrReturnError(outputLen == Crypto::kP256_ECDSA_Signature_Length_Raw, CHIP_ERROR_INTERNAL); + + ReturnErrorOnFailure(rawSignature.SetLength(outputLen)); + return CopySpanToMutableSpan(ByteSpan{ rawSignature.ConstBytes(), rawSignature.Length() }, signature); +} + +CHIP_ERROR ProvisionStorageReader::GetProvisionVersion(char * value, size_t max, size_t & size) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::ReadConfigValueStr(ZephyrStorage::kConfigKeyProvisionVersion, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetSetupPayload(uint8_t * value, size_t max, size_t & size) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::ReadConfigValueBin(ZephyrStorage::kConfigKeySetupPayload, value, max, size); +} + +CHIP_ERROR ProvisionStorageReader::GetOtaTlvEncryptionKeyId(uint32_t & keyId) +{ + (void) keyId; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR ProvisionStorageReader::DecryptUsingOtaTlvEncryptionKey(MutableByteSpan & block, uint32_t & ivOffset) +{ + (void) block; + (void) ivOffset; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR ProvisionStorageReader::GetTestEventTriggerKey(MutableByteSpan & keySpan) +{ + (void) keySpan; + return CHIP_ERROR_NOT_IMPLEMENTED; +} +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/zephyr/ProvisionStorageWriter.cpp b/examples/platform/silabs/provision/zephyr/ProvisionStorageWriter.cpp new file mode 100644 index 00000000000..e8bb44d9649 --- /dev/null +++ b/examples/platform/silabs/provision/zephyr/ProvisionStorageWriter.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#if defined(SL_PROVISION_GENERATOR) && SL_PROVISION_GENERATOR +#include +#endif +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { +using chip::DeviceLayer::Internal::ZephyrConfig; + +namespace { +bool sInitialized = false; +} // namespace + +ProvisionStorageWriter & ProvisionStorageWriter::GetInstance() +{ + static ProvisionStorageWriter instance; + return instance; +} +CHIP_ERROR ProvisionStorageWriter::Initialize(uint32_t flashAddress, uint32_t flashSize) +{ +#if defined(SL_PROVISION_GENERATOR) && SL_PROVISION_GENERATOR + // flashAddress is the offset to the storage area; flashSize is its total size. + VerifyOrReturnError(settings_nvs_set_runtime_geometry(static_cast(flashAddress), flashSize) == 0, + CHIP_ERROR_PERSISTED_STORAGE_FAILED); + ReturnErrorOnFailure(ZephyrConfig::Init()); +#else + (void) flashAddress; + (void) flashSize; + ReturnErrorOnFailure(ZephyrConfig::Init()); + VerifyOrDo(ZephyrStorage::DacPsaKeyExists(), + ChipLogError(DeviceLayer, "DAC PSA key id %u missing", ZephyrStorage::GetDacPsaKeyId())); +#endif + sInitialized = true; + return CHIP_NO_ERROR; +} +CHIP_ERROR ProvisionStorageWriter::Commit() +{ + // Zephyr settings writes are immediate. + return CHIP_NO_ERROR; +} +CHIP_ERROR ProvisionStorageWriter::GetFlashPageSize(uint32_t & size) +{ + (void) size; + return CHIP_ERROR_NOT_IMPLEMENTED; +} +CHIP_ERROR ProvisionStorageWriter::SetCredentialsBaseAddress(uint32_t address) +{ + (void) address; + return CHIP_NO_ERROR; +} +CHIP_ERROR ProvisionStorageWriter::GetCredentialsBaseAddress(uint32_t & address) +{ + address = 0; + return CHIP_NO_ERROR; +} +CHIP_ERROR ProvisionStorageWriter::SetProvisionRequest(bool value) +{ + return sInitialized + ? ZephyrConfig::WriteConfigValue(ZephyrStorage::kConfigKeyProvisionRequest, static_cast(value ? 1 : 0)) + : CHIP_NO_ERROR; +} +CHIP_ERROR ProvisionStorageWriter::GetProvisionRequest(bool & value) +{ + if (!sInitialized) + { + // Generator firmware has not initialized NVS yet, so assume provisioning is required. + value = true; + return CHIP_NO_ERROR; + } + uint32_t stored = 0; + ReturnErrorOnFailure(ZephyrConfig::ReadConfigValue(ZephyrStorage::kConfigKeyProvisionRequest, stored)); + value = stored != 0; + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageWriter::SetSerialNumber(const char * value, size_t len) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::WriteConfigValueStr(ZephyrConfig::kConfigKey_SerialNum, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetVendorId(uint16_t value) +{ + return ZephyrConfig::WriteConfigValue(ZephyrStorage::kConfigKeyVendorId, static_cast(value)); +} + +CHIP_ERROR ProvisionStorageWriter::SetVendorName(const char * value, size_t len) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::WriteConfigValueStr(ZephyrStorage::kConfigKeyVendorName, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductId(uint16_t value) +{ + return ZephyrConfig::WriteConfigValue(ZephyrStorage::kConfigKeyProductId, static_cast(value)); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductName(const char * value, size_t len) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::WriteConfigValueStr(ZephyrStorage::kConfigKeyProductName, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductLabel(const char * value, size_t len) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::WriteConfigValueStr(ZephyrStorage::kConfigKeyProductLabel, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductURL(const char * value, size_t len) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::WriteConfigValueStr(ZephyrStorage::kConfigKeyProductUrl, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetPartNumber(const char * value, size_t len) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::WriteConfigValueStr(ZephyrStorage::kConfigKeyPartNumber, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetHardwareVersion(uint16_t value) +{ + return ZephyrConfig::WriteConfigValue(ZephyrConfig::kConfigKey_HardwareVersion, static_cast(value)); +} + +CHIP_ERROR ProvisionStorageWriter::SetHardwareVersionString(const char * value, size_t len) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::WriteConfigValueStr(ZephyrStorage::kConfigKeyHardwareVersionString, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetManufacturingDate(const char * value, size_t len) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::WriteConfigValueStr(ZephyrConfig::kConfigKey_ManufacturingDate, value, len); +} + +CHIP_ERROR ProvisionStorageWriter::SetPersistentUniqueId(const uint8_t * value, size_t size) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::WriteConfigValueBin(ZephyrConfig::kConfigKey_UniqueId, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetSetupDiscriminator(uint16_t value) +{ + return ZephyrConfig::WriteConfigValue(ZephyrConfig::kConfigKey_SetupDiscriminator, static_cast(value)); +} + +CHIP_ERROR ProvisionStorageWriter::SetSpake2pIterationCount(uint32_t value) +{ + return ZephyrConfig::WriteConfigValue(ZephyrConfig::kConfigKey_Spake2pIterationCount, value); +} + +CHIP_ERROR ProvisionStorageWriter::SetSpake2pSalt(const char * value, size_t size) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::WriteConfigValueStr(ZephyrConfig::kConfigKey_Spake2pSalt, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetSpake2pVerifier(const char * value, size_t size) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::WriteConfigValueStr(ZephyrConfig::kConfigKey_Spake2pVerifier, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetFirmwareInformation(const ByteSpan & value) +{ + (void) value; + return CHIP_NO_ERROR; +} + +CHIP_ERROR ProvisionStorageWriter::SetCertificationDeclaration(const ByteSpan & value) +{ + return ZephyrConfig::WriteConfigValueBin(ZephyrConfig::kConfigKey_CertificationDeclaration, value.data(), value.size()); +} + +CHIP_ERROR ProvisionStorageWriter::SetProductAttestationIntermediateCert(const ByteSpan & value) +{ + return ZephyrConfig::WriteConfigValueBin(ZephyrConfig::kConfigKey_MfrDeviceICACerts, value.data(), value.size()); +} + +CHIP_ERROR ProvisionStorageWriter::SetDeviceAttestationCert(const ByteSpan & value) +{ + return ZephyrConfig::WriteConfigValueBin(ZephyrConfig::kConfigKey_MfrDeviceCert, value.data(), value.size()); +} + +CHIP_ERROR ProvisionStorageWriter::SetProvisionVersion(const char * value, size_t size) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::WriteConfigValueStr(ZephyrStorage::kConfigKeyProvisionVersion, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetSetupPayload(const uint8_t * value, size_t size) +{ + VerifyOrReturnError(value != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + return ZephyrConfig::WriteConfigValueBin(ZephyrStorage::kConfigKeySetupPayload, value, size); +} + +CHIP_ERROR ProvisionStorageWriter::SetOtaTlvEncryptionKey(const ByteSpan & value) +{ + (void) value; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} +CHIP_ERROR ProvisionStorageWriter::SetTestEventTriggerKey(const ByteSpan & value) +{ + (void) value; + return CHIP_NO_ERROR; +} +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/provision/zephyr/ProvisionStorageZephyr.h b/examples/platform/silabs/provision/zephyr/ProvisionStorageZephyr.h new file mode 100644 index 00000000000..ac164cf0317 --- /dev/null +++ b/examples/platform/silabs/provision/zephyr/ProvisionStorageZephyr.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace Silabs { +namespace Provision { +namespace ZephyrStorage { + +#define DEFINE_CONFIG_KEY(name, suffix) \ + inline constexpr char name[] = CHIP_DEVICE_CONFIG_SETTINGS_KEY "-sl-fct/" suffix; \ + static_assert(sizeof(name) <= SETTINGS_MAX_NAME_LEN, #name " is too long") + +DEFINE_CONFIG_KEY(kConfigKeyVendorId, "vendor-id"); +DEFINE_CONFIG_KEY(kConfigKeyProductId, "product-id"); +DEFINE_CONFIG_KEY(kConfigKeyVendorName, "vendor-name"); +DEFINE_CONFIG_KEY(kConfigKeyProductName, "product-name"); +DEFINE_CONFIG_KEY(kConfigKeyProductLabel, "product-label"); +DEFINE_CONFIG_KEY(kConfigKeyProductUrl, "product-url"); +DEFINE_CONFIG_KEY(kConfigKeyPartNumber, "part-number"); +DEFINE_CONFIG_KEY(kConfigKeyHardwareVersionString, "hardware-ver-str"); +DEFINE_CONFIG_KEY(kConfigKeySetupPayload, "setup-payload"); +DEFINE_CONFIG_KEY(kConfigKeyProvisionRequest, "provision-req"); +DEFINE_CONFIG_KEY(kConfigKeyProvisionVersion, "provision-ver"); +DEFINE_CONFIG_KEY(kConfigKeyDacKeyId, "dac-key-id"); + +#undef DEFINE_CONFIG_KEY + +inline constexpr psa_key_id_t kDacPsaKeyId = 2; + +// Stored id when one was provisioned, otherwise the default id. +inline uint32_t GetDacPsaKeyId() +{ + uint32_t keyId = 0; + if (chip::DeviceLayer::Internal::ZephyrConfig::ReadConfigValue(kConfigKeyDacKeyId, keyId) == CHIP_NO_ERROR && keyId != 0) + { + return keyId; + } + return kDacPsaKeyId; +} + +inline bool DacPsaKeyExists() +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + const psa_status_t status = psa_get_key_attributes(static_cast(GetDacPsaKeyId()), &attributes); + psa_reset_key_attributes(&attributes); + return status == PSA_SUCCESS; +} + +} // namespace ZephyrStorage +} // namespace Provision +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/platform/silabs/test-event-trigger/SilabsTestEventTriggerDelegate.cpp b/examples/platform/silabs/test-event-trigger/SilabsTestEventTriggerDelegate.cpp index b86bf0f193f..b03d287068d 100644 --- a/examples/platform/silabs/test-event-trigger/SilabsTestEventTriggerDelegate.cpp +++ b/examples/platform/silabs/test-event-trigger/SilabsTestEventTriggerDelegate.cpp @@ -23,10 +23,10 @@ using namespace ::chip::DeviceLayer; namespace chip { -CHIP_ERROR SilabsTestEventTriggerDelegate::Init(DeviceLayer::Silabs::Provision::ProvisionedDataProvider * provider) +CHIP_ERROR SilabsTestEventTriggerDelegate::Init(DeviceLayer::Silabs::Provision::IProvisionStorageReader * reader) { - VerifyOrReturnError(provider != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - mProvider = provider; + VerifyOrReturnError(reader != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + mReader = reader; return CHIP_NO_ERROR; } @@ -38,11 +38,11 @@ bool SilabsTestEventTriggerDelegate::DoesEnableKeyMatch(const ByteSpan & enableK uint8_t storedEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0 }; MutableByteSpan storedEnableKeySpan(storedEnableKey); - // If mProvider is equal to nullptr, we still continue in the function to check if the requested enableKey matches the zero + // If mReader is equal to nullptr, we still continue in the function to check if the requested enableKey matches the zero // key. - if (mProvider != nullptr) + if (mReader != nullptr) { - error = mProvider->GetTestEventTriggerKey(storedEnableKeySpan); + error = mReader->GetTestEventTriggerKey(storedEnableKeySpan); } if (error != CHIP_NO_ERROR) diff --git a/examples/platform/silabs/test-event-trigger/SilabsTestEventTriggerDelegate.h b/examples/platform/silabs/test-event-trigger/SilabsTestEventTriggerDelegate.h index 9b4a7ebd414..a14cd0a764c 100644 --- a/examples/platform/silabs/test-event-trigger/SilabsTestEventTriggerDelegate.h +++ b/examples/platform/silabs/test-event-trigger/SilabsTestEventTriggerDelegate.h @@ -19,7 +19,7 @@ #pragma once #include -#include +#include #include #include #include @@ -34,12 +34,12 @@ class SilabsTestEventTriggerDelegate : public TestEventTriggerDelegate /** * @brief Configures the Silabs Test Event trigger * - * @param provider pointer to the silabs provisionned data provider + * @param reader pointer to the Silicon Labs provisioning storage reader * - * @return CHIP_ERROR CHIP_NO_ERROR, if the init was succesful - * CHIP_ERROR_INVALID_ARGUMENT, if the manager input is equal to nullptr + * @return CHIP_ERROR CHIP_NO_ERROR, if initialization succeeds + * CHIP_ERROR_INVALID_ARGUMENT, if reader is nullptr */ - CHIP_ERROR Init(DeviceLayer::Silabs::Provision::ProvisionedDataProvider * provider); + CHIP_ERROR Init(DeviceLayer::Silabs::Provision::IProvisionStorageReader * reader); /** * @brief Checks to see if `enableKey` provided matches value chosen by the manufacturer. @@ -49,7 +49,7 @@ class SilabsTestEventTriggerDelegate : public TestEventTriggerDelegate bool DoesEnableKeyMatch(const ByteSpan & enableKey) const override; private: - DeviceLayer::Silabs::Provision::ProvisionedDataProvider * mProvider = nullptr; + DeviceLayer::Silabs::Provision::IProvisionStorageReader * mReader = nullptr; }; } // namespace chip diff --git a/examples/platform/silabs/tests/TestSilabsTestEventTrigger.cpp b/examples/platform/silabs/tests/TestSilabsTestEventTrigger.cpp index 9871444ffb5..3932e11f65e 100644 --- a/examples/platform/silabs/tests/TestSilabsTestEventTrigger.cpp +++ b/examples/platform/silabs/tests/TestSilabsTestEventTrigger.cpp @@ -19,7 +19,6 @@ #include #include -#include #include using namespace chip; @@ -34,9 +33,37 @@ const uint8_t kInvalidEnableKey[TestEventTriggerDelegate::kEnableKeyLength - 1] 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; const uint8_t kZeroEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0 }; -class ProviderStub : public ProvisionedDataProvider +class StorageReaderStub : public IProvisionStorageReader { public: + CHIP_ERROR GetSerialNumber(char *, size_t) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetVendorId(uint16_t &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetVendorName(char *, size_t) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetProductId(uint16_t &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetProductName(char *, size_t) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetProductLabel(char *, size_t) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetProductURL(char *, size_t) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetPartNumber(char *, size_t) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetHardwareVersion(uint16_t &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetHardwareVersionString(char *, size_t) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetManufacturingDate(uint8_t *, size_t, size_t &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetPersistentUniqueId(uint8_t *, size_t, size_t &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetSetupDiscriminator(uint16_t &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetSpake2pIterationCount(uint32_t &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetSpake2pSalt(char *, size_t, size_t &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetSpake2pVerifier(char *, size_t, size_t &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetSetupPayload(uint8_t *, size_t, size_t &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetFirmwareInformation(MutableByteSpan &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetCertificationDeclaration(MutableByteSpan &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetProductAttestationIntermediateCert(MutableByteSpan &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetDeviceAttestationCert(MutableByteSpan &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetProvisionVersion(char *, size_t, size_t &) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetOtaTlvEncryptionKeyId(uint32_t & value) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR DecryptUsingOtaTlvEncryptionKey(MutableByteSpan & block, uint32_t & ivOffset) override + { + return CHIP_ERROR_NOT_IMPLEMENTED; + } + CHIP_ERROR GetTestEventTriggerKey(MutableByteSpan & keySpan) override { VerifyOrReturnError(!forceError, CHIP_ERROR_INTERNAL); @@ -56,17 +83,6 @@ class ProviderStub : public ProvisionedDataProvider void SetForceError(bool value) { forceError = value; } - CHIP_ERROR GetOtaTlvEncryptionKeyId(uint32_t & value) override - { - value = 0; - return CHIP_NO_ERROR; - } - - CHIP_ERROR DecryptUsingOtaTlvEncryptionKey(MutableByteSpan & block, uint32_t & ivOffset) override - { - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; - } - private: uint8_t mEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0 }; bool forceError = false; @@ -77,7 +93,7 @@ class ProviderStub : public ProvisionedDataProvider // Test that a valid key matches TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_ValidKey) { - ProviderStub provider; + StorageReaderStub provider; provider.SetEnableKey(kTestEnableKey1, TestEventTriggerDelegate::kEnableKeyLength); SilabsTestEventTriggerDelegate delegate; @@ -90,7 +106,7 @@ TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_ValidKey) // Test that an invalid key does not match TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_InvalidKey) { - ProviderStub provider; + StorageReaderStub provider; provider.SetEnableKey(kTestEnableKey1, TestEventTriggerDelegate::kEnableKeyLength); SilabsTestEventTriggerDelegate delegate; @@ -103,7 +119,7 @@ TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_InvalidKey) // Test that an empty key does not match TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_EmptyKey) { - ProviderStub provider; + StorageReaderStub provider; provider.SetEnableKey(kTestEnableKey1, TestEventTriggerDelegate::kEnableKeyLength); SilabsTestEventTriggerDelegate delegate; @@ -115,7 +131,7 @@ TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_EmptyKey) // Test that a different valid key does not match TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_DifferentValidKey) { - ProviderStub provider; + StorageReaderStub provider; provider.SetEnableKey(kTestEnableKey1, TestEventTriggerDelegate::kEnableKeyLength); SilabsTestEventTriggerDelegate delegate; @@ -128,7 +144,7 @@ TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_DifferentValidKe // Test that an empty key matchs when no enable key is set TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_NoKeySet_EmptyKey) { - ProviderStub provider; + StorageReaderStub provider; SilabsTestEventTriggerDelegate delegate; TEMPORARY_RETURN_IGNORED delegate.Init(&provider); @@ -139,7 +155,7 @@ TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_NoKeySet_EmptyKe // Test that a valid key does not match when no enable key is set TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_NoKeySet_ValidKey) { - ProviderStub provider; + StorageReaderStub provider; SilabsTestEventTriggerDelegate delegate; TEMPORARY_RETURN_IGNORED delegate.Init(&provider); @@ -177,7 +193,7 @@ TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_NoStorage_EmptyK // Test that a valid key does not match when GetTestEventTriggerKey returns an error TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_GetKeyError_ValidKey) { - ProviderStub provider; + StorageReaderStub provider; provider.SetForceError(true); SilabsTestEventTriggerDelegate delegate; @@ -190,7 +206,7 @@ TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_GetKeyError_Vali // Test that an invalid key does not match when GetTestEventTriggerKey returns an error TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_GetKeyError_InvalidKey) { - ProviderStub provider; + StorageReaderStub provider; provider.SetForceError(true); SilabsTestEventTriggerDelegate delegate; @@ -203,7 +219,7 @@ TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_GetKeyError_Inva // Test that an empty key matchs when GetTestEventTriggerKey returns an error TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_GetKeyError_EmptyKey) { - ProviderStub provider; + StorageReaderStub provider; provider.SetForceError(true); SilabsTestEventTriggerDelegate delegate; @@ -215,7 +231,7 @@ TEST(TestSilabsTestEventTriggerDelegate, TestDoesEnableKeyMatch_GetKeyError_Empt // Test that Init function initializes the delegate with a valid provider TEST(TestSilabsTestEventTriggerDelegate, TestInit_ValidProvider) { - ProviderStub provider; + StorageReaderStub provider; SilabsTestEventTriggerDelegate delegate; EXPECT_EQ(delegate.Init(&provider), CHIP_NO_ERROR); } diff --git a/examples/platform/silabs/zephyr/AppTaskBase.cpp b/examples/platform/silabs/zephyr/AppTaskBase.cpp index bbfe914e4c0..ef7cccbe0eb 100644 --- a/examples/platform/silabs/zephyr/AppTaskBase.cpp +++ b/examples/platform/silabs/zephyr/AppTaskBase.cpp @@ -20,7 +20,8 @@ #include "CHIPDeviceManager.h" #include "CommonDeviceCallbacks.h" #if CONFIG_CHIP_FACTORY_DATA -#include "headers/ProvisionStorage.h" +#include +#include #endif #include @@ -453,11 +454,11 @@ void chip::Zephyr::App::AppTaskBase::PrintCurrentVersion() CHIP_ERROR chip::Zephyr::App::AppTaskBase::InitFactoryDataProvider(void) { #if CONFIG_CHIP_FACTORY_DATA - static Silabs::Provision::Storage sStorage; - ReturnErrorOnFailure(sStorage.Initialize()); - SetDeviceInstanceInfoProvider(&sStorage); - SetDeviceAttestationCredentialsProvider(&sStorage); - SetCommissionableDataProvider(&sStorage); + ReturnErrorOnFailure(Internal::ZephyrConfig::Init()); + auto & storageReader = Silabs::Provision::ProvisionStorageReader::GetInstance(); + SetDeviceInstanceInfoProvider(&storageReader); + SetDeviceAttestationCredentialsProvider(&storageReader); + SetCommissionableDataProvider(&storageReader); #else SetDeviceInstanceInfoProvider(&DeviceInstanceInfoProviderMgrImpl()); SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); diff --git a/src/platform/silabs/MigrationManager.cpp b/src/platform/silabs/MigrationManager.cpp index db588608f72..4a8576fe814 100644 --- a/src/platform/silabs/MigrationManager.cpp +++ b/src/platform/silabs/MigrationManager.cpp @@ -189,6 +189,7 @@ void MigrateS3Certificates() if (CHIP_NO_ERROR == SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_Creds_Base_Addr, credsBaseAddr) && (credsBaseAddr >= tokenStartAddr && credsBaseAddr < secondPageAddr)) { +#if SL_MATTER_PROVISION_CHANNEL_ENABLED uint32_t cdSize = 0; uint32_t dacSize = 0; uint32_t paiSize = 0; @@ -230,6 +231,10 @@ void MigrateS3Certificates() ReturnOnFailure(provision.GetStorage().SetDeviceAttestationCert(dacBufferSpan)); ReturnOnFailure(provision.GetStorage().SetProductAttestationIntermediateCert(paiBufferSpan)); ReturnOnFailure(provision.GetStorage().SetCertificationDeclaration(cdBufferSpan)); +#else + ChipLogError(NotSpecified, "Your credentials must be migrated. This requires this require the ProvisionStorageWriter"); + chipAbort(); +#endif // SL_MATTER_PROVISION_CHANNEL_ENABLED } #endif //_SILICON_LABS_32B_SERIES_3 } diff --git a/src/platform/silabs/SilabsConfig.h b/src/platform/silabs/SilabsConfig.h index cbe8ea7e96f..14dd3035771 100644 --- a/src/platform/silabs/SilabsConfig.h +++ b/src/platform/silabs/SilabsConfig.h @@ -136,7 +136,7 @@ class SilabsConfig static constexpr Key kConfigKey_VendorName = SilabsConfigKey(kMatterFactory_KeyBase, 0x0D); static constexpr Key kConfigKey_ProductName = SilabsConfigKey(kMatterFactory_KeyBase, 0x0E); static constexpr Key kConfigKey_HardwareVersionString = SilabsConfigKey(kMatterFactory_KeyBase, 0x0F); - static constexpr Key KConfigKey_ProductLabel = SilabsConfigKey(kMatterFactory_KeyBase, 0x10); + static constexpr Key kConfigKey_ProductLabel = SilabsConfigKey(kMatterFactory_KeyBase, 0x10); static constexpr Key kConfigKey_ProductURL = SilabsConfigKey(kMatterFactory_KeyBase, 0x11); static constexpr Key kConfigKey_PartNumber = SilabsConfigKey(kMatterFactory_KeyBase, 0x12); static constexpr Key kConfigKey_CACerts = SilabsConfigKey(kMatterFactory_KeyBase, 0x13); diff --git a/src/platform/silabs/efr32/BLEManagerImpl.cpp b/src/platform/silabs/efr32/BLEManagerImpl.cpp index 38942a3394e..aa8dfedc87b 100644 --- a/src/platform/silabs/efr32/BLEManagerImpl.cpp +++ b/src/platform/silabs/efr32/BLEManagerImpl.cpp @@ -61,8 +61,9 @@ extern "C" { #include #endif -#include +#if SL_MATTER_PROVISION_CHANNEL_ENABLED #include +#endif // SL_MATTER_PROVISION_CHANNEL_ENABLED using namespace ::chip; using namespace ::chip::Ble; @@ -892,20 +893,24 @@ BLEManagerImpl::EventFilter BLEManagerImpl::HandleWriteEvent(volatile sl_bt_msg_ { eventFilter = EventFilter::MatterReservedEvent; uint16_t attribute = evt->data.evt_gatt_server_user_write_request.characteristic; - bool do_provision = chip::DeviceLayer::Silabs::Provision::Manager::GetInstance().IsProvisionRequired(); ChipLogProgress(DeviceLayer, "Char Write Req, char : %d", attribute); if (gattdb_CHIPoBLEChar_Rx == attribute) { - if (do_provision) +#if SL_MATTER_PROVISION_CHANNEL_ENABLED + auto & provisionManager = ::chip::DeviceLayer::Silabs::Provision::Manager::GetInstance(); + if (provisionManager.IsProvisionRequired()) { - TEMPORARY_RETURN_IGNORED chip::DeviceLayer::Silabs::Provision::Channel::Update(attribute); - chip::DeviceLayer::Silabs::Provision::Manager::GetInstance().Step(); + TEMPORARY_RETURN_IGNORED provisionManager.OnChannelDataAvailable(); + provisionManager.Step(); } else { HandleRXCharWrite(evt); } +#else + HandleRXCharWrite(evt); +#endif // SL_MATTER_PROVISION_CHANNEL_ENABLED } } else if (isMATTERoBLECharacteristic(evt->data.evt_gatt_server_user_write_request.characteristic)) diff --git a/src/platform/silabs/multi-ota/BUILD.gn b/src/platform/silabs/multi-ota/BUILD.gn index 2671d647611..a4cab47c2ef 100644 --- a/src/platform/silabs/multi-ota/BUILD.gn +++ b/src/platform/silabs/multi-ota/BUILD.gn @@ -49,6 +49,15 @@ source_set("multi-ota-common") { "OTATlvProcessor.cpp", ] deps = [ "${chip_root}/src/app/clusters/ota-requestor:interface" ] + + # OTAFactoryDataProcessor only uses the IProvisionStorageWriter and + # IProvisionCrypto interfaces from ${sl_provision_root}:headers; the concrete + # backends are injected by the application through OTAMultiImageProcessorImpl::Init. + # Only the encrypted TLV path (OTATlvProcessor.cpp) still reaches into the + # concrete provision storage reader. + if (chip_enable_multi_ota_encryption) { + deps += [ "${chip_root}/examples/platform/silabs/provision:storage" ] + } public_deps = [ "${chip_root}/src/lib/core", "${chip_root}/src/lib/support", diff --git a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp index 0afb6a76cec..7fc7dfd6fb4 100644 --- a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp +++ b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.cpp @@ -66,7 +66,7 @@ CHIP_ERROR OTAFactoryDataProcessor::ApplyAction() } else { - error = Provision::Manager::GetInstance().GetStorage().Commit(); + error = mStorageWriter.Commit(); VerifyOrReturnError(error == CHIP_NO_ERROR, error, ChipLogError(SoftwareUpdate, "Failed to commit factory data. Error: %s", ErrorStr(error))); } @@ -135,16 +135,16 @@ CHIP_ERROR OTAFactoryDataProcessor::UpdateValue(uint8_t tag, ByteSpan & newValue { case (int) FactoryTags::kDacKey: ChipLogDetail(SoftwareUpdate, "Set Device Attestation Key"); - return Provision::Manager::GetInstance().GetStorage().SetDeviceAttestationKey(newValue); + return mCrypto.ImportDeviceAttestationKey(newValue); case (int) FactoryTags::kDacCert: ChipLogDetail(SoftwareUpdate, "Set Device Attestation Cert"); - return Provision::Manager::GetInstance().GetStorage().SetDeviceAttestationCert(newValue); + return mStorageWriter.SetDeviceAttestationCert(newValue); case (int) FactoryTags::kPaiCert: ChipLogDetail(SoftwareUpdate, "Set Product Attestation Intermediate Cert"); - return Provision::Manager::GetInstance().GetStorage().SetProductAttestationIntermediateCert(newValue); + return mStorageWriter.SetProductAttestationIntermediateCert(newValue); case (int) FactoryTags::kCdCert: ChipLogDetail(SoftwareUpdate, "Set Certification Declaration"); - return Provision::Manager::GetInstance().GetStorage().SetCertificationDeclaration(newValue); + return mStorageWriter.SetCertificationDeclaration(newValue); } ChipLogError(DeviceLayer, "Failed to find tag %d.", tag); diff --git a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h index 05fe9081cb7..8a1214f028e 100644 --- a/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h +++ b/src/platform/silabs/multi-ota/OTAFactoryDataProcessor.h @@ -18,8 +18,8 @@ #pragma once -#include -#include +#include +#include #include #include #include @@ -65,6 +65,16 @@ enum class FactoryTags : uint8_t class OTAFactoryDataProcessor : public OTATlvProcessor { public: + /** + * @param storageWriter Backend that persists the attestation certificates and commits the update. + * @param crypto Backend that imports the device attestation private key. + * + * Both references must outlive the processor. + */ + OTAFactoryDataProcessor(Provision::IProvisionStorageWriter & storageWriter, Provision::IProvisionCrypto & crypto) : + mStorageWriter(storageWriter), mCrypto(crypto) + {} + CHIP_ERROR ApplyAction() override; CHIP_ERROR FinalizeAction() override; @@ -74,6 +84,8 @@ class OTAFactoryDataProcessor : public OTATlvProcessor CHIP_ERROR Update(uint8_t tag, Optional & optional); CHIP_ERROR UpdateValue(uint8_t tag, ByteSpan & newValue); + Provision::IProvisionStorageWriter & mStorageWriter; + Provision::IProvisionCrypto & mCrypto; OTAFactoryPayload mPayload; uint8_t * mFactoryData = nullptr; diff --git a/src/platform/silabs/multi-ota/OTAHooks.cpp b/src/platform/silabs/multi-ota/OTAHooks.cpp index 76d8d552516..5e92534be25 100644 --- a/src/platform/silabs/multi-ota/OTAHooks.cpp +++ b/src/platform/silabs/multi-ota/OTAHooks.cpp @@ -44,11 +44,12 @@ CHIP_ERROR OTAMultiImageProcessorImpl::ProcessDescriptor(void * descriptor) return CHIP_NO_ERROR; } -CHIP_ERROR OTAMultiImageProcessorImpl::OtaHookInit() +CHIP_ERROR OTAMultiImageProcessorImpl::OtaHookInit(chip::DeviceLayer::Silabs::Provision::IProvisionStorageWriter & storageWriter, + chip::DeviceLayer::Silabs::Provision::IProvisionCrypto & crypto) { auto & imageProcessor = OTAMultiImageProcessorImpl::GetDefaultInstance(); - static OTAFactoryDataProcessor sFactoryDataProcessor; + static OTAFactoryDataProcessor sFactoryDataProcessor(storageWriter, crypto); sFactoryDataProcessor.RegisterDescriptorCallback(ProcessDescriptor); ReturnErrorOnFailure(imageProcessor.RegisterProcessor(OTAProcessorTag::kFactoryDataProcessor, &sFactoryDataProcessor)); diff --git a/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.cpp b/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.cpp index 97d88be179a..6d85b4ea288 100644 --- a/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.cpp +++ b/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.cpp @@ -43,13 +43,14 @@ namespace DeviceLayer { namespace Silabs { namespace MultiOTA { -CHIP_ERROR OTAMultiImageProcessorImpl::Init(OTADownloader * downloader) +CHIP_ERROR OTAMultiImageProcessorImpl::Init(OTADownloader * downloader, Provision::IProvisionStorageWriter & storageWriter, + Provision::IProvisionCrypto & crypto) { VerifyOrReturnError(downloader != nullptr, CHIP_ERROR_INVALID_ARGUMENT); gImageProcessor.SetOTADownloader(downloader); - return OtaHookInit(); + return OtaHookInit(storageWriter, crypto); } void OTAMultiImageProcessorImpl::Clear() diff --git a/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.h b/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.h index 84c99c98b45..2d2579a36f6 100644 --- a/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.h +++ b/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.h @@ -20,6 +20,8 @@ #include #include +#include +#include #include #include #include @@ -41,8 +43,16 @@ class OTAMultiImageProcessorImpl : public chip::OTAImageProcessorInterface public: using ProviderLocation = chip::OTARequestorInterface::ProviderLocationType; - CHIP_ERROR Init(OTADownloader * downloader); - CHIP_ERROR OtaHookInit(); + /** + * @param downloader OTA downloader feeding image blocks to this processor. + * @param storageWriter Backend used by the factory data processor to persist attestation credentials. + * @param crypto Backend used by the factory data processor to import the attestation key. + * + * The backends must outlive the processor; applications typically pass their singletons. + */ + CHIP_ERROR Init(OTADownloader * downloader, Provision::IProvisionStorageWriter & storageWriter, + Provision::IProvisionCrypto & crypto); + CHIP_ERROR OtaHookInit(Provision::IProvisionStorageWriter & storageWriter, Provision::IProvisionCrypto & crypto); static CHIP_ERROR ProcessDescriptor(void * descriptor); void Clear(); diff --git a/src/platform/silabs/multi-ota/OTATlvProcessor.cpp b/src/platform/silabs/multi-ota/OTATlvProcessor.cpp index b2548687d90..8dde463a022 100644 --- a/src/platform/silabs/multi-ota/OTATlvProcessor.cpp +++ b/src/platform/silabs/multi-ota/OTATlvProcessor.cpp @@ -20,12 +20,11 @@ #include #include -#include -#include #include #include -#if SL_MATTER_ENABLE_OTA_ENCRYPTION +#if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION #include +#include #endif using namespace ::chip::DeviceLayer::Internal; @@ -148,11 +147,12 @@ CHIP_ERROR OTADataAccumulator::Accumulate(ByteSpan & block) #if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION CHIP_ERROR OTATlvProcessor::vOtaProcessInternalEncryption(MutableByteSpan & block) { + auto & storageReader = Provision::ProvisionStorageReader::GetInstance(); #if defined(SL_MBEDTLS_USE_TINYCRYPT) - ReturnErrorOnFailure(Provision::Manager::GetInstance().GetStorage().DecryptUsingOtaTlvEncryptionKey(block, mIVOffset)); + ReturnErrorOnFailure(storageReader.DecryptUsingOtaTlvEncryptionKey(block, mIVOffset)); #else // MBEDTLS_USE_PSA_CRYPTO uint32_t keyId; - ReturnErrorOnFailure(Provision::Manager::GetInstance().GetStorage().GetOtaTlvEncryptionKeyId(keyId)); + ReturnErrorOnFailure(storageReader.GetOtaTlvEncryptionKeyId(keyId)); chip::DeviceLayer::Silabs::OtaTlvEncryptionKey key(keyId); ReturnErrorOnFailure(key.Decrypt(block, mIVOffset)); diff --git a/src/test_driver/efr32/BUILD.gn b/src/test_driver/efr32/BUILD.gn index 970405fd918..7d712a61d5d 100644 --- a/src/test_driver/efr32/BUILD.gn +++ b/src/test_driver/efr32/BUILD.gn @@ -80,9 +80,6 @@ source_set("efr32_test_main") { "${chip_root}/examples/common/pigweed/RpcService.cpp", "${chip_root}/examples/common/pigweed/efr32/PigweedLoggerMutex.cpp", "${examples_common_plat_dir}/PigweedLogger.cpp", - "${examples_common_plat_dir}/provision/ProvisionStorageCommon.cpp", - "${examples_common_plat_dir}/provision/ProvisionStorageCustom.cpp", - "${examples_common_plat_dir}/provision/ProvisionStorageDefault.cpp", "${examples_common_plat_dir}/syscalls_stubs.cpp", "${examples_common_plat_dir}/uart.cpp", "src/main.cpp", @@ -94,6 +91,7 @@ source_set("efr32_test_main") { "$dir_pw_unit_test:rpc_service", "${chip_root}/config/efr32/lib/pw_rpc:pw_rpc", "${chip_root}/examples/common/pigweed:system_rpc_server", + "${chip_root}/examples/platform/silabs/provision:storage", "${chip_root}/src/lib", "${chip_root}/src/lib/support:pw_tests_wrapper", "${examples_common_plat_dir}/pw_sys_io:pw_sys_io_silabs", @@ -111,10 +109,6 @@ source_set("efr32_test_main") { deps += pw_build_LINK_DEPS - libs = [ - "${matter_support_root}/provision/libs/libProvision-${silabs_family}.a", - ] - include_dirs = [ "${chip_root}/examples/common/pigweed/efr32" ] public_configs = [ ":efr32_ldflags" ] } diff --git a/src/test_driver/efr32/src/main.cpp b/src/test_driver/efr32/src/main.cpp index cadb68d4f0d..0c3a0d5d06f 100644 --- a/src/test_driver/efr32/src/main.cpp +++ b/src/test_driver/efr32/src/main.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -34,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -103,11 +103,9 @@ int main(void) Platform::MemoryInit(); PlatformMgr().InitChipStack(); - // Init Provision Manager and provider instanaces. Required for inits tied to the event loop - Silabs::Provision::Manager & provision = Silabs::Provision::Manager::GetInstance(); - provision.Init(); - SetDeviceInstanceInfoProvider(&provision.GetStorage()); - SetCommissionableDataProvider(&provision.GetStorage()); + auto & storageReader = Silabs::Provision::ProvisionStorageReader::GetInstance(); + SetDeviceInstanceInfoProvider(&storageReader); + SetCommissionableDataProvider(&storageReader); ChipLogProgress(AppServer, "***** CHIP EFR32 device tests *****\r\n"); diff --git a/third_party/silabs/SiWx917_sdk.gni b/third_party/silabs/SiWx917_sdk.gni index 95bf2690bfc..3a83d4df0a8 100644 --- a/third_party/silabs/SiWx917_sdk.gni +++ b/third_party/silabs/SiWx917_sdk.gni @@ -311,6 +311,12 @@ template("siwx917_sdk") { defines += [ "SL_MATTER_USE_SI70XX_SENSOR=${sl_enable_si70xx_sensor}" ] + if (sl_use_provision_channel) { + defines += [ "SL_MATTER_PROVISION_CHANNEL_ENABLED=1" ] + } else { + defines += [ "SL_MATTER_PROVISION_CHANNEL_ENABLED=0" ] + } + if (silabs_log_enabled && chip_logging) { defines += [ "SILABS_LOG_ENABLED=1" ] } else { @@ -597,7 +603,7 @@ template("siwx917_sdk") { config("siwx917_tinycrypt_config") { defines = [ - "SL_MBEDTLS_USE_TINYCRYPT", + "SL_MBEDTLS_USE_TINYCRYPT=1", "MBEDTLS_CONFIG_FILE=", ] diff --git a/third_party/silabs/efr32_sdk.gni b/third_party/silabs/efr32_sdk.gni index 19081eb1a46..4df97cf4c2b 100644 --- a/third_party/silabs/efr32_sdk.gni +++ b/third_party/silabs/efr32_sdk.gni @@ -91,6 +91,9 @@ declare_args() { # Factory Provision storage use_provision_flash_storage = wifi_soc + # Enable the factory provisioning channel (BLE) used to write provision data + sl_use_provision_channel = false + # Enable TestEventTrigger in GeneralDiagnostics cluster sl_enable_test_event_trigger = false @@ -659,6 +662,12 @@ template("efr32_sdk") { defines += [ "SL_MATTER_PROVISION_FLASH=0" ] } + if (sl_use_provision_channel) { + defines += [ "SL_MATTER_PROVISION_CHANNEL_ENABLED=1" ] + } else { + defines += [ "SL_MATTER_PROVISION_CHANNEL_ENABLED=0" ] + } + if (defined(invoker.chip_enable_thread) && invoker.chip_enable_thread) { defines += [ "SL_OT_ENABLE=1" ] } diff --git a/third_party/silabs/matter_support b/third_party/silabs/matter_support index 2f041d85a9d..a4436ce36e1 160000 --- a/third_party/silabs/matter_support +++ b/third_party/silabs/matter_support @@ -1 +1 @@ -Subproject commit 2f041d85a9dde7c03d5adba64e67b9789a3ecf26 +Subproject commit a4436ce36e11098c8ef238497f67c5ab388c8e74