Skip to content

Commit

Permalink
[crypto] PSA SPAKE2+ introduction (#32924)
Browse files Browse the repository at this point in the history
* [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 <[email protected]>

* [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 <[email protected]>
Co-authored-by: Damian Krolik <[email protected]>
  • Loading branch information
ArekBalysNordic and Damian-Nordic authored Apr 25, 2024
1 parent 6d9dfe9 commit f9a3601
Show file tree
Hide file tree
Showing 16 changed files with 401 additions and 11 deletions.
3 changes: 2 additions & 1 deletion config/nrfconnect/chip-module/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ else()
endif()

if (CONFIG_CHIP_CRYPTO_PSA)
matter_add_gn_arg_string("chip_crypto" "psa")
matter_add_gn_arg_string("chip_crypto" "psa")
matter_add_gn_arg_bool ("chip_crypto_psa_spake2p" CONFIG_PSA_WANT_ALG_SPAKE2P_MATTER)
endif()

if (BOARD STREQUAL "native_posix")
Expand Down
1 change: 1 addition & 0 deletions config/nrfconnect/chip-module/Kconfig.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ config MBEDTLS_HEAP_SIZE

config CHIP_CRYPTO_PSA
default y if !CHIP_WIFI
imply PSA_WANT_ALG_SPAKE2P_MATTER

if CHIP_CRYPTO_PSA

Expand Down
8 changes: 8 additions & 0 deletions src/crypto/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ buildconfig_header("crypto_buildconfig") {
defines = [
"CHIP_CRYPTO_MBEDTLS=${chip_crypto_mbedtls}",
"CHIP_CRYPTO_PSA=${chip_crypto_psa}",
"CHIP_CRYPTO_PSA_SPAKE2P=${chip_crypto_psa_spake2p}",
"CHIP_CRYPTO_OPENSSL=${chip_crypto_openssl}",
"CHIP_CRYPTO_BORINGSSL=${chip_crypto_boringssl}",
"CHIP_CRYPTO_PLATFORM=${chip_crypto_platform}",
Expand Down Expand Up @@ -156,6 +157,13 @@ static_library("crypto") {
]
}

if (chip_crypto_psa_spake2p) {
sources += [
"PSASpake2p.cpp",
"PSASpake2p.h",
]
}

public_configs = []

cflags = [ "-Wconversion" ]
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/CHIPCryptoPAL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ CHIP_ERROR Spake2p::KeyConfirm(const uint8_t * in, size_t in_len)
return CHIP_NO_ERROR;
}

CHIP_ERROR Spake2p::GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key) const
CHIP_ERROR Spake2p::GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key)
{
VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::KC, CHIP_ERROR_INTERNAL);

Expand Down
2 changes: 1 addition & 1 deletion src/crypto/CHIPCryptoPAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -1216,7 +1216,7 @@ class Spake2p
*
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key) const;
CHIP_ERROR GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key);

CHIP_ERROR InternalHash(const uint8_t * in, size_t in_len);
CHIP_ERROR WriteMN();
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/CHIPCryptoPALPSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class PsaKdf
private:
CHIP_ERROR InitOperation(psa_key_id_t hkdfKey, const ByteSpan & salt, const ByteSpan & info);

psa_key_id_t mSecretKeyId = 0;
psa_key_id_t mSecretKeyId = PSA_KEY_ID_NULL;
psa_key_derivation_operation_t mOperation = PSA_KEY_DERIVATION_OPERATION_INIT;
};

Expand Down
2 changes: 1 addition & 1 deletion src/crypto/PSASessionKeystore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ void PSASessionKeystore::DestroyKey(HkdfKeyHandle & key)
auto & keyId = key.AsMutable<psa_key_id_t>();

