Skip to content

Commit f9a3601

Browse files
[crypto] PSA SPAKE2+ introduction (#32924)
* [crypto] Add PSA SPAKE2+ implementation Implement Matter's SPAKE2+ protocol using PSA crypto API. Use the PSA implementation in PASE session for nRF Connect platform. Signed-off-by: Damian Krolik <damian.krolik@nordicsemi.no> * [crypto] Spake2+ alignments regarding the newest PSA version Aligned Spake2+ algorithm to the newest PSA Crypto API version that allows useing the psa_pake_get_shared_key function. * Alignments to the Matter Core. Restyled by gn --------- Signed-off-by: Damian Krolik <damian.krolik@nordicsemi.no> Co-authored-by: Damian Krolik <damian.krolik@nordicsemi.no>
1 parent 6d9dfe9 commit f9a3601

16 files changed

+401
-11
lines changed

config/nrfconnect/chip-module/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ else()
168168
endif()
169169

170170
if (CONFIG_CHIP_CRYPTO_PSA)
171-
matter_add_gn_arg_string("chip_crypto" "psa")
171+
matter_add_gn_arg_string("chip_crypto" "psa")
172+
matter_add_gn_arg_bool ("chip_crypto_psa_spake2p" CONFIG_PSA_WANT_ALG_SPAKE2P_MATTER)
172173
endif()
173174

174175
if (BOARD STREQUAL "native_posix")

config/nrfconnect/chip-module/Kconfig.defaults

+1
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ config MBEDTLS_HEAP_SIZE
298298

299299
config CHIP_CRYPTO_PSA
300300
default y if !CHIP_WIFI
301+
imply PSA_WANT_ALG_SPAKE2P_MATTER
301302

302303
if CHIP_CRYPTO_PSA
303304

src/crypto/BUILD.gn

+8
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ buildconfig_header("crypto_buildconfig") {
5151
defines = [
5252
"CHIP_CRYPTO_MBEDTLS=${chip_crypto_mbedtls}",
5353
"CHIP_CRYPTO_PSA=${chip_crypto_psa}",
54+
"CHIP_CRYPTO_PSA_SPAKE2P=${chip_crypto_psa_spake2p}",
5455
"CHIP_CRYPTO_OPENSSL=${chip_crypto_openssl}",
5556
"CHIP_CRYPTO_BORINGSSL=${chip_crypto_boringssl}",
5657
"CHIP_CRYPTO_PLATFORM=${chip_crypto_platform}",
@@ -156,6 +157,13 @@ static_library("crypto") {
156157
]
157158
}
158159

160+
if (chip_crypto_psa_spake2p) {
161+
sources += [
162+
"PSASpake2p.cpp",
163+
"PSASpake2p.h",
164+
]
165+
}
166+
159167
public_configs = []
160168

161169
cflags = [ "-Wconversion" ]

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
@@ -1216,7 +1216,7 @@ class Spake2p
12161216
*
12171217
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
12181218
**/
1219-
CHIP_ERROR GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key) const;
1219+
CHIP_ERROR GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key);
12201220

12211221
CHIP_ERROR InternalHash(const uint8_t * in, size_t in_len);
12221222
CHIP_ERROR WriteMN();

src/crypto/CHIPCryptoPALPSA.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ class PsaKdf
146146
private:
147147
CHIP_ERROR InitOperation(psa_key_id_t hkdfKey, const ByteSpan & salt, const ByteSpan & info);
148148

149-
psa_key_id_t mSecretKeyId = 0;
149+
psa_key_id_t mSecretKeyId = PSA_KEY_ID_NULL;
150150
psa_key_derivation_operation_t mOperation = PSA_KEY_DERIVATION_OPERATION_INIT;
151151
};
152152

src/crypto/PSASessionKeystore.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ void PSASessionKeystore::DestroyKey(HkdfKeyHandle & key)
188188
auto & keyId = key.AsMutable<psa_key_id_t>();
189189

