From a1ce10690f528fc0490dd5c45315659b75e69455 Mon Sep 17 00:00:00 2001 From: Maciej Baczmanski Date: Tue, 6 Aug 2024 14:33:12 +0200 Subject: [PATCH] WIP --- src/app/chip_data_model.cmake | 6 +- .../icd-management-server.cpp | 2 +- src/app/icd/server/ICDMonitoringTable.cpp | 35 ++++++-- src/app/icd/server/ICDMonitoringTable.h | 5 +- src/crypto/BUILD.gn | 1 + src/crypto/CHIPCryptoPALPSA.cpp | 22 +++++ src/crypto/CHIPCryptoPALPSA.h | 35 +++++++- src/crypto/PSASessionKeystore.cpp | 81 ++++++++++--------- 8 files changed, 133 insertions(+), 54 deletions(-) diff --git a/src/app/chip_data_model.cmake b/src/app/chip_data_model.cmake index 499bf100256546..ca664c78bc6f04 100644 --- a/src/app/chip_data_model.cmake +++ b/src/app/chip_data_model.cmake @@ -142,9 +142,9 @@ function(chip_configure_data_model APP_TARGET) ${CHIP_APP_BASE_DIR}/util/attribute-storage.cpp ${CHIP_APP_BASE_DIR}/util/attribute-table.cpp ${CHIP_APP_BASE_DIR}/util/binding-table.cpp - ${CHIP_APP_BASE_DIR}/icd/server/ICDMonitoringTable.cpp - ${CHIP_APP_BASE_DIR}/icd/server/ICDNotifier.cpp - ${CHIP_APP_BASE_DIR}/icd/server/ICDConfigurationData.cpp + # ${CHIP_APP_BASE_DIR}/icd/server/ICDMonitoringTable.cpp + # ${CHIP_APP_BASE_DIR}/icd/server/ICDNotifier.cpp + # ${CHIP_APP_BASE_DIR}/icd/server/ICDConfigurationData.cpp ${CHIP_APP_BASE_DIR}/util/DataModelHandler.cpp ${CHIP_APP_BASE_DIR}/util/ember-compatibility-functions.cpp ${CHIP_APP_BASE_DIR}/util/ember-global-attribute-access-interface.cpp diff --git a/src/app/clusters/icd-management-server/icd-management-server.cpp b/src/app/clusters/icd-management-server/icd-management-server.cpp index 8445cad117c2a3..ded0eddc8dcc03 100644 --- a/src/app/clusters/icd-management-server/icd-management-server.cpp +++ b/src/app/clusters/icd-management-server/icd-management-server.cpp @@ -312,7 +312,7 @@ Status ICDManagementServer::RegisterClient(CommandHandler * commandObj, const Co entry.DeleteKey(); } - err = entry.SetKey(key); + err = entry.SetKey(key, true); VerifyOrReturnError(CHIP_ERROR_INVALID_ARGUMENT != err, Status::ConstraintError); VerifyOrReturnError(CHIP_NO_ERROR == err, Status::Failure); err = table.Set(entry.index, entry); diff --git a/src/app/icd/server/ICDMonitoringTable.cpp b/src/app/icd/server/ICDMonitoringTable.cpp index 8148a7fe33b237..f5c44149de7411 100644 --- a/src/app/icd/server/ICDMonitoringTable.cpp +++ b/src/app/icd/server/ICDMonitoringTable.cpp @@ -19,6 +19,10 @@ #include +#ifdef CONFIG_CHIP_CRYPTO_PSA +#include +#endif + namespace chip { enum class Fields : uint8_t @@ -131,7 +135,7 @@ void ICDMonitoringEntry::Clear() this->clientType = app::Clusters::IcdManagement::ClientTypeEnum::kPermanent; } -CHIP_ERROR ICDMonitoringEntry::SetKey(ByteSpan keyData) +CHIP_ERROR ICDMonitoringEntry::SetKey(ByteSpan keyData, bool persistent) { VerifyOrReturnError(keyData.size() == sizeof(Crypto::Symmetric128BitsKeyByteArray), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(symmetricKeystore != nullptr, CHIP_ERROR_INTERNAL); @@ -140,7 +144,20 @@ CHIP_ERROR ICDMonitoringEntry::SetKey(ByteSpan keyData) Crypto::Symmetric128BitsKeyByteArray keyMaterial; memcpy(keyMaterial, keyData.data(), sizeof(Crypto::Symmetric128BitsKeyByteArray)); - // TODO - Add function to set PSA key lifetime +#ifdef CONFIG_CHIP_CRYPTO_PSA + if (persistent) + { + ReturnErrorOnFailure(Crypto::FindFreeKeySlotInRange(aesKeyHandle.AsMutable(), + to_underlying(Crypto::KeyIdBase::ICDAesKeyRangeStart), + Crypto::kMaxICDClientKeys)); + ReturnErrorOnFailure(Crypto::FindFreeKeySlotInRange(hmacKeyHandle.AsMutable(), + to_underlying(Crypto::KeyIdBase::ICDHmacKeyRangeStart), + Crypto::kMaxICDClientKeys)); + } +#else + IgnoreUnusedVariable(persistent); +#endif // CONFIG_CHIP_CRYPTO_PSA + ReturnErrorOnFailure(symmetricKeystore->CreateKey(keyMaterial, aesKeyHandle)); CHIP_ERROR error = symmetricKeystore->CreateKey(keyMaterial, hmacKeyHandle); @@ -242,15 +259,21 @@ CHIP_ERROR ICDMonitoringTable::Get(uint16_t index, ICDMonitoringEntry & entry) c CHIP_ERROR ICDMonitoringTable::Find(NodeId id, ICDMonitoringEntry & entry) { - uint16_t index = 0; - while (index < this->Limit()) + CHIP_ERROR err; + uint16_t index; + ICDMonitoringEntry tempEntry(mSymmetricKeystore); + + for (index = 0; index < this->Limit(); index++) { - ReturnErrorOnFailure(this->Get(index++, entry)); - if (id == entry.checkInNodeID) + SuccessOrExit(err = this->Get(index, tempEntry)); + if (id == tempEntry.checkInNodeID) { + entry = tempEntry; return CHIP_NO_ERROR; } } + +exit: entry.index = index; return CHIP_ERROR_NOT_FOUND; } diff --git a/src/app/icd/server/ICDMonitoringTable.h b/src/app/icd/server/ICDMonitoringTable.h index 942c56fda45e71..2ee72b04afb34e 100644 --- a/src/app/icd/server/ICDMonitoringTable.h +++ b/src/app/icd/server/ICDMonitoringTable.h @@ -69,13 +69,14 @@ struct ICDMonitoringEntry : public PersistentData * A new entry object should be used for each key when adding entries to the ICDMonitoring * table. * - * @param keyData A byte span containing the raw key + * @param keyData A byte span containing the raw key + * @param persistent Persistence of the key to be set (optional, needed only when setting persistent key with PSA Crypto API) * @return CHIP_ERROR CHIP_NO_ERROR success * CHIP_ERROR_INVALID_ARGUMENT wrong size of the raw key * CHIP_ERROR_INTERNAL No KeyStore for the entry or Key Handle already present * CHIP_ERROR_XXX Crypto API related failure */ - CHIP_ERROR SetKey(ByteSpan keyData); + CHIP_ERROR SetKey(ByteSpan keyData, bool persistent = false); CHIP_ERROR DeleteKey(void); inline bool IsValid() { diff --git a/src/crypto/BUILD.gn b/src/crypto/BUILD.gn index 1fb8b94f39a82f..9de65971ecaac8 100644 --- a/src/crypto/BUILD.gn +++ b/src/crypto/BUILD.gn @@ -71,6 +71,7 @@ source_set("public_headers") { "${chip_root}/src/lib/core", "${chip_root}/src/lib/core:types", "${chip_root}/src/lib/support", + "${chip_root}/src/app/icd/server:icd-server-config", "${nlassert_root}:nlassert", ] } diff --git a/src/crypto/CHIPCryptoPALPSA.cpp b/src/crypto/CHIPCryptoPALPSA.cpp index 6eccb1dde8f1ab..7fc9f93aeebe45 100644 --- a/src/crypto/CHIPCryptoPALPSA.cpp +++ b/src/crypto/CHIPCryptoPALPSA.cpp @@ -263,6 +263,28 @@ void Hash_SHA256_stream::Clear() psa_hash_abort(toHashOperation(&mContext)); } +CHIP_ERROR FindFreeKeySlotInRange(psa_key_id_t & keyId, psa_key_id_t start, uint32_t range) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t end = start + range; + + VerifyOrReturnError(start >= PSA_KEY_ID_USER_MIN && end - 1 <= PSA_KEY_ID_USER_MAX, CHIP_ERROR_INVALID_ARGUMENT); + + for(keyId = start; keyId < end; keyId++) + { + psa_status_t status = psa_get_key_attributes(keyId, &attributes); + if (status == PSA_ERROR_INVALID_HANDLE) + { + return CHIP_NO_ERROR; + } + else if (status != PSA_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } + } + return CHIP_ERROR_NOT_FOUND; +} + CHIP_ERROR PsaKdf::Init(const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info) { psa_status_t status = PSA_SUCCESS; diff --git a/src/crypto/CHIPCryptoPALPSA.h b/src/crypto/CHIPCryptoPALPSA.h index 8fa3dc57a54024..6b101c56cf518f 100644 --- a/src/crypto/CHIPCryptoPALPSA.h +++ b/src/crypto/CHIPCryptoPALPSA.h @@ -27,6 +27,7 @@ #pragma once #include "CHIPCryptoPAL.h" +#include #include #include @@ -55,19 +56,47 @@ namespace Crypto { #define CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE 0x30000 #endif // CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE +#if CHIP_CONFIG_ENABLE_ICD_CIP +static constexpr uint32_t kMaxICDClientKeys = CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC * CHIP_CONFIG_MAX_FABRICS; +#endif // CHIP_CONFIG_ENABLE_ICD_CIP + /** * @brief Defines subranges of the PSA key identifier space used by Matter. */ enum class KeyIdBase : psa_key_id_t { - Minimum = CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE, - Operational = Minimum, ///< Base of the PSA key ID range for Node Operational Certificate private keys - Maximum = Operational + kMaxValidFabricIndex, + Minimum = CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE, + Operational = Minimum, ///< Base of the PSA key ID range for Node Operational Certificate private keys + DACPrivKey = Operational + kMaxValidFabricIndex + 1, +#if CHIP_CONFIG_ENABLE_ICD_CIP + ICDHmacKeyRangeStart = DACPrivKey + 1, + ICDAesKeyRangeStart = ICDHmacKeyRangeStart + kMaxICDClientKeys, + ICDKeysRangeEnd = ICDAesKeyRangeStart + kMaxICDClientKeys, +#else + // If Check-In Protocol is disabled, set ICDKeysRangeEnd to previous key, to allow setting next key ID to `ICDKeysRangeEnd + 1` + ICDKeysRangeEnd = DACPrivKey, +#endif // CHIP_CONFIG_ENABLE_ICD_CIP + Maximum = ICDKeysRangeEnd, }; static_assert(to_underlying(KeyIdBase::Minimum) >= PSA_KEY_ID_USER_MIN && to_underlying(KeyIdBase::Maximum) <= PSA_KEY_ID_USER_MAX, "PSA key ID base out of allowed range"); + +/** + * @brief Finds first free persistent Key slot ID within range. + * + * @param[out] keyId Key ID handler to which free ID will be set. + * @param[in] start Starting ID in search range. + * @param[in] range Search range. + * + * @retval CHIP_NO_ERROR On success. + * @retval CHIP_ERROR_INTERNAL On PSA crypto API error. + * @retval CHIP_ERROR_NOT_FOUND On no free Key ID within range. + * @retval CHIP_ERROR_INVALID_ARGUMENT On search arguments out of PSA allowed range. + */ +CHIP_ERROR FindFreeKeySlotInRange(psa_key_id_t & keyId, psa_key_id_t start, uint32_t range); + /** * @brief Calculates PSA key ID for Node Operational Certificate private key for the given fabric. */ diff --git a/src/crypto/PSASessionKeystore.cpp b/src/crypto/PSASessionKeystore.cpp index 304fa10086daba..2085a01cdc926f 100644 --- a/src/crypto/PSASessionKeystore.cpp +++ b/src/crypto/PSASessionKeystore.cpp @@ -24,20 +24,24 @@ namespace Crypto { namespace { -class AesKeyAttributes +class keyAttributesBase { public: - AesKeyAttributes() + keyAttributesBase(psa_key_id_t keyId, psa_key_type_t type, psa_algorithm_t algorithm, + psa_key_usage_t usageFlags, size_t bits) { - constexpr psa_algorithm_t kAlgorithm = PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8); - - psa_set_key_type(&mAttrs, PSA_KEY_TYPE_AES); - psa_set_key_algorithm(&mAttrs, kAlgorithm); - psa_set_key_usage_flags(&mAttrs, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); - psa_set_key_bits(&mAttrs, CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES * 8); + psa_set_key_type(&mAttrs, type); + psa_set_key_algorithm(&mAttrs, algorithm); + psa_set_key_usage_flags(&mAttrs, usageFlags); + psa_set_key_bits(&mAttrs, bits); + if (to_underlying(KeyIdBase::Maximum) >= keyId && keyId >= to_underlying(KeyIdBase::Minimum)) + { + psa_set_key_lifetime(&mAttrs, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_id(&mAttrs, keyId); + } } - ~AesKeyAttributes() { psa_reset_key_attributes(&mAttrs); } + ~keyAttributesBase() { psa_reset_key_attributes(&mAttrs); } const psa_key_attributes_t & Get() { return mAttrs; } @@ -45,41 +49,40 @@ class AesKeyAttributes psa_key_attributes_t mAttrs = PSA_KEY_ATTRIBUTES_INIT; }; -class HmacKeyAttributes +class AesKeyAttributes : public keyAttributesBase { public: - HmacKeyAttributes() - { - psa_set_key_type(&mAttrs, PSA_KEY_TYPE_HMAC); - psa_set_key_algorithm(&mAttrs, PSA_ALG_HMAC(PSA_ALG_SHA_256)); - psa_set_key_usage_flags(&mAttrs, PSA_KEY_USAGE_SIGN_MESSAGE); - psa_set_key_bits(&mAttrs, CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES * 8); - } - - ~HmacKeyAttributes() { psa_reset_key_attributes(&mAttrs); } - - const psa_key_attributes_t & Get() { return mAttrs; } - -private: - psa_key_attributes_t mAttrs = PSA_KEY_ATTRIBUTES_INIT; + AesKeyAttributes(psa_key_id_t keyId = PSA_KEY_ID_NULL) + : keyAttributesBase(keyId, + PSA_KEY_TYPE_AES, + PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8), + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT, + CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES * 8) + {} }; -class HkdfKeyAttributes +class HmacKeyAttributes : public keyAttributesBase { public: - HkdfKeyAttributes() - { - psa_set_key_type(&mAttrs, PSA_KEY_TYPE_DERIVE); - psa_set_key_algorithm(&mAttrs, PSA_ALG_HKDF(PSA_ALG_SHA_256)); - psa_set_key_usage_flags(&mAttrs, PSA_KEY_USAGE_DERIVE); - } - - ~HkdfKeyAttributes() { psa_reset_key_attributes(&mAttrs); } - - const psa_key_attributes_t & Get() { return mAttrs; } + HmacKeyAttributes(psa_key_id_t keyId = PSA_KEY_ID_NULL) + : keyAttributesBase(keyId, + PSA_KEY_TYPE_HMAC, + PSA_ALG_HMAC(PSA_ALG_SHA_256), + PSA_KEY_USAGE_SIGN_MESSAGE, + CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES * 8) + {} +}; -private: - psa_key_attributes_t mAttrs = PSA_KEY_ATTRIBUTES_INIT; +class HkdfKeyAttributes : public keyAttributesBase +{ +public: + HkdfKeyAttributes(psa_key_id_t keyId = PSA_KEY_ID_NULL) + : keyAttributesBase(keyId, + PSA_KEY_TYPE_DERIVE, + PSA_ALG_HKDF(PSA_ALG_SHA_256), + PSA_KEY_USAGE_DERIVE, + 0) + {} }; } // namespace @@ -89,7 +92,7 @@ CHIP_ERROR PSASessionKeystore::CreateKey(const Symmetric128BitsKeyByteArray & ke // Destroy the old key if already allocated psa_destroy_key(key.As()); - AesKeyAttributes attrs; + AesKeyAttributes attrs(key.As()); psa_status_t status = psa_import_key(&attrs.Get(), keyMaterial, sizeof(Symmetric128BitsKeyByteArray), &key.AsMutable()); LogPsaError(status); @@ -103,7 +106,7 @@ CHIP_ERROR PSASessionKeystore::CreateKey(const Symmetric128BitsKeyByteArray & ke // Destroy the old key if already allocated psa_destroy_key(key.As()); - HmacKeyAttributes attrs; + HmacKeyAttributes attrs(key.As()); psa_status_t status = psa_import_key(&attrs.Get(), keyMaterial, sizeof(Symmetric128BitsKeyByteArray), &key.AsMutable()); LogPsaError(status);