Skip to content

Commit 1fa4e7c

Browse files
[nrf noup] Integrated HKDF key handle with Spake2+
* Aligned Spake2+ implementation with the new CHIPCryptoPAL API using HKDF key handle instead of raw data. * Removed workaround extracting raw key data from oberon context. * Removed const from GetKeys and DeriveSecureSession methods, as PSA API requires access to non-const members to obtains shared secret. Signed-off-by: Kamil Kasperczyk <kamil.kasperczyk@nordicsemi.no>
1 parent 157480a commit 1fa4e7c

14 files changed

+99
-45
lines changed

src/crypto/CHIPCryptoPAL.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ CHIP_ERROR Spake2p::KeyConfirm(const uint8_t * in, size_t in_len)
501501
return CHIP_NO_ERROR;
502502
}
503503

504-
CHIP_ERROR Spake2p::GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key) const
504+
CHIP_ERROR Spake2p::GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key)
505505
{
506506
VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::KC, CHIP_ERROR_INTERNAL);
507507

src/crypto/CHIPCryptoPAL.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1184,7 +1184,7 @@ class Spake2p
11841184
*
11851185
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
11861186
**/
1187-
CHIP_ERROR GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key) const;
1187+
CHIP_ERROR GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key);
11881188

11891189
CHIP_ERROR InternalHash(const uint8_t * in, size_t in_len);
11901190
CHIP_ERROR WriteMN();

src/crypto/CHIPCryptoPALPSA.cpp

+37-14
Original file line numberDiff line numberDiff line change
@@ -284,45 +284,68 @@ CHIP_ERROR PsaKdf::Init(const ByteSpan & secret, const ByteSpan & salt, const By
284284
psa_reset_key_attributes(&attrs);
285285
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
286286

287-
return InitOperation(mSecretKeyId, salt, info);
287+
PsaHkdfKeyHandle hkdfKeyHandle = { .mKeyId = mSecretKeyId, .mIsKeyId = true };
288+
289+
return InitOperation(hkdfKeyHandle, salt, info);
288290
}
289291

290292
CHIP_ERROR PsaKdf::Init(const HkdfKeyHandle & hkdfKey, const ByteSpan & salt, const ByteSpan & info)
291293
{
292-
return InitOperation(hkdfKey.As<psa_key_id_t>(), salt, info);
294+
return InitOperation(hkdfKey.As<PsaHkdfKeyHandle>(), salt, info);
293295
}
294296

295-
CHIP_ERROR PsaKdf::InitOperation(psa_key_id_t hkdfKey, const ByteSpan & salt, const ByteSpan & info)
297+
CHIP_ERROR PsaKdf::InitOperation(PsaHkdfKeyHandle hkdfKey, const ByteSpan & salt, const ByteSpan & info)
296298
{
297-
psa_status_t status = psa_key_derivation_setup(&mOperation, PSA_ALG_HKDF(PSA_ALG_SHA_256));
298-
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
299-
300-
if (salt.size() > 0)
299+
psa_status_t status;
300+
if (hkdfKey.mIsKeyId)
301301
{
302-
status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_SALT, salt.data(), salt.size());
302+
status = psa_key_derivation_setup(&mOperation, PSA_ALG_HKDF(PSA_ALG_SHA_256));
303303
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
304+
305+
if (salt.size() > 0)
306+
{
307+
status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_SALT, salt.data(), salt.size());
308+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
309+
}
310+
311+
status = psa_key_derivation_input_key(&mOperation, PSA_KEY_DERIVATION_INPUT_SECRET, hkdfKey.mKeyId);
312+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
313+
314+
status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_INFO, info.data(), info.size());
315+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
316+
317+
mDerivationOperation = &mOperation;
304318
}
319+
else
320+
{
321+
mDerivationOperation = hkdfKey.mKeyDerivationOp;
305322

306-
status = psa_key_derivation_input_key(&mOperation, PSA_KEY_DERIVATION_INPUT_SECRET, hkdfKey);
307-
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
323+
if (salt.size() > 0)
324+
{
325+
status = psa_key_derivation_input_bytes(mDerivationOperation, PSA_KEY_DERIVATION_INPUT_SALT, salt.data(), salt.size());
326+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
327+
}
308328

309-
status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_INFO, info.data(), info.size());
310-
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
329+
status = psa_key_derivation_input_bytes(mDerivationOperation, PSA_KEY_DERIVATION_INPUT_INFO, info.data(), info.size());
330+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
331+
}
311332

