[crypto] PSA API: support HKDF extraction with HMAC-SHA256 keys

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 <[email protected]>
This commit is contained in:
Łukasz Duda
2025-11-04 21:53:32 +01:00
parent b614af3a91
commit 2c0c3e84a3
3 changed files with 64 additions and 22 deletions
+36 -4
View File
@@ -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;
}
+1 -15
View File
@@ -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
+27 -3
View File
@@ -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;
}