From f3dded43b650d0518aa3f6f37ba6b33bf864ae95 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 7 Jan 2025 15:39:07 -0800 Subject: [PATCH] [crypto-storage] add `KeyRefManager` to select `KeyRef` values (#11102) This commit introduces `Crypto::Storage::KeyRefManager`, which manages and selects the `KeyRef` values. `ot::Instance` now will have its own `KeyRefManager`. Under `MULTIPLE_INSTANCE_ENABLE`, this allows different `ot::Instance`s to use different `KeyRef` ranges by setting an instance-specific offset. This offset is used when determining the `KeyRef` numerical value for secure storage access. --- src/core/crypto/storage.cpp | 20 +++--- src/core/crypto/storage.hpp | 92 ++++++++++++++++++++++++---- src/core/instance/instance.cpp | 11 ++++ src/core/instance/instance.hpp | 9 +++ src/core/meshcop/dataset_manager.cpp | 18 +++--- src/core/meshcop/dataset_manager.hpp | 14 +++-- src/core/net/srp_client.cpp | 2 +- src/core/net/srp_client.hpp | 4 -- src/core/thread/key_manager.cpp | 7 ++- 9 files changed, 134 insertions(+), 43 deletions(-) diff --git a/src/core/crypto/storage.cpp b/src/core/crypto/storage.cpp index 726daa930..ec0a373e0 100644 --- a/src/core/crypto/storage.cpp +++ b/src/core/crypto/storage.cpp @@ -39,6 +39,7 @@ namespace ot { namespace Crypto { #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Error Key::ExtractKey(uint8_t *aKeyBuffer, uint16_t &aKeyLength) const { Error error = kErrorNone; @@ -56,17 +57,18 @@ exit: return error; } -void Storage::DestroyPersistentKeys(void) +void Storage::KeyRefManager::DestroyPersistentKeys(void) { - DestroyKey(kNetworkKeyRef); - DestroyKey(kPskcRef); - DestroyKey(kActiveDatasetNetworkKeyRef); - DestroyKey(kActiveDatasetPskcRef); - DestroyKey(kPendingDatasetNetworkKeyRef); - DestroyKey(kPendingDatasetPskcRef); - DestroyKey(kEcdsaRef); + DestroyKey(KeyRefFor(kNetworkKey)); + DestroyKey(KeyRefFor(kPskc)); + DestroyKey(KeyRefFor(kActiveDatasetNetworkKey)); + DestroyKey(KeyRefFor(kActiveDatasetPskc)); + DestroyKey(KeyRefFor(kPendingDatasetNetworkKey)); + DestroyKey(KeyRefFor(kPendingDatasetPskc)); + DestroyKey(KeyRefFor(kEcdsa)); } -#endif + +#endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE LiteralKey::LiteralKey(const Key &aKey) : mKey(aKey.GetBytes()) diff --git a/src/core/crypto/storage.hpp b/src/core/crypto/storage.hpp index 7bcae5bd1..b86bbd7ed 100644 --- a/src/core/crypto/storage.hpp +++ b/src/core/crypto/storage.hpp @@ -42,6 +42,7 @@ #include "common/clearable.hpp" #include "common/code_utils.hpp" #include "common/error.hpp" +#include "common/locator.hpp" #include "common/non_copyable.hpp" namespace ot { @@ -94,14 +95,84 @@ enum StorageType : uint8_t */ typedef otCryptoKeyRef KeyRef; -constexpr KeyRef kInvalidKeyRef = 0x80000000; ///< Invalid `KeyRef` value (PSA_KEY_ID_VENDOR_MAX + 1). -constexpr KeyRef kNetworkKeyRef = OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET + 1; -constexpr KeyRef kPskcRef = OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET + 2; -constexpr KeyRef kActiveDatasetNetworkKeyRef = OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET + 3; -constexpr KeyRef kActiveDatasetPskcRef = OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET + 4; -constexpr KeyRef kPendingDatasetNetworkKeyRef = OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET + 5; -constexpr KeyRef kPendingDatasetPskcRef = OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET + 6; -constexpr KeyRef kEcdsaRef = OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET + 7; +constexpr KeyRef kInvalidKeyRef = 0x80000000; ///< Invalid `KeyRef` value (PSA_KEY_ID_VENDOR_MAX + 1). + +/** + * Manages and selects the `KeyRef` values. + */ +class KeyRefManager : public InstanceLocator +{ +public: + /** + * Represents difference `KeyRef` types. + */ + enum Type : uint8_t + { + kNetworkKey = 1, + kPskc = 2, + kActiveDatasetNetworkKey = 3, + kActiveDatasetPskc = 4, + kPendingDatasetNetworkKey = 5, + kPendingDatasetPskc = 6, + kEcdsa = 7, + }; + + /** + * Initializes the `KeyRefManager`. + * + * @param[in] aInstance A reference to the OpenThread instance. + */ + explicit KeyRefManager(Instance &aInstance) + : InstanceLocator(aInstance) +#if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE + , mExtraOffset(0) +#endif + { + } + + /** + * Determines the `KeyRef` to use for a given `Type`. + * + * @param[in] aType The key ref type. + * + * @returns The `KeyRef` associated with @p aType. + */ + KeyRef KeyRefFor(Type aType) + { + KeyRef keyRef = kPsaItsNvmOffset + aType; + +#if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE + keyRef += mExtraOffset; +#endif + return keyRef; + } + + /** + * Delete all the persistent keys. + */ + void DestroyPersistentKeys(void); + +#if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE + static constexpr uint32_t kKeyRefExtraOffset = 32; ///< Recommended extra offset to use. + + /** + * Sets the additional `KeyRef` offset value to use when determining the `KeyRef`s. + * + * This is intended for when `MULTIPLE_INSTANCE_ENABLE` is enabled to ensure different `ot::Instance`s use + * different `KeyRef` value ranges. + * + * @param[in] aOffset The offset value. + */ + void SetKeyRefExtraOffset(uint32_t aOffset) { mExtraOffset = aOffset; } +#endif + +private: + static constexpr KeyRef kPsaItsNvmOffset = OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET; + +#if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE + uint32_t mExtraOffset; +#endif +}; /** * Determine if a given `KeyRef` is valid or not. @@ -181,11 +252,6 @@ inline void DestroyKey(KeyRef aKeyRef) */ inline bool HasKey(KeyRef aKeyRef) { return otPlatCryptoHasKey(aKeyRef); } -/** - * Delete all the persistent keys stored in PSA ITS. - */ -void DestroyPersistentKeys(void); - } // namespace Storage #endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE diff --git a/src/core/instance/instance.cpp b/src/core/instance/instance.cpp index fc00ce7fe..d00129c70 100644 --- a/src/core/instance/instance.cpp +++ b/src/core/instance/instance.cpp @@ -75,6 +75,9 @@ Instance::Instance(void) : mTimerMilliScheduler(*this) #if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE , mTimerMicroScheduler(*this) +#endif +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + , mCryptoStorageKeyRefManager(*this) #endif , mRadio(*this) #if OPENTHREAD_CONFIG_UPTIME_ENABLE @@ -276,6 +279,14 @@ Instance::Instance(void) , mIsInitialized(false) , mId(Random::NonCrypto::GetUint32()) { +#if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE && OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE +#if OPENTHREAD_CONFIG_MULTIPLE_STATIC_INSTANCE_ENABLE + mCryptoStorageKeyRefManager.SetKeyRefExtraOffset(Crypto::Storage::KeyRefManager::kKeyRefExtraOffset * GetIdx(this)); +#else +#error "MULTIPLE_INSTANCE (without static allocation) is used with PLATFORM_KEY_REFERENCES_ENABLE " \ + "The `KeyRef` values will be shared across different `Instance` objects" +#endif +#endif } #if (OPENTHREAD_MTD || OPENTHREAD_FTD) && !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE diff --git a/src/core/instance/instance.hpp b/src/core/instance/instance.hpp index fa1699ad2..3cbf72832 100644 --- a/src/core/instance/instance.hpp +++ b/src/core/instance/instance.hpp @@ -79,6 +79,7 @@ #include "common/notifier.hpp" #include "common/settings.hpp" #include "crypto/mbedtls.hpp" +#include "crypto/storage.hpp" #include "mac/mac.hpp" #include "mac/wakeup_tx_scheduler.hpp" #include "meshcop/border_agent.hpp" @@ -464,6 +465,10 @@ private: Random::Manager mRandomManager; +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Storage::KeyRefManager mCryptoStorageKeyRefManager; +#endif + // Radio is initialized before other member variables // (particularly, SubMac and Mac) to allow them to use its methods // from their constructor. @@ -769,6 +774,10 @@ template <> inline SettingsDriver &Instance::Get(void) { return mSettingsDriver; template <> inline MeshForwarder &Instance::Get(void) { return mMeshForwarder; } +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE +template <> inline Crypto::Storage::KeyRefManager &Instance::Get(void) { return mCryptoStorageKeyRefManager; } +#endif + #if OPENTHREAD_CONFIG_MULTI_RADIO template <> inline RadioSelector &Instance::Get(void) { return mRadioSelector; } #endif diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index c3dca49ea..114e334a6 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -755,13 +755,13 @@ void DatasetManager::TlvList::Add(uint8_t aTlvType) const DatasetManager::SecurelyStoredTlv DatasetManager::kSecurelyStoredTlvs[] = { { Tlv::kNetworkKey, - Crypto::Storage::kActiveDatasetNetworkKeyRef, - Crypto::Storage::kPendingDatasetNetworkKeyRef, + KeyRefManager::kActiveDatasetNetworkKey, + KeyRefManager::kPendingDatasetNetworkKey, }, { Tlv::kPskc, - Crypto::Storage::kActiveDatasetPskcRef, - Crypto::Storage::kPendingDatasetPskcRef, + KeyRefManager::kActiveDatasetPskc, + KeyRefManager::kPendingDatasetPskc, }, }; @@ -769,7 +769,7 @@ void DatasetManager::DestroySecurelyStoredKeys(void) const { for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs) { - Crypto::Storage::DestroyKey(entry.GetKeyRef(mType)); + Crypto::Storage::DestroyKey(Get().KeyRefFor(entry.GetKeyRefType(mType))); } } @@ -777,7 +777,9 @@ void DatasetManager::MoveKeysToSecureStorage(Dataset &aDataset) const { for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs) { - SaveTlvInSecureStorageAndClearValue(aDataset, entry.mTlvType, entry.GetKeyRef(mType)); + KeyRef keyRef = Get().KeyRefFor(entry.GetKeyRefType(mType)); + + SaveTlvInSecureStorageAndClearValue(aDataset, entry.mTlvType, keyRef); } } @@ -792,7 +794,9 @@ void DatasetManager::EmplaceSecurelyStoredKeys(Dataset &aDataset) const for (const SecurelyStoredTlv &entry : kSecurelyStoredTlvs) { - if (ReadTlvFromSecureStorage(aDataset, entry.mTlvType, entry.GetKeyRef(mType)) != kErrorNone) + KeyRef keyRef = Get().KeyRefFor(entry.GetKeyRefType(mType)); + + if (ReadTlvFromSecureStorage(aDataset, entry.mTlvType, keyRef) != kErrorNone) { moveKeys = true; } diff --git a/src/core/meshcop/dataset_manager.hpp b/src/core/meshcop/dataset_manager.hpp index b3c0f4e22..134ec843a 100644 --- a/src/core/meshcop/dataset_manager.hpp +++ b/src/core/meshcop/dataset_manager.hpp @@ -238,18 +238,20 @@ private: }; #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - using KeyRef = Crypto::Storage::KeyRef; + using KeyRef = Crypto::Storage::KeyRef; + using KeyRefManager = Crypto::Storage::KeyRefManager; + using KeyRefType = Crypto::Storage::KeyRefManager::Type; struct SecurelyStoredTlv { - KeyRef GetKeyRef(Dataset::Type aType) const + KeyRefType GetKeyRefType(Dataset::Type aType) const { - return (aType == Dataset::kActive) ? mActiveKeyRef : mPendingKeyRef; + return (aType == Dataset::kActive) ? mActiveKeyRefType : mPendingKeyRefType; } - Tlv::Type mTlvType; - KeyRef mActiveKeyRef; - KeyRef mPendingKeyRef; + Tlv::Type mTlvType; + KeyRefType mActiveKeyRefType; + KeyRefType mPendingKeyRefType; }; static const SecurelyStoredTlv kSecurelyStoredTlvs[]; diff --git a/src/core/net/srp_client.cpp b/src/core/net/srp_client.cpp index 451360392..121a29417 100644 --- a/src/core/net/srp_client.cpp +++ b/src/core/net/srp_client.cpp @@ -1110,7 +1110,7 @@ Error Client::PrepareUpdateMessage(MsgInfo &aInfo) aInfo.mRecordCount = 0; #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - aInfo.mKeyInfo.SetKeyRef(kSrpEcdsaKeyRef); + aInfo.mKeyInfo.SetKeyRef(Get().KeyRefFor(Crypto::Storage::KeyRefManager::kEcdsa)); #endif SuccessOrExit(error = ReadOrGenerateKey(aInfo.mKeyInfo)); diff --git a/src/core/net/srp_client.hpp b/src/core/net/srp_client.hpp index 8f5891bd0..fd5a2b3e5 100644 --- a/src/core/net/srp_client.hpp +++ b/src/core/net/srp_client.hpp @@ -749,10 +749,6 @@ private: // Number of fast data polls after SRP Update tx (11x 188ms = ~2 seconds) static constexpr uint8_t kFastPollsAfterUpdateTx = 11; -#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - static constexpr uint32_t kSrpEcdsaKeyRef = Crypto::Storage::kEcdsaRef; -#endif - #if OPENTHREAD_CONFIG_SRP_CLIENT_SWITCH_SERVER_ON_FAILURE static constexpr uint8_t kMaxTimeoutFailuresToSwitchServer = OPENTHREAD_CONFIG_SRP_CLIENT_MAX_TIMEOUT_FAILURES_TO_SWITCH_SERVER; diff --git a/src/core/thread/key_manager.cpp b/src/core/thread/key_manager.cpp index 8b8eb9073..6596bf75e 100644 --- a/src/core/thread/key_manager.cpp +++ b/src/core/thread/key_manager.cpp @@ -586,7 +586,7 @@ void KeyManager::StoreNetworkKey(const NetworkKey &aNetworkKey, bool aOverWriteE { NetworkKeyRef keyRef; - keyRef = Crypto::Storage::kNetworkKeyRef; + keyRef = Get().KeyRefFor(Crypto::Storage::KeyRefManager::kNetworkKey); if (!aOverWriteExisting) { @@ -617,7 +617,7 @@ exit: void KeyManager::StorePskc(const Pskc &aPskc) { - PskcRef keyRef = Crypto::Storage::kPskcRef; + PskcRef keyRef = Get().KeyRefFor(Crypto::Storage::KeyRefManager::kPskc); Crypto::Storage::DestroyKey(keyRef); @@ -671,7 +671,8 @@ void KeyManager::DestroyTemporaryKeys(void) Get().ClearMode2Key(); } -void KeyManager::DestroyPersistentKeys(void) { Crypto::Storage::DestroyPersistentKeys(); } +void KeyManager::DestroyPersistentKeys(void) { Get().DestroyPersistentKeys(); } + #endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE } // namespace ot