312333
return CHIP_NO_ERROR;
313334
}
314335

315336
CHIP_ERROR PsaKdf::DeriveBytes(const MutableByteSpan & output)
316337
{
317-
psa_status_t status = psa_key_derivation_output_bytes(&mOperation, output.data(), output.size());
338+
psa_status_t status = psa_key_derivation_output_bytes(mDerivationOperation, output.data(), output.size());
339+
318340
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
319341

320342
return CHIP_NO_ERROR;
321343
}
322344

323345
CHIP_ERROR PsaKdf::DeriveKey(const psa_key_attributes_t & attributes, psa_key_id_t & keyId)
324346
{
325-
psa_status_t status = psa_key_derivation_output_key(&attributes, &mOperation, &keyId);
347+
psa_status_t status = psa_key_derivation_output_key(&attributes, mDerivationOperation, &keyId);
348+
326349
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
327350

328351
return CHIP_NO_ERROR;

src/crypto/CHIPCryptoPALPSA.h

+15-4
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,17 @@ inline const PsaP256KeypairContext & ToConstPsaContext(const P256KeypairContext
9595
return *SafePointerCast<const PsaP256KeypairContext *>(&context);
9696
}
9797

98+
struct PsaHkdfKeyHandle
99+
{
100+
union
101+
{
102+
psa_key_id_t mKeyId;
103+
psa_key_derivation_operation_t * mKeyDerivationOp;
104+
};
105+
106+
bool mIsKeyId = true;
107+
};
108+
98109
/**
99110
* @brief Wrapper for PSA key derivation API.
100111
*/
@@ -145,11 +156,11 @@ class PsaKdf
145156
CHIP_ERROR DeriveKey(const psa_key_attributes_t & attributes, psa_key_id_t & keyId);
146157

147158
private:
148-
CHIP_ERROR InitOperation(psa_key_id_t hkdfKey, const ByteSpan & salt, const ByteSpan & info);
159+
CHIP_ERROR InitOperation(PsaHkdfKeyHandle hkdfKey, const ByteSpan & salt, const ByteSpan & info);
149160

150-
psa_key_id_t mSecretKeyId = 0;
151-
psa_key_derivation_operation_t mOperation = PSA_KEY_DERIVATION_OPERATION_INIT;
161+
psa_key_id_t mSecretKeyId = PSA_KEY_ID_NULL;
162+
psa_key_derivation_operation_t mOperation = PSA_KEY_DERIVATION_OPERATION_INIT;
163+
psa_key_derivation_operation_t * mDerivationOperation = nullptr;
152164
};
153-
154165
} // namespace Crypto
155166
} // namespace chip

src/crypto/PSASessionKeystore.cpp

+12-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "PSASessionKeystore.h"
1919

20+
#include <lib/support/CHIPMem.h>
2021
#include <psa/crypto.h>
2122

2223
namespace chip {
@@ -185,10 +186,18 @@ void PSASessionKeystore::DestroyKey(Symmetric128BitsKeyHandle & key)
185186

186187
void PSASessionKeystore::DestroyKey(HkdfKeyHandle & key)
187188
{
188-
auto & keyId = key.AsMutable<psa_key_id_t>();
189+
auto & keyHandle = key.AsMutable<PsaHkdfKeyHandle>();
189190

190-
psa_destroy_key(keyId);
191-
keyId = 0;
191+
if (keyHandle.mIsKeyId)
192+
{
193+
psa_destroy_key(keyHandle.mKeyId);
194+
keyHandle.mKeyId = 0;
195+
}
196+
else
197+
{
198+
Platform::Delete(keyHandle.mKeyDerivationOp);
199+
keyHandle.mKeyDerivationOp = nullptr;
200+
}
192201
}
193202

194203
} // namespace Crypto

