Skip to content

Commit 3ba4001

Browse files
authored
Support Trusty OS backed operational keystore (project-chip#41740)
i.MX enabled Trusty OS. Move the persistent storage operations to Trusty OS. Change-Id: I13cbe98236a4fec43b78853163b322a8d45156c0 Signed-off-by: Maximus <[email protected]>
1 parent bc5e8e3 commit 3ba4001

File tree

3 files changed

+267
-18
lines changed

3 files changed

+267
-18
lines changed

src/crypto/BUILD.gn

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ buildconfig_header("crypto_buildconfig") {
7474
"CHIP_CRYPTO_OPENSSL=${chip_crypto_openssl}",
7575
"CHIP_CRYPTO_BORINGSSL=${chip_crypto_boringssl}",
7676
"CHIP_CRYPTO_PLATFORM=${chip_crypto_platform}",
77-
"CHIP_CRYPTO_TRUSTY_OS=${chip_with_trusty_os}",
7877
]
7978
}
8079

@@ -183,7 +182,6 @@ static_library("crypto") {
183182
sources = [
184183
"CHIPCryptoPAL.cpp",
185184
"DefaultSessionKeystore.h",
186-
"PersistentStorageOperationalKeystore.cpp",
187185
"PersistentStorageOperationalKeystore.h",
188186
"RandUtils.cpp",
189187
"RandUtils.h",
@@ -212,6 +210,12 @@ static_library("crypto") {
212210
]
213211
}
214212

213+
if (chip_with_trusty_os) {
214+
sources += [ "PersistentStorageOperationalKeystoreTrusty.cpp" ]
215+
} else {
216+
sources += [ "PersistentStorageOperationalKeystore.cpp" ]
217+
}
218+
215219
public_configs = []
216220

217221
cflags = [ "-Wconversion" ]

src/crypto/P256KeyPairTrustyImpl.cpp

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ CHIP_ERROR P256Keypair::Initialize(ECPKeyTarget key_target)
102102
uint64_t p256_handle = 0;
103103
int rc = 0;
104104

105+
if (!memcmp(&mKeypair, kTrustyMagicNumberFabricIndex, sizeof(kTrustyMagicNumberFabricIndex)))
106+
{
107+
/* Fixed p256_handle consists of magic number and a fabric index. */
108+
p256_handle = to_Handle(&mKeypair);
109+
}
105110
rc = GetTrustyMatter().P256KeypairInitialize(p256_handle, public_key);
106111
VerifyOrExit(rc == MATTER_ERROR_OK, error = CHIP_ERROR_INTERNAL);
107112

@@ -117,23 +122,30 @@ CHIP_ERROR P256Keypair::Initialize(ECPKeyTarget key_target)
117122
CHIP_ERROR P256Keypair::Serialize(P256SerializedKeypair & output) const
118123
{
119124
CHIP_ERROR error = CHIP_NO_ERROR;
120-
uint8_t privkey[kP256_PrivateKey_Length];
121-
int rc = 0;
125+
int rc = 0;
122126

123-
rc = GetTrustyMatter().P256KeypairSerialize(to_Handle(&mKeypair), privkey);
124-
VerifyOrExit(rc == MATTER_ERROR_OK, error = CHIP_ERROR_INTERNAL);
127+
size_t len = output.Length() == 0 ? output.Capacity() : output.Length();
128+
Encoding::BufferWriter bbuf(output.Bytes(), len);
129+
bbuf.Put(mPublicKey, mPublicKey.Length());
125130

131+
if (!memcmp(&mKeypair, kTrustyMagicNumberFabricIndex, sizeof(kTrustyMagicNumberFabricIndex)))
126132
{
127-
size_t len = output.Length() == 0 ? output.Capacity() : output.Length();
128-
Encoding::BufferWriter bbuf(output.Bytes(), len);
129-
bbuf.Put(mPublicKey, mPublicKey.Length());
133+
/* To keep confidential, private key not provided but p256_handle */
134+
bbuf.Put(&mKeypair, sizeof(uint64_t));
135+
}
136+
else
137+
{
138+
uint8_t privkey[kP256_PrivateKey_Length];
139+
uint64_t p256_handle = to_Handle(&mKeypair);
140+
rc = GetTrustyMatter().P256KeypairSerialize(p256_handle, privkey);
141+
VerifyOrExit(rc == MATTER_ERROR_OK, error = CHIP_ERROR_INTERNAL);
130142
bbuf.Put(privkey, sizeof(privkey));
131-
VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_NO_MEMORY);
132-
output.SetLength(bbuf.Needed());
143+
ClearSecretData(privkey, sizeof(privkey));
133144
}
145+
VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_NO_MEMORY);
146+
output.SetLength(bbuf.Needed());
134147