psa_destroy_key(keyId);
keyId = 0;
keyId = PSA_KEY_ID_NULL;
}

} // namespace Crypto
Expand Down
201 changes: 201 additions & 0 deletions src/crypto/PSASpake2p.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/*
* Copyright (c) 2024 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 "PSASpake2p.h"

#include "CHIPCryptoPALPSA.h"

#include <lib/support/CodeUtils.h>

#include <psa/crypto.h>

namespace chip {
namespace Crypto {

CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::Init(const uint8_t * context, size_t context_len)
{
Clear();

VerifyOrReturnError(context_len <= sizeof(mContext), CHIP_ERROR_BUFFER_TOO_SMALL);

memcpy(mContext, context, context_len);
mContextLen = context_len;

return CHIP_NO_ERROR;
}

void PSASpake2p_P256_SHA256_HKDF_HMAC::Clear()
{
IgnoreUnusedVariable(psa_pake_abort(&mOperation));
mOperation = psa_pake_operation_init();

IgnoreUnusedVariable(psa_destroy_key(mKey));
mKey = PSA_KEY_ID_NULL;
}

CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::BeginVerifier(const uint8_t * my_identity, size_t my_identity_len,
const uint8_t * peer_identity, size_t peer_identity_len,
const uint8_t * w0in, size_t w0in_len, const uint8_t * Lin,
size_t Lin_len)
{
VerifyOrReturnError(w0in_len <= kSpake2p_WS_Length, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(Lin_len == kP256_Point_Length, CHIP_ERROR_INVALID_ARGUMENT);

uint8_t password[kSpake2p_WS_Length + kP256_Point_Length];
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_pake_cipher_suite_t cp = PSA_PAKE_CIPHER_SUITE_INIT;

psa_pake_cs_set_algorithm(&cp, PSA_ALG_SPAKE2P_MATTER);
psa_pake_cs_set_primitive(&cp, PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256));

memcpy(password + 0, w0in, w0in_len);
memcpy(password + w0in_len, Lin, Lin_len);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
psa_set_key_algorithm(&attributes, PSA_ALG_SPAKE2P_MATTER);
psa_set_key_type(&attributes, PSA_KEY_TYPE_SPAKE2P_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));

psa_status_t status = psa_import_key(&attributes, password, w0in_len + Lin_len, &mKey);

psa_reset_key_attributes(&attributes);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

status = psa_pake_setup(&mOperation, mKey, &cp);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

mRole = PSA_PAKE_ROLE_SERVER;
status = psa_pake_set_role(&mOperation, PSA_PAKE_ROLE_SERVER);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

status = psa_pake_set_peer(&mOperation, peer_identity, peer_identity_len);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

status = psa_pake_set_user(&mOperation, my_identity, my_identity_len);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

status = psa_pake_set_context(&mOperation, mContext, mContextLen);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

return CHIP_NO_ERROR;
}

CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::BeginProver(const uint8_t * my_identity, size_t my_identity_len,
const uint8_t * peer_identity, size_t peer_identity_len,
const uint8_t * w0in, size_t w0in_len, const uint8_t * w1in,
size_t w1in_len)
{
VerifyOrReturnError(w0in_len <= kSpake2p_WS_Length, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(w1in_len <= kSpake2p_WS_Length, CHIP_ERROR_INVALID_ARGUMENT);

uint8_t password[kSpake2p_WS_Length * 2];
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_pake_cipher_suite_t cp = PSA_PAKE_CIPHER_SUITE_INIT;

psa_pake_cs_set_algorithm(&cp, PSA_ALG_SPAKE2P_MATTER);
psa_pake_cs_set_primitive(&cp, PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256));

memcpy(password + 0, w0in, w0in_len);
memcpy(password + w0in_len, w1in, w1in_len);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
psa_set_key_algorithm(&attributes, PSA_ALG_SPAKE2P_MATTER);
psa_set_key_type(&attributes, PSA_KEY_TYPE_SPAKE2P_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));

psa_status_t status = psa_import_key(&attributes, password, w0in_len + w1in_len, &mKey);

psa_reset_key_attributes(&attributes);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

status = psa_pake_setup(&mOperation, mKey, &cp);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

mRole = PSA_PAKE_ROLE_CLIENT;
status = psa_pake_set_role(&mOperation, PSA_PAKE_ROLE_CLIENT);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

status = psa_pake_set_user(&mOperation, my_identity, my_identity_len);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

status = psa_pake_set_peer(&mOperation, peer_identity, peer_identity_len);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

status = psa_pake_set_context(&mOperation, mContext, mContextLen);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

return CHIP_NO_ERROR;
}

CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::ComputeRoundOne(const uint8_t * pab, size_t pab_len, uint8_t * out, size_t * out_len)
{
VerifyOrReturnError(out_len != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

psa_status_t status;

if (mRole == PSA_PAKE_ROLE_SERVER)
{
status = psa_pake_input(&mOperation, PSA_PAKE_STEP_KEY_SHARE, pab, pab_len);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
}

status = psa_pake_output(&mOperation, PSA_PAKE_STEP_KEY_SHARE, out, *out_len, out_len);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

return CHIP_NO_ERROR;
}

CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::ComputeRoundTwo(const uint8_t * in, size_t in_len, uint8_t * out, size_t * out_len)
{
VerifyOrReturnError(out_len != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

psa_status_t status;

if (mRole == PSA_PAKE_ROLE_CLIENT)
{
status = psa_pake_input(&mOperation, PSA_PAKE_STEP_KEY_SHARE, in, in_len);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
}

status = psa_pake_output(&mOperation, PSA_PAKE_STEP_CONFIRM, out, *out_len, out_len);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

return CHIP_NO_ERROR;
}

CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::KeyConfirm(const uint8_t * in, size_t in_len)
{
psa_status_t status = psa_pake_input(&mOperation, PSA_PAKE_STEP_CONFIRM, in, in_len);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

return CHIP_NO_ERROR;
}

CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key)
{
auto & keyId = key.AsMutable<psa_key_id_t>();

psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;

psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
psa_set_key_algorithm(&attributes, PSA_ALG_HKDF(PSA_ALG_SHA_256));

psa_status_t status = psa_pake_get_shared_key(&(mOperation), &attributes, &keyId);
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);

return CHIP_NO_ERROR;
}

} // namespace Crypto
} // namespace chip
Loading

0 comments on commit f9a3601

Please sign in to comment.