Skip to content

Commit 63bb696

Browse files
Switched to kmu file, content of the file is not changed to KMU
1 parent 93c712e commit 63bb696

File tree

6 files changed

+346
-1
lines changed

6 files changed

+346
-1
lines changed

config/nrfconnect/chip-module/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ matter_add_gn_arg_bool ("chip_enable_factory_data" CONFIG_CHIP_FA
154154
matter_add_gn_arg_bool ("chip_enable_read_client" CONFIG_CHIP_ENABLE_READ_CLIENT)
155155
matter_add_gn_arg_bool ("chip_mdns_minimal" CONFIG_WIFI_NRF70)
156156
matter_add_gn_arg_bool ("chip_mdns_platform" CONFIG_NET_L2_OPENTHREAD)
157+
matter_add_gn_arg_bool ("chip_crypto_psa_use_kmu" CONFIG_CHIP_CRYPTO_PSA_KMU)
157158

158159
if (CONFIG_CHIP_ENABLE_ICD_SUPPORT)
159160
matter_add_gn_arg_bool ("chip_enable_icd_lit" CONFIG_CHIP_ICD_LIT_SUPPORT)

config/nrfconnect/chip-module/Kconfig.features

+15
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,21 @@ config CHIP_WIFI
4040
imply NET_STATISTICS_IPV6
4141
imply NET_STATISTICS_USER_API
4242

43+
config CHIP_CRYPTO_PSA_KMU
44+
bool "Use KMU to store persistent keys"
45+
depends on SOC_SERIES_NRF54LX
46+
default y
47+
help
48+
Uses Key Management Unit module to store persistent keys if the PSA ITS
49+
is disabled.
50+
51+
config CHIP_CRYPTO_PSA_KMU_ENCRYPTION
52+
bool "Use encryption while storing persistent keys in KMU"
53+
depends on CHIP_CRYPTO_PSA_KMU
54+
help
55+
Uses encryption while storing persistent keys in Key Management Unit.
56+
This operation costs two KMU slots more than without encryption.
57+
4358
config CHIP_QSPI_NOR
4459
bool "Enable QSPI NOR feature set"
4560
imply NORDIC_QSPI_NOR

src/crypto/BUILD.gn

+12-1
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,22 @@ static_library("crypto") {
145145

146146
if (chip_crypto == "psa") {
147147
sources += [
148-
"PSAOperationalKeystore.cpp",
149148
"PSAOperationalKeystore.h",
150149
"PSASessionKeystore.cpp",
151150
"PSASessionKeystore.h",
152151
]
152+
153+
if(chip_crypto_psa_use_kmu)
154+
{
155+
sources += [
156+
"PSAKMUOperationalKeystore.cpp",
157+
]
158+
} else
159+
{
160+
sources += [
161+
"PSAOperationalKeystore.cpp",
162+
]
163+
}
153164
} else {
154165
sources += [
155166
"RawKeySessionKeystore.cpp",
+307
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
/*
2+
* Copyright (c) 2023 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include "PSAOperationalKeystore.h"
19+
#include "PersistentStorageOperationalKeystore.h"
20+
21+
#include <lib/support/CHIPMem.h>
22+
23+
#include <psa/crypto.h>
24+
25+
#ifdef CHIP_CONFIG_CRYPTO_PSA_KMU
26+
#include <cracen_psa_kmu.h>
27+
#endif
28+
29+
namespace chip {
30+
namespace Crypto {
31+
32+
PSAOperationalKeystore::PersistentP256Keypair::PersistentP256Keypair(FabricIndex fabricIndex)
33+
{
34+
ToPsaContext(mKeypair).key_id = MakeOperationalKeyId(fabricIndex);
35+
mInitialized = true;
36+
}
37+
38+
PSAOperationalKeystore::PersistentP256Keypair::~PersistentP256Keypair()
39+
{
40+
// This class requires explicit control of the key lifetime. Therefore, clear the key ID
41+
// to prevent it from being destroyed by the base class destructor.
42+
ToPsaContext(mKeypair).key_id = 0;
43+
}
44+
45+
inline psa_key_id_t PSAOperationalKeystore::PersistentP256Keypair::GetKeyId() const
46+
{
47+
return ToConstPsaContext(mKeypair).key_id;
48+
}
49+
50+
bool PSAOperationalKeystore::PersistentP256Keypair::Exists() const
51+
{
52+
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
53+
psa_status_t status = psa_get_key_attributes(GetKeyId(), &attributes);
54+
55+
psa_reset_key_attributes(&attributes);
56+
57+
return status == PSA_SUCCESS;
58+
}
59+
60+
CHIP_ERROR PSAOperationalKeystore::PersistentP256Keypair::Generate()
61+
{
62+
CHIP_ERROR error = CHIP_NO_ERROR;
63+
psa_status_t status = PSA_SUCCESS;
64+
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
65+
psa_key_id_t keyId = 0;
66+
size_t publicKeyLength;
67+
68+
Destroy();
69+
70+
// Type based on ECC with the elliptic curve SECP256r1 -> PSA_ECC_FAMILY_SECP_R1
71+
psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
72+
psa_set_key_bits(&attributes, kP256_PrivateKey_Length * 8);
73+
psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
74+
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE);
75+
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_PERSISTENT);
76+
psa_set_key_id(&attributes, GetKeyId());
77+
78+
status = psa_generate_key(&attributes, &keyId);
79+
VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL);
80+
81+
status = psa_export_public_key(keyId, mPublicKey.Bytes(), mPublicKey.Length(), &publicKeyLength);
82+
VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL);
83+
VerifyOrExit(publicKeyLength == kP256_PublicKey_Length, error = CHIP_ERROR_INTERNAL);
84+
85+
exit:
86+
psa_reset_key_attributes(&attributes);
87+
88+
return error;
89+
}
90+
91+
CHIP_ERROR PSAOperationalKeystore::PersistentP256Keypair::Destroy()
92+
{
93+
psa_status_t status = psa_destroy_key(GetKeyId());
94+
95+
ReturnErrorCodeIf(status == PSA_ERROR_INVALID_HANDLE, CHIP_ERROR_INVALID_FABRIC_INDEX);
96+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
97+
98+
return CHIP_NO_ERROR;
99+
}
100+
101+
bool PSAOperationalKeystore::HasPendingOpKeypair() const
102+
{
103+
return mPendingFabricIndex != kUndefinedFabricIndex;
104+
}
105+
106+
bool PSAOperationalKeystore::HasOpKeypairForFabric(FabricIndex fabricIndex) const
107+
{
108+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), false);
109+
110+
if (mPendingFabricIndex == fabricIndex)
111+
{
112+
return mIsPendingKeypairActive;
113+
}
114+
115+
return PersistentP256Keypair(fabricIndex).Exists();
116+
}
117+
118+
CHIP_ERROR PSAOperationalKeystore::NewOpKeypairForFabric(FabricIndex fabricIndex, MutableByteSpan & outCertificateSigningRequest)
119+
{
120+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
121+
122+
if (HasPendingOpKeypair())
123+
{
124+
VerifyOrReturnError(fabricIndex == mPendingFabricIndex, CHIP_ERROR_INVALID_FABRIC_INDEX);
125+
}
126+
127+
if (mPendingKeypair == nullptr)
128+
{
129+
mPendingKeypair = Platform::New<PersistentP256Keypair>(fabricIndex);
130+
}
131+
132+
VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_NO_MEMORY);
133+
ReturnErrorOnFailure(mPendingKeypair->Generate());
134+
135+
size_t csrLength = outCertificateSigningRequest.size();
136+
ReturnErrorOnFailure(mPendingKeypair->NewCertificateSigningRequest(outCertificateSigningRequest.data(), csrLength));
137+
outCertificateSigningRequest.reduce_size(csrLength);
138+
mPendingFabricIndex = fabricIndex;
139+
140+
return CHIP_NO_ERROR;
141+
}
142+
143+
CHIP_ERROR PSAOperationalKeystore::PersistentP256Keypair::Deserialize(P256SerializedKeypair & input)
144+
{
145+
CHIP_ERROR error = CHIP_NO_ERROR;
146+
psa_status_t status = PSA_SUCCESS;
147+
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
148+
psa_key_id_t keyId = 0;
149+
VerifyOrReturnError(input.Length() == mPublicKey.Length() + kP256_PrivateKey_Length, CHIP_ERROR_INVALID_ARGUMENT);
150+
151+
Destroy();
152+
153+
// Type based on ECC with the elliptic curve SECP256r1 -> PSA_ECC_FAMILY_SECP_R1
154+
psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
155+
psa_set_key_bits(&attributes, kP256_PrivateKey_Length * 8);
156+
psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
157+
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE);
158+
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_PERSISTENT);
159+
psa_set_key_id(&attributes, GetKeyId());
160+
161+
status = psa_import_key(&attributes, input.ConstBytes() + mPublicKey.Length(), kP256_PrivateKey_Length, &keyId);
162+
VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL);
163+
164+
memcpy(mPublicKey.Bytes(), input.ConstBytes(), mPublicKey.Length());
165+
166+
exit:
167+
psa_reset_key_attributes(&attributes);
168+
169+
return error;
170+
}
171+
172+
CHIP_ERROR PSAOperationalKeystore::ActivateOpKeypairForFabric(FabricIndex fabricIndex, const Crypto::P256PublicKey & nocPublicKey)
173+
{
174+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && mPendingFabricIndex == fabricIndex, CHIP_ERROR_INVALID_FABRIC_INDEX);
175+
VerifyOrReturnError(mPendingKeypair->Pubkey().Matches(nocPublicKey), CHIP_ERROR_INVALID_PUBLIC_KEY);
176+
mIsPendingKeypairActive = true;
177+
178+
return CHIP_NO_ERROR;
179+
}
180+
181+
CHIP_ERROR PSAOperationalKeystore::CommitOpKeypairForFabric(FabricIndex fabricIndex)
182+
{
183+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && mPendingFabricIndex == fabricIndex, CHIP_ERROR_INVALID_FABRIC_INDEX);
184+
VerifyOrReturnError(mIsPendingKeypairActive, CHIP_ERROR_INCORRECT_STATE);
185+
186+
ReleasePendingKeypair();
187+
188+
return CHIP_NO_ERROR;
189+
}
190+
191+
CHIP_ERROR PSAOperationalKeystore::ExportOpKeypairForFabric(FabricIndex fabricIndex, Crypto::P256SerializedKeypair & outKeypair)
192+
{
193+
// Currently exporting the key is forbidden in PSAOperationalKeystore because the PSA_KEY_USAGE_EXPORT usage flag is not set, so
194+
// there is no need to compile the code for the device, but there should be an implementation for test purposes to verify if
195+
// the psa_export_key returns an error.
196+
#if CHIP_CONFIG_TEST
197+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
198+
VerifyOrReturnError(HasOpKeypairForFabric(fabricIndex), CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
199+
200+
size_t outSize = 0;
201+
psa_status_t status =
202+
psa_export_key(PersistentP256Keypair(fabricIndex).GetKeyId(), outKeypair.Bytes(), outKeypair.Capacity(), &outSize);
203+
204+
if (status == PSA_ERROR_BUFFER_TOO_SMALL)
205+
{
206+
return CHIP_ERROR_BUFFER_TOO_SMALL;
207+
}
208+
else if (status == PSA_ERROR_NOT_PERMITTED)
209+
{
210+
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
211+
}
212+
else if (status != PSA_SUCCESS)
213+
{
214+
return CHIP_ERROR_INTERNAL;
215+
}
216+
217+
outKeypair.SetLength(outSize);
218+
219+
return CHIP_NO_ERROR;
220+
#else
221+
return CHIP_ERROR_NOT_IMPLEMENTED;
222+
#endif
223+
}
224+
225+
CHIP_ERROR PSAOperationalKeystore::RemoveOpKeypairForFabric(FabricIndex fabricIndex)
226+
{
227+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
228+
229+
if (mPendingFabricIndex == fabricIndex)
230+
{
231+
RevertPendingKeypair();
232+
return CHIP_NO_ERROR;
233+
}
234+
235+
return PersistentP256Keypair(fabricIndex).Destroy();
236+
}
237+
238+
void PSAOperationalKeystore::RevertPendingKeypair()
239+
{
240+
VerifyOrReturn(HasPendingOpKeypair());
241+
mPendingKeypair->Destroy();
242+
ReleasePendingKeypair();
243+
}
244+
245+
CHIP_ERROR PSAOperationalKeystore::SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message,
246+
Crypto::P256ECDSASignature & outSignature) const
247+
{
248+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
249+
250+
if (mPendingFabricIndex == fabricIndex)
251+
{
252+
VerifyOrReturnError(mIsPendingKeypairActive, CHIP_ERROR_INVALID_FABRIC_INDEX);
253+
return mPendingKeypair->ECDSA_sign_msg(message.data(), message.size(), outSignature);
254+
}
255+
256+
PersistentP256Keypair keypair(fabricIndex);
257+
VerifyOrReturnError(keypair.Exists(), CHIP_ERROR_INVALID_FABRIC_INDEX);
258+
259+
return keypair.ECDSA_sign_msg(message.data(), message.size(), outSignature);
260+
}
261+
262+
Crypto::P256Keypair * PSAOperationalKeystore::AllocateEphemeralKeypairForCASE()
263+
{
264+
return Platform::New<Crypto::P256Keypair>();
265+
}
266+
267+
void PSAOperationalKeystore::ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair)
268+
{
269+
Platform::Delete(keypair);
270+
}
271+
272+
void PSAOperationalKeystore::ReleasePendingKeypair()
273+
{
274+
Platform::Delete(mPendingKeypair);
275+
mPendingKeypair = nullptr;
276+
mPendingFabricIndex = kUndefinedFabricIndex;
277+
mIsPendingKeypairActive = false;
278+
}
279+
280+
CHIP_ERROR PSAOperationalKeystore::MigrateOpKeypairForFabric(FabricIndex fabricIndex,
281+
OperationalKeystore & operationalKeystore) const
282+
{
283+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
284+
285+
P256SerializedKeypair serializedKeypair;
286+
287+
// Do not allow overwriting the existing key and just remove it from the previous Operational Keystore if needed.
288+
if (!HasOpKeypairForFabric(fabricIndex))
289+
{
290+
ReturnErrorOnFailure(operationalKeystore.ExportOpKeypairForFabric(fabricIndex, serializedKeypair));
291+
292+
PersistentP256Keypair keypair(fabricIndex);
293+
ReturnErrorOnFailure(keypair.Deserialize(serializedKeypair));
294+
295+
// Migrated key is not useful anymore, remove it from the previous keystore.
296+
ReturnErrorOnFailure(operationalKeystore.RemoveOpKeypairForFabric(fabricIndex));
297+
}
298+
else if (operationalKeystore.HasOpKeypairForFabric(fabricIndex))
299+
{
300+
ReturnErrorOnFailure(operationalKeystore.RemoveOpKeypairForFabric(fabricIndex));
301+
}
302+
303+
return CHIP_NO_ERROR;
304+
}
305+
306+
} // namespace Crypto
307+
} // namespace chip

src/crypto/crypto.gni

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ declare_args() {
2222

2323
# Use PSA Spake2+ implementation. Only used if chip_crypto == "psa"
2424
chip_crypto_psa_spake2p = false
25+
26+
# Use PSA KMU storage. Only used if device == nRF54LX series.
27+
chip_crypto_psa_use_kmu = false
2528
}
2629

2730
assert(

src/platform/nrfconnect/CHIPPlatformConfig.h

+8
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@
5959
#define CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE 0x30000
6060
#endif // CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE
6161

62+
#ifndef CHIP_CONFIG_CRYPTO_PSA_KMU
63+
#define CHIP_CONFIG_CRYPTO_PSA_KMU CONFIG_CHIP_CRYPTO_PSA_KMU
64+
#endif // CHIP_CONFIG_CRYPTO_PSA_KMU
65+
66+
#ifndef CHIP_CONFIG_CRYPTO_PSA_KMU_USE_ENCRYPTION
67+
#define CHIP_CONFIG_CRYPTO_PSA_KMU_USE_ENCRYPTION CONFIG_CHIP_CRYPTO_PSA_KMU_ENCRYPTION
68+
#endif // CHIP_CONFIG_CRYPTO_PSA_KMU_USE_ENCRYPTION
69+
6270
// ==================== General Configuration Overrides ====================
6371

6472
#ifndef CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS

0 commit comments

Comments
 (0)