135148
exit:
136-
ClearSecretData(privkey, sizeof(privkey));
137149
return error;
138150
}
139151

@@ -144,16 +156,28 @@ CHIP_ERROR P256Keypair::Deserialize(P256SerializedKeypair & input)
144156
int rc = 0;
145157
uint64_t p256_handle = 0;
146158

147-
uint8_t * pubkey = input.Bytes();
148-
uint8_t * privkey = input.Bytes() + mPublicKey.Length();
149-
150-
VerifyOrExit(input.Length() == mPublicKey.Length() + kP256_PrivateKey_Length, error = CHIP_ERROR_INVALID_ARGUMENT);
159+
uint8_t * pubkey = input.Bytes();
160+
VerifyOrExit(input.Length() >= mPublicKey.Length(), error = CHIP_ERROR_INVALID_ARGUMENT);
151161
bbuf.Put(input.ConstBytes(), mPublicKey.Length());
152162
VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_NO_MEMORY);
153163

154-
rc = GetTrustyMatter().P256KeypairDeserialize(p256_handle, pubkey, mPublicKey.Length(), privkey, kP256_PrivateKey_Length);
164+
if (!memcmp(input.Bytes() + kP256_PublicKey_Length, kTrustyMagicNumberFabricIndex, sizeof(kTrustyMagicNumberFabricIndex)))
165+
{
166+
/* If the fixed p256_handle was passed in following the public key, then the private key should be interpreted as the
167+
* p256_handle */
168+
VerifyOrExit(input.Length() == mPublicKey.Length() + sizeof(uint64_t), error = CHIP_ERROR_INVALID_ARGUMENT);
169+
memcpy(&p256_handle, input.Bytes() + kP256_PublicKey_Length, sizeof(uint64_t));
170+
}
171+
else
172+
{
173+
uint8_t * privkey;
174+
VerifyOrExit(input.Length() == mPublicKey.Length() + kP256_PrivateKey_Length, error = CHIP_ERROR_INVALID_ARGUMENT);
175+
privkey = input.Bytes() + kP256_PublicKey_Length;
176+
rc = GetTrustyMatter().P256KeypairDeserialize(p256_handle, pubkey, mPublicKey.Length(), privkey, kP256_PrivateKey_Length);
177+
VerifyOrExit(rc == MATTER_ERROR_OK, error = CHIP_ERROR_INTERNAL);
178+
}
179+
155180
from_Handle(&p256_handle, &mKeypair);
156-
VerifyOrExit(rc == MATTER_ERROR_OK, error = CHIP_ERROR_INTERNAL);
157181