src/crypto/PSASpake2p.cpp

+20-11
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "CHIPCryptoPALPSA.h"
2121

22+
#include <lib/support/CHIPMem.h>
2223
#include <lib/support/CodeUtils.h>
2324

2425
#include <psa/crypto.h>
@@ -179,22 +180,30 @@ CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::KeyConfirm(const uint8_t * in, size
179180
return CHIP_NO_ERROR;
180181
}
181182

182-
CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::GetKeys(uint8_t * out, size_t * out_len)
183+
CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key)
183184
{
184-
VerifyOrReturnError(out != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
185-
VerifyOrReturnError(out_len != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
186-
187185
/*
188-
* TODO: either:
189-
* - use psa_pake_shared_secret() proposed in https://github.com/ARM-software/psa-api/issues/86
190-
* - refactor Matter's GetKeys API to take an abstract shared secret instead of raw secret bytes.
186+
* TODO: use psa_pake_shared_secret() proposed in https://github.com/ARM-software/psa-api/issues/86
191187
*/
192-
oberon_spake2p_operation_t & oberonCtx = mOperation.MBEDTLS_PRIVATE(ctx).oberon_pake_ctx.ctx.oberon_spake2p_ctx;
193188

194-
VerifyOrReturnError((oberonCtx.hash_len / 2) <= *out_len, CHIP_ERROR_BUFFER_TOO_SMALL);
189+
psa_key_derivation_operation_t * kdf = Platform::New<psa_key_derivation_operation_t>();
190+
Platform::UniquePtr<psa_key_derivation_operation_t> kdfPtr(kdf);
191+
192+
VerifyOrReturnError(kdfPtr, CHIP_ERROR_NO_MEMORY);
193+
194+
*kdfPtr = PSA_KEY_DERIVATION_OPERATION_INIT;
195+
196+
psa_status_t status = psa_key_derivation_setup(kdfPtr.get(), PSA_ALG_HKDF(PSA_ALG_SHA_256));
197+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
198+
199+
status = psa_pake_get_implicit_key(&mOperation, kdfPtr.get());
200+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
201+
202+
auto & hkdfKeyHandle = key.AsMutable<PsaHkdfKeyHandle>();
203+
hkdfKeyHandle.mKeyDerivationOp = kdfPtr.get();
204+
hkdfKeyHandle.mIsKeyId = false;
195205

196-
memcpy(out, oberonCtx.shared, oberonCtx.hash_len / 2);
197-
*out_len = oberonCtx.hash_len / 2;
206+
kdfPtr.release();
198207

199208
return CHIP_NO_ERROR;
200209
}

src/crypto/PSASpake2p.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#pragma once
1919

2020
#include "CHIPCryptoPAL.h"
21+
#include <crypto/SessionKeystore.h>
2122

2223
#include <psa/crypto.h>
2324

@@ -144,14 +145,14 @@ class PSASpake2p_P256_SHA256_HKDF_HMAC
144145
CHIP_ERROR KeyConfirm(const uint8_t * in, size_t in_len);
145146

146147
/**
147-
* @brief Return the shared secret.
148+
* @brief Return the HKDF Key handle containing a key reference to the shared secret.
148149
*
149-
* @param out The output secret.
150-
* @param out_len The output secret length.
150+
* @param keystore The session keystore for managing the HKDF key lifetime.
151+
* @param key The output HKDF key.
151152
*
152153
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
153154
**/
154-
CHIP_ERROR GetKeys(uint8_t * out, size_t * out_len);
155+
CHIP_ERROR GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key);
155156

156157
private:
157158
psa_pake_operation_t mOperation = PSA_PAKE_OPERATION_INIT;

src/platform/nrfconnect/CHIPPlatformConfig.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040

4141
#ifdef CONFIG_CHIP_CRYPTO_PSA
4242
#define CHIP_CONFIG_SHA256_CONTEXT_SIZE sizeof(psa_hash_operation_t)
43-
#define CHIP_CONFIG_HKDF_KEY_HANDLE_CONTEXT_SIZE sizeof(psa_key_id_t)
43+
// Alignment to sizeof(PsaHkdfKeyHandle) from crypto/CHIPCryptoPALPSA.h.
44+
#define CHIP_CONFIG_HKDF_KEY_HANDLE_CONTEXT_SIZE (sizeof(psa_key_id_t) + sizeof(bool))
4445
#elif defined(CONFIG_CC3XX_BACKEND)
4546
// Size of the statically allocated context for SHA256 operations in CryptoPAL
4647
// determined empirically.

src/protocols/secure_channel/CASESession.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ void CASESession::AbortPendingEstablish(CHIP_ERROR err)
560560
NotifySessionEstablishmentError(err);
561561
}
562562