190190
psa_destroy_key(keyId);
191-
keyId = 0;
191+
keyId = PSA_KEY_ID_NULL;
192192
}
193193

194194
} // namespace Crypto

src/crypto/PSASpake2p.cpp

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/*
2+
* Copyright (c) 2024 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 "PSASpake2p.h"
19+
20+
#include "CHIPCryptoPALPSA.h"
21+
22+
#include <lib/support/CodeUtils.h>
23+
24+
#include <psa/crypto.h>
25+
26+
namespace chip {
27+
namespace Crypto {
28+
29+
CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::Init(const uint8_t * context, size_t context_len)
30+
{
31+
Clear();
32+
33+
VerifyOrReturnError(context_len <= sizeof(mContext), CHIP_ERROR_BUFFER_TOO_SMALL);
34+
35+
memcpy(mContext, context, context_len);
36+
mContextLen = context_len;
37+
38+
return CHIP_NO_ERROR;
39+
}
40+
41+
void PSASpake2p_P256_SHA256_HKDF_HMAC::Clear()
42+
{
43+
IgnoreUnusedVariable(psa_pake_abort(&mOperation));
44+
mOperation = psa_pake_operation_init();
45+
46+
IgnoreUnusedVariable(psa_destroy_key(mKey));
47+
mKey = PSA_KEY_ID_NULL;
48+
}
49+
50+
CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::BeginVerifier(const uint8_t * my_identity, size_t my_identity_len,
51+
const uint8_t * peer_identity, size_t peer_identity_len,
52+
const uint8_t * w0in, size_t w0in_len, const uint8_t * Lin,
53+
size_t Lin_len)
54+
{
55+
VerifyOrReturnError(w0in_len <= kSpake2p_WS_Length, CHIP_ERROR_INVALID_ARGUMENT);
56+
VerifyOrReturnError(Lin_len == kP256_Point_Length, CHIP_ERROR_INVALID_ARGUMENT);
57+
58+
uint8_t password[kSpake2p_WS_Length + kP256_Point_Length];
59+
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
60+
psa_pake_cipher_suite_t cp = PSA_PAKE_CIPHER_SUITE_INIT;
61+
62+
psa_pake_cs_set_algorithm(&cp, PSA_ALG_SPAKE2P_MATTER);
63+
psa_pake_cs_set_primitive(&cp, PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256));
64+
65+
memcpy(password + 0, w0in, w0in_len);
66+
memcpy(password + w0in_len, Lin, Lin_len);
67+
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
68+
psa_set_key_algorithm(&attributes, PSA_ALG_SPAKE2P_MATTER);
69+
psa_set_key_type(&attributes, PSA_KEY_TYPE_SPAKE2P_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
70+
71+
psa_status_t status = psa_import_key(&attributes, password, w0in_len + Lin_len, &mKey);
72+
73+
psa_reset_key_attributes(&attributes);
74+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
75+
76+
status = psa_pake_setup(&mOperation, mKey, &cp);
77+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
78+
79+
mRole = PSA_PAKE_ROLE_SERVER;
80+
status = psa_pake_set_role(&mOperation, PSA_PAKE_ROLE_SERVER);
81+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
82+
83+
status = psa_pake_set_peer(&mOperation, peer_identity, peer_identity_len);
84+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
85+
86+
status = psa_pake_set_user(&mOperation, my_identity, my_identity_len);
87+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
88+
89+
status = psa_pake_set_context(&mOperation, mContext, mContextLen);
90+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
91+
92+
return CHIP_NO_ERROR;
93+
}
94+
95+
CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::BeginProver(const uint8_t * my_identity, size_t my_identity_len,
96+
const uint8_t * peer_identity, size_t peer_identity_len,
97+
const uint8_t * w0in, size_t w0in_len, const uint8_t * w1in,
98+
size_t w1in_len)
99+
{
100+
VerifyOrReturnError(w0in_len <= kSpake2p_WS_Length, CHIP_ERROR_INVALID_ARGUMENT);
101+
VerifyOrReturnError(w1in_len <= kSpake2p_WS_Length, CHIP_ERROR_INVALID_ARGUMENT);
102+
103+
uint8_t password[kSpake2p_WS_Length * 2];
104+
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
105+
psa_pake_cipher_suite_t cp = PSA_PAKE_CIPHER_SUITE_INIT;
106+
107+
psa_pake_cs_set_algorithm(&cp, PSA_ALG_SPAKE2P_MATTER);
108+
psa_pake_cs_set_primitive(&cp, PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256));
109+
110+
memcpy(password + 0, w0in, w0in_len);
111+
memcpy(password + w0in_len, w1in, w1in_len);
112+
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
113+
psa_set_key_algorithm(&attributes, PSA_ALG_SPAKE2P_MATTER);
114+
psa_set_key_type(&attributes, PSA_KEY_TYPE_SPAKE2P_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
115+
116+
psa_status_t status = psa_import_key(&attributes, password, w0in_len + w1in_len, &mKey);
117+
118+
psa_reset_key_attributes(&attributes);
119+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
120+
121+
status = psa_pake_setup(&mOperation, mKey, &cp);
122+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
123+
124+
mRole = PSA_PAKE_ROLE_CLIENT;
125+
status = psa_pake_set_role(&mOperation, PSA_PAKE_ROLE_CLIENT);
126+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
127+
128+
status = psa_pake_set_user(&mOperation, my_identity, my_identity_len);
129+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
130+
131+
status = psa_pake_set_peer(&mOperation, peer_identity, peer_identity_len);
132+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
133+
134+
status = psa_pake_set_context(&mOperation, mContext, mContextLen);
135+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
136+
137+
return CHIP_NO_ERROR;
138+
}
139+
140+
CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::ComputeRoundOne(const uint8_t * pab, size_t pab_len, uint8_t * out, size_t * out_len)
141+
{
142+
VerifyOrReturnError(out_len != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
143+
144+
psa_status_t status;
145+
146+
if (mRole == PSA_PAKE_ROLE_SERVER)
147+
{
148+
status = psa_pake_input(&mOperation, PSA_PAKE_STEP_KEY_SHARE, pab, pab_len);
149+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
150+
}
151+
152+
status = psa_pake_output(&mOperation, PSA_PAKE_STEP_KEY_SHARE, out, *out_len, out_len);
153+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
154+
155+
return CHIP_NO_ERROR;
156+
}
157+
158+
CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::ComputeRoundTwo(const uint8_t * in, size_t in_len, uint8_t * out, size_t * out_len)
159+
{
160+
VerifyOrReturnError(out_len != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
161+
162+
psa_status_t status;
163+
164+
if (mRole == PSA_PAKE_ROLE_CLIENT)
165+
{
166+
status = psa_pake_input(&mOperation, PSA_PAKE_STEP_KEY_SHARE, in, in_len);
167+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
168+
}
169+
170+
status = psa_pake_output(&mOperation, PSA_PAKE_STEP_CONFIRM, out, *out_len, out_len);
171+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
172+
173+
return CHIP_NO_ERROR;
174+
}
175+
176+
CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::KeyConfirm(const uint8_t * in, size_t in_len)
177+
{
178+
psa_status_t status = psa_pake_input(&mOperation, PSA_PAKE_STEP_CONFIRM, in, in_len);
179+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
180+
181+
return CHIP_NO_ERROR;
182+
}
183+
184+
CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key)
185+
{
186+
auto & keyId = key.AsMutable<psa_key_id_t>();
187+
188+
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
189+
190+
psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE);
191+
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
192+
psa_set_key_algorithm(&attributes, PSA_ALG_HKDF(PSA_ALG_SHA_256));
193+
194+
psa_status_t status = psa_pake_get_shared_key(&(mOperation), &attributes, &keyId);
195+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
196+
197+
return CHIP_NO_ERROR;
198+
}
199+
200+
} // namespace Crypto
201+
} // namespace chip

0 commit comments

Comments
 (0)