158182
mInitialized = true;
159183

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 Project CHIP Authors
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 <crypto/OperationalKeystore.h>
19+
#include <lib/core/CHIPError.h>
20+
#include <lib/core/CHIPPersistentStorageDelegate.h>
21+
#include <lib/core/CHIPSafeCasts.h>
22+
#include <lib/core/DataModelTypes.h>
23+
#include <lib/support/CHIPMem.h>
24+
#include <lib/support/CodeUtils.h>
25+
#include <lib/support/DefaultStorageKeyAllocator.h>
26+
#include <lib/support/SafeInt.h>
27+
#include <trusty_matter.h>
28+
29+
#include "PersistentStorageOperationalKeystore.h"
30+
31+
using namespace matter;
32+
using namespace chip::Crypto;
33+
34+
namespace chip {
35+
36+
TrustyMatter & GetTrustyMatter()
37+
{
38+
static TrustyMatter instance;
39+
return instance;
40+
}
41+
42+
bool PersistentStorageOperationalKeystore::HasOpKeypairForFabric(FabricIndex fabricIndex) const
43+
{
44+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), false);
45+
46+
// If there was a pending keypair, then there's really a usable key
47+
if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex) && (mPendingKeypair != nullptr))
48+
{
49+
return true;
50+
}
51+
52+
return GetTrustyMatter().HasOpKeypairForFabric(fabricIndex);
53+
}
54+
55+
CHIP_ERROR PersistentStorageOperationalKeystore::NewOpKeypairForFabric(FabricIndex fabricIndex,
56+
MutableByteSpan & outCertificateSigningRequest)
57+
{
58+
P256SerializedKeypair serializedKeypair;
59+
uint8_t public_key[kP256_PublicKey_Length] = { 0 };
60+
uint64_t p256_handle = 0;
61+
62+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
63+
// If a key is pending, we cannot generate for a different fabric index until we commit or revert.
64+
if ((mPendingFabricIndex != kUndefinedFabricIndex) && (fabricIndex != mPendingFabricIndex))
65+
{
66+
return CHIP_ERROR_INVALID_FABRIC_INDEX;
67+
}
68+
VerifyOrReturnError(outCertificateSigningRequest.size() >= Crypto::kMIN_CSR_Buffer_Size, CHIP_ERROR_BUFFER_TOO_SMALL);
69+
70+
// Replace previous pending keypair, if any was previously allocated
71+
ResetPendingKey();
72+
73+
mPendingKeypair = Platform::New<Crypto::P256Keypair>();
74+
VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_NO_MEMORY);
75+
76+
memcpy(serializedKeypair.Bytes(), public_key, kP256_PublicKey_Length);
77+
78+
// kTrustyMagicNumberFabricIndex = { 0x2, 0x3, 0x5, 0x7, 0x0B, 0x0D, 0x11 }
79+
// It is a flag to inform the Trusty OS to use a fixed p256_handle, and provide an opaque key
80+
memcpy(&p256_handle, kTrustyMagicNumberFabricIndex, sizeof(kTrustyMagicNumberFabricIndex));
81+
// FabricIndex is a uint8_t indeed
82+
static_assert(1 == sizeof(FabricIndex));
83+
84+
// Append the fabric index after the magic number
85+
memcpy((uint8_t *) &p256_handle + sizeof(kTrustyMagicNumberFabricIndex), &fabricIndex, sizeof(FabricIndex));
86+
87+
memcpy(serializedKeypair.Bytes() + kP256_PublicKey_Length, &p256_handle, sizeof(uint64_t));
88+
serializedKeypair.SetLength(kP256_PublicKey_Length + sizeof(uint64_t));
89+
90+
ReturnErrorOnFailure(mPendingKeypair->Deserialize(serializedKeypair));
91+
92+
mPendingKeypair->Initialize(Crypto::ECPKeyTarget::ECDSA);
93+
94+
size_t csrLength = outCertificateSigningRequest.size();
95+
CHIP_ERROR err = mPendingKeypair->NewCertificateSigningRequest(outCertificateSigningRequest.data(), csrLength);
96+
if (err != CHIP_NO_ERROR)
97+
{
98+
ResetPendingKey();
99+
return CHIP_ERROR_HSM;
100+
}
101+
102+
outCertificateSigningRequest.reduce_size(csrLength);
103+
mPendingFabricIndex = fabricIndex;
104+
105+
return CHIP_NO_ERROR;
106+
}
107+
108+
CHIP_ERROR PersistentStorageOperationalKeystore::ActivateOpKeypairForFabric(FabricIndex fabricIndex,
109+
const Crypto::P256PublicKey & nocPublicKey)
110+
{
111+
VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
112+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
113+
114+
// Validate public key being activated matches last generated pending keypair
115+
VerifyOrReturnError(mPendingKeypair->Pubkey().Matches(nocPublicKey), CHIP_ERROR_INVALID_PUBLIC_KEY);
116+
117+
mIsPendingKeypairActive = true;
118+
119+
return CHIP_NO_ERROR;
120+
}
121+
122+
CHIP_ERROR PersistentStorageOperationalKeystore::CommitOpKeypairForFabric(FabricIndex fabricIndex)
123+
{
124+
P256SerializedKeypair serializedOpKey;
125+
uint64_t p256_handle = 0;
126+
uint8_t p256_handle_expect[8] = { 0 };
127+
128+
VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
129+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
130+
VerifyOrReturnError(mIsPendingKeypairActive == true, CHIP_ERROR_INCORRECT_STATE);
131+
132+
// Try to store persistent key. On failure, leave everything pending as-is
133+
CHIP_ERROR err = mPendingKeypair->Serialize(serializedOpKey);
134+
VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL);
135+
memcpy(&p256_handle, serializedOpKey.Bytes() + kP256_PublicKey_Length, sizeof(uint64_t));
136+
137+
memcpy(&p256_handle_expect[0], kTrustyMagicNumberFabricIndex, sizeof(kTrustyMagicNumberFabricIndex));
138+
memcpy(&p256_handle_expect[7], &fabricIndex, sizeof(FabricIndex));
139+
VerifyOrReturnError(!memcmp(&p256_handle, p256_handle_expect, sizeof(p256_handle_expect)), CHIP_ERROR_INTERNAL);
140+
141+
int rc = GetTrustyMatter().CommitOpKeypairForFabric(p256_handle, fabricIndex);
142+
VerifyOrReturnError(rc == MATTER_ERROR_OK, CHIP_ERROR_INTERNAL);
143+
144+
// If we got here, we succeeded and can reset the pending key: next `SignWithOpKeypair` will use the stored key.
145+
ResetPendingKey();
146+
return CHIP_NO_ERROR;
147+
}
148+
149+
CHIP_ERROR PersistentStorageOperationalKeystore::ExportOpKeypairForFabric(FabricIndex fabricIndex,
150+
Crypto::P256SerializedKeypair & outKeypair)
151+
{
152+
return CHIP_ERROR_NOT_IMPLEMENTED;
153+
}
154+
155+
CHIP_ERROR PersistentStorageOperationalKeystore::RemoveOpKeypairForFabric(FabricIndex fabricIndex)
156+
{
157+
int rc = 0;
158+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
159+
160+
// Remove pending state if matching
161+
if ((mPendingKeypair != nullptr) && (fabricIndex == mPendingFabricIndex))
162+
{
163+
RevertPendingKeypair();
164+
}
165+
166+
rc = GetTrustyMatter().RemoveOpKeypairForFabric(fabricIndex);
167+
if (rc != MATTER_ERROR_OK)
168+
return CHIP_ERROR_INTERNAL;
169+
170+
return CHIP_NO_ERROR;
171+
}
172+
173+
void PersistentStorageOperationalKeystore::RevertPendingKeypair()
174+
{
175+
// Just reset the pending key, it hasn't been stored into secure storage.
176+
ResetPendingKey();
177+
}
178+
179+
CHIP_ERROR PersistentStorageOperationalKeystore::SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message,
180+
Crypto::P256ECDSASignature & outSignature) const
181+
{
182+
int rc = 0;
183+
size_t sig_size = 0;
184+
uint8_t sig[kP256_ECDSA_Signature_Length_Raw];
185+
186+
VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
187+
188+
if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex))
189+
{
190+
VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INTERNAL);
191+
// We have an override key: sign with it!
192+
return mPendingKeypair->ECDSA_sign_msg(message.data(), message.size(), outSignature);
193+
}
194+
195+
rc = GetTrustyMatter().SignWithStoredOpKey(fabricIndex, message.data(), message.size(), sig, sig_size);
196+
if (rc != MATTER_ERROR_OK)
197+
return CHIP_ERROR_INTERNAL;
198+
199+
VerifyOrReturnError(sig_size == kP256_ECDSA_Signature_Length_Raw, CHIP_ERROR_INTERNAL);
200+
VerifyOrReturnError(outSignature.SetLength(sig_size) == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL);
201+
memcpy(outSignature.Bytes(), sig, sig_size);
202+
return CHIP_NO_ERROR;
203+
}
204+
205+
Crypto::P256Keypair * PersistentStorageOperationalKeystore::AllocateEphemeralKeypairForCASE()
206+
{
207+
return Platform::New<Crypto::P256Keypair>();
208+
}
209+
210+
void PersistentStorageOperationalKeystore::ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair)
211+
{
212+
Platform::Delete<Crypto::P256Keypair>(keypair);
213+
}
214+
215+
CHIP_ERROR PersistentStorageOperationalKeystore::MigrateOpKeypairForFabric(FabricIndex fabricIndex,
216+
OperationalKeystore & operationalKeystore) const
217+
{
218+
return CHIP_ERROR_NOT_IMPLEMENTED;
219+
}
220+
221+
} // namespace chip

0 commit comments

Comments
 (0)