From 2c0c3e84a35d7c9674db3ed322ebcb186befa2b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Duda?= Date: Sat, 1 Nov 2025 23:36:38 +0100 Subject: [PATCH] [crypto] PSA API: support HKDF extraction with HMAC-SHA256 keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PSA platform now transparently handles HKDF operations when using HMAC-SHA256 keys by exporting and re-importing them as volatile HKDF-SHA256 keys. The export/import logic has been moved into the platform layer. This change is required to support TREL and the PSA API key usage restrictions. Signed-off-by: Ɓukasz Duda --- src/core/crypto/crypto_platform_psa.cpp | 40 ++++++++++++++++++++++--- src/core/thread/key_manager.cpp | 16 +--------- tests/unit/test_hkdf_sha256.cpp | 30 +++++++++++++++++-- 3 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/core/crypto/crypto_platform_psa.cpp b/src/core/crypto/crypto_platform_psa.cpp index 1b44e040b..5dac04f48 100644 --- a/src/core/crypto/crypto_platform_psa.cpp +++ b/src/core/crypto/crypto_platform_psa.cpp @@ -451,9 +451,15 @@ OT_TOOL_WEAK otError otPlatCryptoHkdfExtract(otCryptoContext *aContext, uint16_t aSaltLength, const otCryptoKey *aInputKey) { - Error error = kErrorNone; - psa_status_t status = PSA_SUCCESS; - psa_key_derivation_operation_t *operation; + Error error = kErrorNone; + psa_status_t status = PSA_SUCCESS; + psa_key_derivation_operation_t *operation = nullptr; + otCryptoKeyRef keyRef = PSA_KEY_ID_NULL; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_algorithm_t keyAlg = PSA_ALG_NONE; + size_t keyLength = 0; + constexpr size_t kBufferSize = 128; + uint8_t keyBuffer[kBufferSize]; VerifyOrExit(checkContext(aContext, sizeof(psa_key_derivation_operation_t)), error = kErrorInvalidArgs); VerifyOrExit(aInputKey != nullptr, error = kErrorInvalidArgs); @@ -463,10 +469,36 @@ OT_TOOL_WEAK otError otPlatCryptoHkdfExtract(otCryptoContext *aContext, status = psa_key_derivation_input_bytes(operation, PSA_KEY_DERIVATION_INPUT_SALT, aSalt, aSaltLength); SuccessOrExit(error = psaToOtError(status)); - status = psa_key_derivation_input_key(operation, PSA_KEY_DERIVATION_INPUT_SECRET, aInputKey->mKeyRef); + status = psa_get_key_attributes(aInputKey->mKeyRef, &attributes); SuccessOrExit(error = psaToOtError(status)); + keyAlg = psa_get_key_algorithm(&attributes); + + // The PSA API enforces a policy that restricts each key to a single algorithm. + // If the key is already HKDF-SHA256, we can use it directly. + // Otherwise, export and re-import it as a volatile HKDF key. + if (keyAlg != toPsaAlgorithm(OT_CRYPTO_KEY_ALG_HKDF_SHA256)) + { + SuccessOrExit(error = otPlatCryptoExportKey(aInputKey->mKeyRef, keyBuffer, sizeof(keyBuffer), &keyLength)); + SuccessOrExit(error = otPlatCryptoImportKey(&keyRef, OT_CRYPTO_KEY_TYPE_DERIVE, OT_CRYPTO_KEY_ALG_HKDF_SHA256, + OT_CRYPTO_KEY_USAGE_DERIVE, OT_CRYPTO_KEY_STORAGE_VOLATILE, + keyBuffer, keyLength)); + + status = psa_key_derivation_input_key(operation, PSA_KEY_DERIVATION_INPUT_SECRET, keyRef); + SuccessOrExit(error = psaToOtError(status)); + } + else + { + status = psa_key_derivation_input_key(operation, PSA_KEY_DERIVATION_INPUT_SECRET, aInputKey->mKeyRef); + SuccessOrExit(error = psaToOtError(status)); + } + exit: + if (keyRef != PSA_KEY_ID_NULL) + { + otPlatCryptoDestroyKey(keyRef); + } + return error; } diff --git a/src/core/thread/key_manager.cpp b/src/core/thread/key_manager.cpp index f709b29a7..d520d8162 100644 --- a/src/core/thread/key_manager.cpp +++ b/src/core/thread/key_manager.cpp @@ -311,17 +311,7 @@ void KeyManager::ComputeTrelKey(uint32_t aKeySequence, Mac::Key &aKey) const Crypto::Key cryptoKey; #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - Crypto::Storage::KeyRef keyRef; - NetworkKey networkKey; - - GetNetworkKey(networkKey); - - // Create temporary key to perform derive operation. - SuccessOrAssert(Crypto::Storage::ImportKey(keyRef, Crypto::Storage::kKeyTypeDerive, - Crypto::Storage::kKeyAlgorithmHkdfSha256, Crypto::Storage::kUsageDerive, - Crypto::Storage::kTypeVolatile, networkKey.m8, NetworkKey::kSize)); - - cryptoKey.SetAsKeyRef(keyRef); + cryptoKey.SetAsKeyRef(mNetworkKeyRef); #else cryptoKey.Set(mNetworkKey.m8, NetworkKey::kSize); #endif @@ -331,10 +321,6 @@ void KeyManager::ComputeTrelKey(uint32_t aKeySequence, Mac::Key &aKey) const hkdf.Extract(salt, sizeof(salt), cryptoKey); hkdf.Expand(kTrelInfoString, sizeof(kTrelInfoString), aKey.m8, Mac::Key::kSize); - -#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - Crypto::Storage::DestroyKey(keyRef); -#endif } #endif diff --git a/tests/unit/test_hkdf_sha256.cpp b/tests/unit/test_hkdf_sha256.cpp index 219272c70..98ce41202 100644 --- a/tests/unit/test_hkdf_sha256.cpp +++ b/tests/unit/test_hkdf_sha256.cpp @@ -50,7 +50,11 @@ struct TestVector uint16_t mOutKeyLength; }; +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE +void TestHkdfSha256(Crypto::Storage::KeyAlgorithm aAlgorithm) +#else void TestHkdfSha256(void) +#endif { enum { @@ -147,9 +151,23 @@ void TestHkdfSha256(void) memset(outKey, kFillByte, sizeof(outKey)); #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - SuccessOrQuit(Crypto::Storage::ImportKey( - keyRef, Crypto::Storage::kKeyTypeDerive, Crypto::Storage::kKeyAlgorithmHkdfSha256, - Crypto::Storage::kUsageDerive, Crypto::Storage::kTypeVolatile, test->mInKey, test->mInKeyLength)); + if (aAlgorithm == Crypto::Storage::kKeyAlgorithmHkdfSha256) + { + SuccessOrQuit(Crypto::Storage::ImportKey( + keyRef, Crypto::Storage::kKeyTypeDerive, Crypto::Storage::kKeyAlgorithmHkdfSha256, + Crypto::Storage::kUsageDerive, Crypto::Storage::kTypeVolatile, test->mInKey, test->mInKeyLength)); + } + else if (aAlgorithm == Crypto::Storage::kKeyAlgorithmHmacSha256) + { + SuccessOrQuit(Crypto::Storage::ImportKey(keyRef, Crypto::Storage::kKeyTypeHmac, + Crypto::Storage::kKeyAlgorithmHmacSha256, + Crypto::Storage::kUsageSignHash | Crypto::Storage::kUsageExport, + Crypto::Storage::kTypeVolatile, test->mInKey, test->mInKeyLength)); + } + else + { + VerifyOrQuit(false); + } testInputKey.SetAsKeyRef(keyRef); #else @@ -180,7 +198,13 @@ void TestHkdfSha256(void) int main(void) { +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + ot::TestHkdfSha256(ot::Crypto::Storage::kKeyAlgorithmHkdfSha256); + ot::TestHkdfSha256(ot::Crypto::Storage::kKeyAlgorithmHmacSha256); +#else ot::TestHkdfSha256(); +#endif + printf("All tests passed\n"); return 0; }