From f2b51a5a7ada7ee7657fe175c2ad52110295c70a Mon Sep 17 00:00:00 2001 From: Junior Martinez <67972863+jmartinez-silabs@users.noreply.github.com> Date: Wed, 7 Oct 2026 18:04:03 -0400 Subject: [PATCH 1/7] [Silabs]Restructure Silabs Matter Provisioning implementation. (#74613) * Restructure our Provisioning implementation. This commit restructures the Provisioning implementation to use a more modular approach. Create interfaces splitting each feature into a separate class to call into the core library. The core library is now much more concise and easier to maintain. Offer implementations for each interface that are used by our platform. User could implement their own version of the interfaces to use their own storage, crypto, etc. * Add fix to issue found by copilot * Fix some issues flagged by coderabbit * Update OTAMultiImage to leverage new provision interface. Fix other misc issues * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Potential fix for pull request finding 'Remove trailing backtick from preprocessor directive' Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Fix a conercase with multiota * Address reviewer comments * Bump matter_support to commit merged in offical branch --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- config/silabs/Kconfig | 123 +-- examples/lighting-app/silabs/openthread.gn | 2 +- .../lighting-app/silabs/zephyr/CMakeLists.txt | 6 +- examples/platform/silabs/BaseApplication.cpp | 12 +- examples/platform/silabs/MatterConfig.cpp | 46 +- examples/platform/silabs/OTAConfig.cpp | 14 +- examples/platform/silabs/provision/BUILD.gn | 92 +- .../silabs/provision/ProvisionChannel.h | 34 + .../provision/ProvisionChannelEFR32BLE.cpp | 64 ++ .../silabs/provision/ProvisionChannelRTT.cpp | 63 ++ .../provision/ProvisionChannelSi917BLE.cpp | 41 + .../silabs/provision/ProvisionCrypto.h | 36 + .../silabs/provision/ProvisionCryptoMbed.cpp | 247 +++++ .../silabs/provision/ProvisionCryptoPSA.cpp | 276 ++++++ .../provision/ProvisionStorageCommon.cpp | 186 ---- .../provision/ProvisionStorageDefault.cpp | 788 ---------------- .../provision/ProvisionStorageFlash.cpp | 856 ------------------ .../silabs/provision/ProvisionStorageReader.h | 112 +++ .../ProvisionStorageReaderCommon.cpp | 246 +++++ .../silabs/provision/ProvisionStorageWriter.h | 87 ++ .../provision/ProvisionStorageZephyr.cpp | 580 ------------ .../default/ProvisionStorageReader.cpp | 398 ++++++++ .../default/ProvisionStorageWriter.cpp | 312 +++++++ .../provision/flash/ProvisionStorageFlash.cpp | 330 +++++++ .../provision/flash/ProvisionStorageFlash.h | 47 + .../flash/ProvisionStorageReader.cpp | 348 +++++++ .../flash/ProvisionStorageWriter.cpp | 206 +++++ .../zephyr/ProvisionStorageReader.cpp | 237 +++++ .../zephyr/ProvisionStorageWriter.cpp | 235 +++++ .../provision/zephyr/ProvisionStorageZephyr.h | 75 ++ .../SilabsTestEventTriggerDelegate.cpp | 12 +- .../SilabsTestEventTriggerDelegate.h | 12 +- .../tests/TestSilabsTestEventTrigger.cpp | 62 +- .../platform/silabs/zephyr/AppTaskBase.cpp | 13 +- src/platform/silabs/SilabsConfig.h | 2 +- src/platform/silabs/efr32/BLEManagerImpl.cpp | 15 +- src/platform/silabs/multi-ota/BUILD.gn | 9 + .../multi-ota/OTAFactoryDataProcessor.cpp | 10 +- .../multi-ota/OTAFactoryDataProcessor.h | 16 +- src/platform/silabs/multi-ota/OTAHooks.cpp | 5 +- .../multi-ota/OTAMultiImageProcessorImpl.cpp | 5 +- .../multi-ota/OTAMultiImageProcessorImpl.h | 14 +- .../silabs/multi-ota/OTATlvProcessor.cpp | 10 +- src/test_driver/efr32/BUILD.gn | 8 +- src/test_driver/efr32/src/main.cpp | 10 +- third_party/silabs/SiWx917_sdk.gni | 8 +- third_party/silabs/efr32_sdk.gni | 9 + 47 files changed, 3718 insertions(+), 2601 deletions(-) create mode 100644 examples/platform/silabs/provision/ProvisionChannel.h create mode 100644 examples/platform/silabs/provision/ProvisionChannelEFR32BLE.cpp create mode 100644 examples/platform/silabs/provision/ProvisionChannelRTT.cpp create mode 100644 examples/platform/silabs/provision/ProvisionChannelSi917BLE.cpp create mode 100644 examples/platform/silabs/provision/ProvisionCrypto.h create mode 100644 examples/platform/silabs/provision/ProvisionCryptoMbed.cpp create mode 100644 examples/platform/silabs/provision/ProvisionCryptoPSA.cpp delete mode 100644 examples/platform/silabs/provision/ProvisionStorageCommon.cpp delete mode 100644 examples/platform/silabs/provision/ProvisionStorageDefault.cpp delete mode 100644 examples/platform/silabs/provision/ProvisionStorageFlash.cpp create mode 100644 examples/platform/silabs/provision/ProvisionStorageReader.h create mode 100644 examples/platform/silabs/provision/ProvisionStorageReaderCommon.cpp create mode 100644 examples/platform/silabs/provision/ProvisionStorageWriter.h delete mode 100644 examples/platform/silabs/provision/ProvisionStorageZephyr.cpp create mode 100644 examples/platform/silabs/provision/default/ProvisionStorageReader.cpp create mode 100644 examples/platform/silabs/provision/default/ProvisionStorageWriter.cpp create mode 100644 examples/platform/silabs/provision/flash/ProvisionStorageFlash.cpp create mode 100644 examples/platform/silabs/provision/flash/ProvisionStorageFlash.h create mode 100644 examples/platform/silabs/provision/flash/ProvisionStorageReader.cpp create mode 100644 examples/platform/silabs/provision/flash/ProvisionStorageWriter.cpp create mode 100644 examples/platform/silabs/provision/zephyr/ProvisionStorageReader.cpp create mode 100644 examples/platform/silabs/provision/zephyr/ProvisionStorageWriter.cpp create mode 100644 examples/platform/silabs/provision/zephyr/ProvisionStorageZephyr.h 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/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..f519a25c713 100644 --- a/examples/platform/silabs/provision/BUILD.gn +++ b/examples/platform/silabs/provision/BUILD.gn @@ -14,57 +14,90 @@ 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}" ] + + # 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 +107,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..14866c2b5f5 --- /dev/null +++ b/examples/platform/silabs/provision/ProvisionCryptoMbed.cpp @@ -0,0 +1,247 @@ +/* + * 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 + +#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) +{ + size_t size = 0; + ReturnErrorOnFailure(SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_Creds_KeyId, key.data(), key.size(), size)); + key.reduce_size(size); + return CHIP_NO_ERROR; +} + +#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 SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_Creds_KeyId, key.data(), key.size()); +} + +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 SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_Creds_KeyId, encodedKey + sizeof(encodedKey) - encodedSize, + 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..60bb3d434c2 --- /dev/null +++ b/examples/platform/silabs/provision/default/ProvisionStorageReader.cpp @@ -0,0 +1,398 @@ +/* + * 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 +#include + +#ifndef NDEBUG +#if defined(SL_MATTER_TEST_EVENT_TRIGGER_ENABLED) && (SL_MATTER_GN_BUILD == 0) +#include +#endif +#endif + +#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..12939653ef2 --- /dev/null +++ b/examples/platform/silabs/provision/default/ProvisionStorageWriter.cpp @@ -0,0 +1,312 @@ +/* + * 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 + +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..a2d08f0e270 --- /dev/null +++ b/examples/platform/silabs/provision/flash/ProvisionStorageReader.cpp @@ -0,0 +1,348 @@ +/* + * 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 +#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..dad4ef02a29 --- /dev/null +++ b/examples/platform/silabs/provision/flash/ProvisionStorageWriter.cpp @@ -0,0 +1,206 @@ +/* + * 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/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" ] } From 8538ccfdf2cd9396ccca98c16a6c91a29575e5a3 Mon Sep 17 00:00:00 2001 From: Junior Martinez Date: Sun, 11 Oct 2026 12:00:21 -0400 Subject: [PATCH 2/7] Point matter_support to commit goin to 2.10 branch --- third_party/silabs/matter_support | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/silabs/matter_support b/third_party/silabs/matter_support index 2f041d85a9d..f7d534c811a 160000 --- a/third_party/silabs/matter_support +++ b/third_party/silabs/matter_support @@ -1 +1 @@ -Subproject commit 2f041d85a9dde7c03d5adba64e67b9789a3ecf26 +Subproject commit f7d534c811a629e55ab89a3feb2c0534a075c9e0 From defbb13f683c692f271b3ef60d520ef2afdb02b0 Mon Sep 17 00:00:00 2001 From: Junior Martinez <67972863+jmartinez-silabs@users.noreply.github.com> Date: Sun, 11 Oct 2026 13:05:44 -0400 Subject: [PATCH 3/7] [Silabs] Fix 917 Flash ProvisionStorage (#74702) * Fix for 917 provisionCrypto with provision flash * [Silabs] Fix 917 Flash provisionStorage. Add condition statement to fix slc based builds * Restyled by gn --------- Co-authored-by: Restyled.io --- examples/platform/silabs/provision/BUILD.gn | 6 +++-- .../silabs/provision/ProvisionCryptoMbed.cpp | 27 ++++++++++++++++--- .../default/ProvisionStorageReader.cpp | 15 ++++++++--- .../default/ProvisionStorageWriter.cpp | 5 +++- .../flash/ProvisionStorageReader.cpp | 14 +++++++++- .../flash/ProvisionStorageWriter.cpp | 2 ++ 6 files changed, 58 insertions(+), 11 deletions(-) diff --git a/examples/platform/silabs/provision/BUILD.gn b/examples/platform/silabs/provision/BUILD.gn index f519a25c713..2246eedd30a 100644 --- a/examples/platform/silabs/provision/BUILD.gn +++ b/examples/platform/silabs/provision/BUILD.gn @@ -83,8 +83,10 @@ source_set("storage") { } } - defines = - [ "SL_MATTER_ENABLE_EXAMPLE_CREDENTIALS=${sl_use_example_credentials}" ] + 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) { diff --git a/examples/platform/silabs/provision/ProvisionCryptoMbed.cpp b/examples/platform/silabs/provision/ProvisionCryptoMbed.cpp index 14866c2b5f5..fa5d879b2d0 100644 --- a/examples/platform/silabs/provision/ProvisionCryptoMbed.cpp +++ b/examples/platform/silabs/provision/ProvisionCryptoMbed.cpp @@ -17,6 +17,11 @@ #include #endif +#if SL_MATTER_USE_FLASH_STORE +#include +#include +#endif // SL_MATTER_USE_FLASH_STORE + #include #include @@ -64,10 +69,27 @@ CHIP_ERROR FormatMatterOidUtf8DerHex(char * destination, size_t destinationSize, 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 @@ -146,7 +168,7 @@ CHIP_ERROR ProvisionCrypto::Hash256(const ByteSpan & input, MutableByteSpan & ou CHIP_ERROR ProvisionCrypto::ImportDeviceAttestationKey(const ByteSpan & key) { VerifyOrReturnError(!key.empty() && key.size() <= kDeviceAttestationKeySizeMax, CHIP_ERROR_INVALID_ARGUMENT); - return SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_Creds_KeyId, key.data(), key.size()); + return WriteKey(key); } CHIP_ERROR ProvisionCrypto::GenerateDeviceAttestationCSR(uint16_t vid, uint16_t pid, const CharSpan & commonName, @@ -201,8 +223,7 @@ CHIP_ERROR ProvisionCrypto::GenerateDeviceAttestationCSR(uint16_t vid, uint16_t 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 SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_Creds_KeyId, encodedKey + sizeof(encodedKey) - encodedSize, - encodedSize); + return WriteKey(ByteSpan(encodedKey + sizeof(encodedKey) - encodedSize, static_cast(encodedSize))); #endif } diff --git a/examples/platform/silabs/provision/default/ProvisionStorageReader.cpp b/examples/platform/silabs/provision/default/ProvisionStorageReader.cpp index 60bb3d434c2..e94e4b5cf70 100644 --- a/examples/platform/silabs/provision/default/ProvisionStorageReader.cpp +++ b/examples/platform/silabs/provision/default/ProvisionStorageReader.cpp @@ -22,16 +22,23 @@ #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) && (SL_MATTER_GN_BUILD == 0) +#if defined(SL_MATTER_TEST_EVENT_TRIGGER_ENABLED) #include -#endif -#endif +#endif // defined(SL_MATTER_TEST_EVENT_TRIGGER_ENABLED) +#endif // NDEBUG +#endif // !SL_MATTER_GN_BUILD #include diff --git a/examples/platform/silabs/provision/default/ProvisionStorageWriter.cpp b/examples/platform/silabs/provision/default/ProvisionStorageWriter.cpp index 12939653ef2..774e0896bbc 100644 --- a/examples/platform/silabs/provision/default/ProvisionStorageWriter.cpp +++ b/examples/platform/silabs/provision/default/ProvisionStorageWriter.cpp @@ -19,13 +19,16 @@ #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 diff --git a/examples/platform/silabs/provision/flash/ProvisionStorageReader.cpp b/examples/platform/silabs/provision/flash/ProvisionStorageReader.cpp index a2d08f0e270..7d06c1e32eb 100644 --- a/examples/platform/silabs/provision/flash/ProvisionStorageReader.cpp +++ b/examples/platform/silabs/provision/flash/ProvisionStorageReader.cpp @@ -25,9 +25,21 @@ #include #include #include + #if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION #include -#endif +#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 { diff --git a/examples/platform/silabs/provision/flash/ProvisionStorageWriter.cpp b/examples/platform/silabs/provision/flash/ProvisionStorageWriter.cpp index dad4ef02a29..b686c7ed395 100644 --- a/examples/platform/silabs/provision/flash/ProvisionStorageWriter.cpp +++ b/examples/platform/silabs/provision/flash/ProvisionStorageWriter.cpp @@ -19,9 +19,11 @@ #include #include #include + #if defined(SL_MATTER_ENABLE_OTA_ENCRYPTION) && SL_MATTER_ENABLE_OTA_ENCRYPTION #include #endif + namespace chip { namespace DeviceLayer { namespace Silabs { From 6decb57088d3441cd32d90231b327e8553ad6f11 Mon Sep 17 00:00:00 2001 From: Junior Martinez Date: Tue, 13 Oct 2026 23:02:15 -0400 Subject: [PATCH 4/7] Add missing change lost in merge conflict resolution sync commit --- src/platform/silabs/MigrationManager.cpp | 5 +++++ 1 file changed, 5 insertions(+) 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 } From c1657d0eac9d08f2745cd526540ab9aec52d3dd8 Mon Sep 17 00:00:00 2001 From: Junior Martinez Date: Wed, 14 Oct 2026 08:31:24 -0400 Subject: [PATCH 5/7] Update Zephyr all-devices-app CMakeLists with the new provision Reader sources --- examples/all-devices-app/zephyr/silabs/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 From 44bb5ee924e5c05ffb5e076b64a244ffe3132c30 Mon Sep 17 00:00:00 2001 From: Junior Martinez Date: Wed, 14 Oct 2026 09:59:08 -0400 Subject: [PATCH 6/7] use provisionReader in all-device-app --- .../zephyr/silabs/SilabsAppTask.cpp | 18 ++++++++---------- .../zephyr/silabs/SilabsAppTask.h | 6 ++---- 2 files changed, 10 insertions(+), 14 deletions(-) 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 From 86aad89e270fc65163f844e0748fe1bbd1243f96 Mon Sep 17 00:00:00 2001 From: Junior Martinez Date: Thu, 15 Oct 2026 09:20:04 -0400 Subject: [PATCH 7/7] Bump matter_support to merge commit --- third_party/silabs/matter_support | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/silabs/matter_support b/third_party/silabs/matter_support index f7d534c811a..a4436ce36e1 160000 --- a/third_party/silabs/matter_support +++ b/third_party/silabs/matter_support @@ -1 +1 @@ -Subproject commit f7d534c811a629e55ab89a3feb2c0534a075c9e0 +Subproject commit a4436ce36e11098c8ef238497f67c5ab388c8e74