diff --git a/config/nrfconnect/chip-module/CMakeLists.txt b/config/nrfconnect/chip-module/CMakeLists.txt index 2f87e4b01c..9688501d8a 100644 --- a/config/nrfconnect/chip-module/CMakeLists.txt +++ b/config/nrfconnect/chip-module/CMakeLists.txt @@ -192,6 +192,7 @@ endif() if (CONFIG_CHIP_CRYPTO_PSA) matter_add_gn_arg_string("chip_crypto" "psa") matter_add_gn_arg_bool ("chip_crypto_psa_spake2p" CONFIG_PSA_WANT_ALG_SPAKE2P_MATTER) + matter_add_gn_arg_bool ("chip_use_cracen_kmu" CONFIG_CHIP_STORE_KEYS_IN_KMU) endif() if (BOARD STREQUAL "native_posix") diff --git a/config/nrfconnect/chip-module/Kconfig b/config/nrfconnect/chip-module/Kconfig index b785a6d412..d83b1a9d12 100644 --- a/config/nrfconnect/chip-module/Kconfig +++ b/config/nrfconnect/chip-module/Kconfig @@ -397,6 +397,38 @@ config CHIP_CRYPTO_PSA_DAC_PRIV_KEY_KMU_ENCRYPTED endif # CHIP_CRYPTO_PSA_MIGRATE_DAC_PRIV_KEY +config CHIP_STORE_KEYS_IN_KMU + bool "Use KMU to store crypto keys" + depends on CRACEN_LIB_KMU + default y + select EXPERIMENTAL + help + Stores cryptographic materials like keys in the KMU if available on the device. + This option utilizes a custom nRF Connect implementation of PSAKeyAllocator for key + storage. All non-volatile cryptographic materials used by the Matter stack will be + stored in KMU slots. + +if CHIP_STORE_KEYS_IN_KMU + +config CHIP_KMU_SLOT_RANGE_START + int "Starting KMU slot number for Matter crypto materials" + default 100 + help + Defines the starting KMU slot number reserved for storing Matter-related keys. + This configuration does not include the DAC private key. To change DAC private key + location see the CHIP_CRYPTO_PSA_DAC_PRIV_KEY_KMU_SLOT_ID Kconfig. + +config CHIP_KMU_SLOT_RANGE_END + int "Last available KMU slot for Matter crypto materials" + default 175 if CHIP_CRYPTO_PSA_DAC_PRIV_KEY_KMU + default 180 + help + Defines the last available KMU slot for storing Matter-related keys. + This configuration does not include the DAC private key. To change DAC private key + location see the CHIP_CRYPTO_PSA_DAC_PRIV_KEY_KMU_SLOT_ID Kconfig. + +endif # CHIP_STORE_KEYS_IN_KMU + config CHIP_PERSISTENT_SUBSCRIPTIONS default n # selecting experimental for this feature since there is an issue with multiple controllers. diff --git a/config/nrfconnect/chip-module/Kconfig.features b/config/nrfconnect/chip-module/Kconfig.features index 350e67caaa..20d609c709 100644 --- a/config/nrfconnect/chip-module/Kconfig.features +++ b/config/nrfconnect/chip-module/Kconfig.features @@ -288,5 +288,4 @@ config CHIP_LAST_FABRIC_REMOVED_ACTION_DELAY After removing the last fabric the device will wait for the defined time and then perform 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. - endif # CHIP diff --git a/src/platform/nrfconnect/BUILD.gn b/src/platform/nrfconnect/BUILD.gn index 3e5b9c2f9c..80defb149c 100644 --- a/src/platform/nrfconnect/BUILD.gn +++ b/src/platform/nrfconnect/BUILD.gn @@ -132,6 +132,12 @@ static_library("nrfconnect") { sources += [ "../Zephyr/SysHeapMalloc.cpp" ] } + if (chip_use_cracen_kmu) { + sources += [ + "KMUKeyAllocator.h", + ] + } + cflags = [ "-Wconversion" ] } diff --git a/src/platform/nrfconnect/KMUKeyAllocator.h b/src/platform/nrfconnect/KMUKeyAllocator.h new file mode 100644 index 0000000000..12b77d614a --- /dev/null +++ b/src/platform/nrfconnect/KMUKeyAllocator.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2025 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 + +// Define the number of slots per NOC and ICD key. +#define KMU_SLOTS_PER_NOC_KEY 2 +#define KMU_SLOTS_PER_ICD_KEY 2 // ICD KEY means a pair of AES and HMAC keys per fabric +#define KMU_SLOTS_PER_GROUP_KEY 1 + +#define KMU_SLOTS_NOC_MAX_NUMBER (KMU_SLOTS_PER_NOC_KEY * CONFIG_CHIP_MAX_FABRICS) +#define KMU_SLOTS_ICD_MAX_NUMBER (KMU_SLOTS_PER_ICD_KEY * CONFIG_CHIP_MAX_FABRICS * CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC) +#define KMU_SLOTS_GROUP_MAX_NUMBER (KMU_SLOTS_PER_GROUP_KEY * CHIP_CONFIG_MAX_GROUP_KEYS_PER_FABRIC * CONFIG_CHIP_MAX_FABRICS) + +// Check whether the number of slots is within the range of the KMU. +#if ((KMU_SLOTS_NOC_MAX_NUMBER + KMU_SLOTS_ICD_MAX_NUMBER + KMU_SLOTS_GROUP_MAX_NUMBER) > \ + CONFIG_CHIP_KMU_SLOT_RANGE_END - CONFIG_CHIP_KMU_SLOT_RANGE_START) +{ +#pragma message("NOC keys: " STRINGIFY(KMU_SLOTS_NOC_MAX_NUMBER) "+ ICD keys: " STRINGIFY( \ + KMU_SLOTS_ICD_MAX_NUMBER) "+ GROUP keys: " STRINGIFY(KMU_SLOTS_GROUP_MAX_NUMBER) ">" STRINGIFY(KMU_AVAILABLE_MATTER_SLOTS)) +#error \ + "The number of slots exceeds the range of the KMU defined in CONFIG_CHIP_KMU_SLOT_RANGE_START and CONFIG_CHIP_KMU_SLOT_RANGE_END" +} +#endif + +// Define the start of the KMU slots for Matter. +#define KMU_NOC_SLOT_START PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, CONFIG_CHIP_KMU_SLOT_RANGE_START) +#define KMU_ICD_SLOT_START \ + PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, (KMU_NOC_SLOT_START + KMU_SLOTS_NOC_MAX_NUMBER)) +#define KMU_GROUP_KEYS_SLOT_START \ + PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, (KMU_ICD_SLOT_START + KMU_SLOTS_ICD_MAX_NUMBER)) + +// Check whether the DAC KMU slot doesn not overlap with the KMU slots dedicated for Matter core. +#if defined(CONFIG_CHIP_CRYPTO_PSA_DAC_PRIV_KEY_KMU) && \ + (CONFIG_CHIP_CRYPTO_PSA_DAC_PRIV_KEY_KMU_SLOT_ID >= CONFIG_CHIP_KMU_SLOT_RANGE_START && \ + CONFIG_CHIP_CRYPTO_PSA_DAC_PRIV_KEY_KMU_SLOT_ID <= CONFIG_CHIP_KMU_SLOT_RANGE_END) +#error "CONFIG_CHIP_CRYPTO_PSA_DAC_PRIV_KEY_KMU_SLOT_ID cannot overlap with KMU slots dedicated for Matter core" +#endif + +namespace chip { +namespace DeviceLayer { +class KMUKeyAllocator : public chip::Crypto::PSAKeyAllocator +{ +public: + psa_key_id_t GetDacKeyId() override + { + return PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, + CONFIG_CHIP_CRYPTO_PSA_DAC_PRIV_KEY_KMU_SLOT_ID); + } + psa_key_id_t GetOpKeyId(FabricIndex fabricIndex) override + { + return static_cast(KMU_NOC_SLOT_START + ((fabricIndex - 1) * KMU_SLOTS_PER_NOC_KEY)); + } + psa_key_id_t AllocateICDKeyId() override + { + psa_key_id_t newKeyId = PSA_KEY_ID_NULL; + if (CHIP_NO_ERROR != FindFreeSlot(newKeyId, KMU_ICD_SLOT_START, KMU_ICD_SLOT_START + KMU_SLOTS_ICD_MAX_NUMBER)) + { + newKeyId = PSA_KEY_ID_NULL; + } + return newKeyId; + } + void UpdateKeyAttributes(psa_key_attributes_t & attrs) override + { + // Set the key lifetime to persistent and the location to CRACEN_KMU if key is in a proper range + if (psa_get_key_id(&attrs) >= + PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, CONFIG_CHIP_KMU_SLOT_RANGE_START) && + psa_get_key_id(&attrs) < + PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, CONFIG_CHIP_KMU_SLOT_RANGE_END)) + { + psa_set_key_lifetime( + &attrs, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_DEFAULT, PSA_KEY_LOCATION_CRACEN_KMU)); + } + // TODO: Currently ECDSA keys are supported only if HASH_ANY is provided, so change it. + // Remove this workaround once KMU supports ECDSA SHA256. + if (psa_get_key_algorithm(&attrs) == PSA_ALG_ECDSA(PSA_ALG_SHA_256)) + { + psa_set_key_algorithm(&attrs, PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)); + } + + // TODO: Change PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8) to PSA_ALG_CCM + // To be compatible with the KMU. Remove this workaround once KMU supports PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG. + // Currently we need to use EXPORT flag because the Cracen does not support copying keys from ITS to KMU + if (psa_get_key_algorithm(&attrs) == PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8)) + { + psa_set_key_algorithm(&attrs, PSA_ALG_CCM); + psa_set_key_usage_flags(&attrs, psa_get_key_usage_flags(&attrs) | PSA_KEY_USAGE_EXPORT); + } + + // TODO: Currently we need to use EXPORT flag because the Cracen does not support copying keys from ITS to KMU + if (psa_get_key_type(&attrs) == PSA_KEY_TYPE_HMAC) + { + psa_set_key_usage_flags(&attrs, psa_get_key_usage_flags(&attrs) | PSA_KEY_USAGE_EXPORT); + } + } + +private: + CHIP_ERROR FindFreeSlot(psa_key_id_t & keyId, psa_key_id_t start, psa_key_id_t end) + { + psa_key_attributes_t attributes; + psa_status_t status = PSA_SUCCESS; + for (keyId = start; keyId < end; ++keyId) + { + status = psa_get_key_attributes(keyId, &attributes); + if (status == PSA_ERROR_INVALID_HANDLE) + { + return CHIP_NO_ERROR; + } + else if (status != PSA_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } + psa_reset_key_attributes(&attributes); + } + return CHIP_ERROR_NOT_FOUND; + } +}; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nrfconnect/args.gni b/src/platform/nrfconnect/args.gni index 902804219d..3610d973d3 100644 --- a/src/platform/nrfconnect/args.gni +++ b/src/platform/nrfconnect/args.gni @@ -17,4 +17,8 @@ declare_args() { # Enable factory data support chip_enable_factory_data = false + + # Use KMU to store cryptographic materials. + # This requires a dedicated platform-specific crypto implementation. + chip_use_cracen_kmu = false }