Skip to content

Commit

Permalink
[nrfconnect] Add platform crypto for KMU usage
Browse files Browse the repository at this point in the history
Added a platform crypto implementation to store crypto materials
in KMU(Key management unit) for devices that use it.
  • Loading branch information
ArekBalysNordic committed Jan 28, 2025
1 parent 29a63e3 commit a35590d
Show file tree
Hide file tree
Showing 10 changed files with 436 additions and 5 deletions.
8 changes: 7 additions & 1 deletion config/nrfconnect/chip-module/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,13 @@ else()
endif()

if (CONFIG_CHIP_CRYPTO_PSA)
matter_add_gn_arg_string("chip_crypto" "psa")
if (CONFIG_CHIP_KMU_SUPPORT)
matter_add_gn_arg_string ("chip_crypto" "platform")
matter_add_gn_arg_bool ("chip_external_mbedtls" FALSE)
matter_add_gn_arg_bool ("chip_use_cracen_kmu" TRUE)
else()
matter_add_gn_arg_string("chip_crypto" "psa")
endif()
matter_add_gn_arg_bool ("chip_crypto_psa_spake2p" CONFIG_PSA_WANT_ALG_SPAKE2P_MATTER)
endif()

Expand Down
39 changes: 39 additions & 0 deletions config/nrfconnect/chip-module/Kconfig.features
Original file line number Diff line number Diff line change
Expand Up @@ -289,4 +289,43 @@ 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.

config CHIP_KMU_SUPPORT
bool "Use KMU to store crypto keys"
default y
depends on CRACEN_LIB_KMU
help
Uses KMU to store keys if it is available on the device. This option changes the Matter crypto
implementation to "platform" and uses custom crypto implementation of Session Keystore and
Operational Keystore.

if CHIP_KMU_SUPPORT

config CHIP_CORE_KMU_SLOT_START
int "Initial KMU slot number for Matter keys"
default 100
help
Starting slot number dedicated for Matter purposes.
This config does not include DAC private key.

config CHIP_CORE_KMU_SLOT_END
int
default 175 if CHIP_CRYPTO_PSA_DAC_PRIV_KEY_KMU
default 180
help
The last available KMU slot for Matter purposes.
This slot does not include DAC private key.

config CHIP_KMU_MAX_FABRICS
int
default 18 if (CHIP_ENABLE_ICD_SUPPORT && CHIP_CRYPTO_PSA_DAC_PRIV_KEY_KMU)
default 37 if CHIP_CRYPTO_PSA_DAC_PRIV_KEY_KMU
default 20 if CHIP_ENABLE_ICD_SUPPORT
default 40
help
Maximum possible Matter fabrics to store NOC keys in the Key Management Unit.
The slots number is limited, so there is the limited NOC keys possible to store as well.
Currently, each NOC key uses 2 KMU slots.

endif

endif # CHIP
2 changes: 0 additions & 2 deletions src/crypto/PSASpake2p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@

#include "PSASpake2p.h"

#include "CHIPCryptoPALPSA.h"

#include <lib/support/CodeUtils.h>

#include <psa/crypto.h>
Expand Down
23 changes: 22 additions & 1 deletion src/platform/nrfconnect/BUILD.gn
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2021 Project CHIP Authors
# Copyright (c) 2021-2025 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.
Expand All @@ -14,6 +14,7 @@

import("//build_overrides/chip.gni")

import("${chip_root}/src/crypto/crypto.gni")
import("${chip_root}/src/platform/device.gni")
import("${chip_root}/src/platform/nrfconnect/args.gni")

Expand Down Expand Up @@ -132,6 +133,26 @@ static_library("nrfconnect") {
sources += [ "../Zephyr/SysHeapMalloc.cpp" ]
}

if (chip_use_cracen_kmu) {
# Use platform crypto implementation for KMU support
sources += [
"crypto/KMUOperationalKeystore.cpp",
"crypto/KMUOperationalKeystore.h",
"crypto/KMUSessionKeystore.cpp",
"crypto/KMUSessionKeystore.h",

# Sources from common crypto core
"${chip_root}/src/crypto/CHIPCryptoPALPSA.cpp",
"${chip_root}/src/crypto/CHIPCryptoPALPSA.h",
"${chip_root}/src/crypto/PSAOperationalKeystore.cpp",
"${chip_root}/src/crypto/PSAOperationalKeystore.h",
"${chip_root}/src/crypto/PSASessionKeystore.cpp",
"${chip_root}/src/crypto/PSASessionKeystore.h",
"${chip_root}/src/crypto/PSASpake2p.cpp",
"${chip_root}/src/crypto/PSASpake2p.h",
]
}

cflags = [ "-Wconversion" ]
}

Expand Down
6 changes: 5 additions & 1 deletion src/platform/nrfconnect/args.gni
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2020 Project CHIP Authors
# Copyright (c) 2020-2025 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.
Expand All @@ -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
}
138 changes: 138 additions & 0 deletions src/platform/nrfconnect/crypto/KMUOperationalKeystore.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* 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.
*/

#include "KMUOperationalKeystore.h"
#include "KMUSlotDefinitions.h"

#include <lib/support/CHIPMem.h>

#include <cracen_psa_kmu.h>
#include <psa/crypto.h>