563-
CHIP_ERROR CASESession::DeriveSecureSession(CryptoContext & session) const
563+
CHIP_ERROR CASESession::DeriveSecureSession(CryptoContext & session)
564564
{
565565
switch (mState)
566566
{

src/protocols/secure_channel/CASESession.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler,
146146
* @param session Reference to the secure session that will be initialized once session establishment is complete
147147
* @return CHIP_ERROR The result of session derivation
148148
*/
149-
CHIP_ERROR DeriveSecureSession(CryptoContext & session) const override;
149+
CHIP_ERROR DeriveSecureSession(CryptoContext & session) override;
150150

151151
//// UnsolicitedMessageHandler Implementation ////
152152
CHIP_ERROR OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader, ExchangeDelegate *& newDelegate) override

src/protocols/secure_channel/PASESession.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ void PASESession::OnResponseTimeout(ExchangeContext * ec)
253253
NotifySessionEstablishmentError(CHIP_ERROR_TIMEOUT);
254254
}
255255

256-
CHIP_ERROR PASESession::DeriveSecureSession(CryptoContext & session) const
256+
CHIP_ERROR PASESession::DeriveSecureSession(CryptoContext & session)
257257
{
258258
VerifyOrReturnError(mPairingComplete, CHIP_ERROR_INCORRECT_STATE);
259259

src/protocols/secure_channel/PASESession.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ class DLL_EXPORT PASESession : public Messaging::UnsolicitedMessageHandler,
141141
* @param session Reference to the secure session that will be initialized once pairing is complete
142142
* @return CHIP_ERROR The result of session derivation
143143
*/
144-
CHIP_ERROR DeriveSecureSession(CryptoContext & session) const override;
144+
CHIP_ERROR DeriveSecureSession(CryptoContext & session) override;
145145

146146
// TODO: remove Clear, we should create a new instance instead reset the old instance.
147147
/** @brief This function zeroes out and resets the memory used by the object.

src/protocols/secure_channel/PairingSession.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class DLL_EXPORT PairingSession : public SessionDelegate
9494
* @param session Reference to the secure session that will be initialized once pairing is complete
9595
* @return CHIP_ERROR The result of session derivation
9696
*/
97-
virtual CHIP_ERROR DeriveSecureSession(CryptoContext & session) const = 0;
97+
virtual CHIP_ERROR DeriveSecureSession(CryptoContext & session) = 0;
9898

9999
const ReliableMessageProtocolConfig & GetRemoteMRPConfig() const { return mRemoteMRPConfig; }
100100
void SetRemoteMRPConfig(const ReliableMessageProtocolConfig & config) { mRemoteMRPConfig = config; }

src/protocols/secure_channel/tests/TestPairingSession.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class TestPairingSession : public PairingSession
4848

4949
const ReliableMessageProtocolConfig & GetRemoteMRPConfig() const { return mRemoteMRPConfig; }
5050

51-
CHIP_ERROR DeriveSecureSession(CryptoContext & session) const override { return CHIP_NO_ERROR; }
51+
CHIP_ERROR DeriveSecureSession(CryptoContext & session) override { return CHIP_NO_ERROR; }
5252

5353
CHIP_ERROR DecodeMRPParametersIfPresent(TLV::Tag expectedTag, System::PacketBufferTLVReader & tlvReader)
5454
{

0 commit comments

Comments
 (0)