namespace chip {
namespace Crypto {

KMUOperationalKeystore::KMUPersistentP256Keypair::KMUPersistentP256Keypair(FabricIndex fabricIndex) :
PSAOperationalKeystore::PersistentP256Keypair(0)
{
if (IsValidFabricIndex(fabricIndex))
{
// Decrease fabricIndex by 1 to match the 0-based index used by the KMU slot definitions.
ToPsaContext(mKeypair).key_id =
static_cast<psa_key_id_t>(KMU_MATTER_NOC_SLOT_START + ((fabricIndex - 1) * KMU_MATTER_SLOTS_PER_NOC_KEY));

mInitialized = true;
}
}

KMUOperationalKeystore::KMUPersistentP256Keypair::~KMUPersistentP256Keypair()
{
// This class requires explicit control of the key lifetime. Therefore, clear the key ID
// to prevent it from being destroyed by the base class destructor.
ToPsaContext(mKeypair).key_id = 0;
}

CHIP_ERROR KMUOperationalKeystore::NewOpKeypairForFabric(FabricIndex fabricIndex, MutableByteSpan & outCertificateSigningRequest)
{
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);

if (HasPendingOpKeypair())
{
VerifyOrReturnError(fabricIndex == mPendingFabricIndex, CHIP_ERROR_INVALID_FABRIC_INDEX);
}

if (mPendingKeypair == nullptr)
{
mPendingKeypair = Platform::New<PersistentP256Keypair>(fabricIndex);
}

VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_NO_MEMORY);
ReturnErrorOnFailure(mPendingKeypair->Generate());

size_t csrLength = outCertificateSigningRequest.size();
ReturnErrorOnFailure(mPendingKeypair->NewCertificateSigningRequest(outCertificateSigningRequest.data(), csrLength));
outCertificateSigningRequest.reduce_size(csrLength);
mPendingFabricIndex = fabricIndex;

return CHIP_NO_ERROR;
}

CHIP_ERROR KMUOperationalKeystore::KMUPersistentP256Keypair::Deserialize(P256SerializedKeypair & input)
{
CHIP_ERROR error = CHIP_NO_ERROR;
psa_status_t status = PSA_SUCCESS;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t keyId = 0;
VerifyOrReturnError(input.Length() == mPublicKey.Length() + kP256_PrivateKey_Length, CHIP_ERROR_INVALID_ARGUMENT);

Destroy();

// Type based on ECC with the elliptic curve SECP256r1 -> PSA_ECC_FAMILY_SECP_R1
psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&attributes, kP256_PrivateKey_Length * 8);
psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_ANY_HASH));
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE);
psa_set_key_lifetime(&attributes,
PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_DEFAULT, PSA_KEY_LOCATION_CRACEN_KMU));
psa_set_key_id(&attributes, GetKeyId());

status = psa_import_key(&attributes, input.ConstBytes() + mPublicKey.Length(), kP256_PrivateKey_Length, &keyId);
VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL);

memcpy(mPublicKey.Bytes(), input.ConstBytes(), mPublicKey.Length());

exit:
LogPsaError(status);
psa_reset_key_attributes(&attributes);

return error;
}

CHIP_ERROR KMUOperationalKeystore::KMUPersistentP256Keypair::Generate()
{
CHIP_ERROR error = CHIP_NO_ERROR;
psa_status_t status = PSA_SUCCESS;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t keyId = 0;
size_t publicKeyLength;

Destroy();

// Type based on ECC with the elliptic curve SECP256r1 -> PSA_ECC_FAMILY_SECP_R1
psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&attributes, kP256_PrivateKey_Length * 8);
psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_ANY_HASH));
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE);
psa_set_key_lifetime(&attributes,
PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_DEFAULT, PSA_KEY_LOCATION_CRACEN_KMU));
psa_set_key_id(&attributes, GetKeyId());

status = psa_generate_key(&attributes, &keyId);
VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL);

status = psa_export_public_key(keyId, mPublicKey.Bytes(), mPublicKey.Length(), &publicKeyLength);
VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL);
VerifyOrExit(publicKeyLength == kP256_PublicKey_Length, error = CHIP_ERROR_INTERNAL);

exit:
psa_reset_key_attributes(&attributes);

return error;
}

} // namespace Crypto
} // namespace chip
43 changes: 43 additions & 0 deletions src/platform/nrfconnect/crypto/KMUOperationalKeystore.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2023 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 <crypto/PSAOperationalKeystore.h>

namespace chip {
namespace Crypto {

class KMUOperationalKeystore : public PSAOperationalKeystore
{
public:
CHIP_ERROR NewOpKeypairForFabric(FabricIndex fabricIndex, MutableByteSpan & outCertificateSigningRequest) override;

protected:
class KMUPersistentP256Keypair : public PSAOperationalKeystore::PersistentP256Keypair
{
public:
KMUPersistentP256Keypair(FabricIndex fabricIndex);
~KMUPersistentP256Keypair() override;

CHIP_ERROR Generate() override;
CHIP_ERROR Deserialize(P256SerializedKeypair & input) override;
};
};

} // namespace Crypto
} // namespace chip
Loading

0 comments on commit a35590d

Please sign in to comment.