mirror of
https://github.com/espressif/openthread.git
synced 2026-09-25 18:37:40 +00:00
[crypto] validate aHeader and KeyRef inputs in platform crypto APIs (#13303)
Reject a null `aHeader` combined with non-zero `mHeaderLength` in `otPlatCryptoAesCcmProcessOneShot()`, in both the mbedtls and PSA backends. Add `otPlatCryptoIsKeyRefValid()` so each crypto backend can define what KeyRef values it accepts, and use it in the default PSA backend at every entry point that takes a KeyRef (import/export/destroy/ has-key, AES, HMAC, HKDF, ECDSA) instead of relying solely on the underlying PSA library to reject a bad handle. Make the "invalid KeyRef" sentinel backend-configurable via the new `OPENTHREAD_CONFIG_CRYPTO_INVALID_KEY_REF`, defaulting to `PSA_KEY_ID_NULL` (0), so a backend other than the default PSA one can reserve a different value as invalid without a generic core header depending on any one backend's implementation file.
This commit is contained in:
@@ -38,6 +38,14 @@
|
||||
|
||||
// crypto key storage stubs
|
||||
|
||||
bool otPlatCryptoIsKeyRefValid(otCryptoKeyRef aKeyRef)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aKeyRef);
|
||||
|
||||
// No key ref is ever actually stored by this stub, so none is valid.
|
||||
return false;
|
||||
}
|
||||
|
||||
otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef,
|
||||
otCryptoKeyType aKeyType,
|
||||
otCryptoKeyAlgorithm aKeyAlgorithm,
|
||||
|
||||
@@ -52,7 +52,7 @@ extern "C" {
|
||||
*
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (621)
|
||||
#define OPENTHREAD_API_VERSION (622)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -223,6 +223,21 @@ typedef struct otPlatCryptoEcdsaSignature otPlatCryptoEcdsaSignature;
|
||||
*/
|
||||
void otPlatCryptoInit(void);
|
||||
|
||||
/**
|
||||
* Check whether a given key reference is valid.
|
||||
*
|
||||
* This API does not check whether a key is currently stored under @p aKeyRef. Instead, use `otPlatCryptoHasKey()` for
|
||||
* existence checks.
|
||||
*
|
||||
* @note This API is only used by OT core when `OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE` is enabled.
|
||||
*
|
||||
* @param[in] aKeyRef The Key Ref to check.
|
||||
*
|
||||
* @retval TRUE @p aKeyRef is valid.
|
||||
* @retval FALSE @p aKeyRef is not valid.
|
||||
*/
|
||||
bool otPlatCryptoIsKeyRefValid(otCryptoKeyRef aKeyRef);
|
||||
|
||||
/**
|
||||
* Import a key into PSA ITS.
|
||||
*
|
||||
|
||||
@@ -161,6 +161,17 @@
|
||||
(OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_CRYPTO_INVALID_KEY_REF
|
||||
*
|
||||
* The sentinel `KeyRef` value that marks "no key set". Depends on the crypto backend in use. A backend whose
|
||||
* platform reserves a different value as invalid can override this definition. Defaults to `PSA_KEY_ID_NULL`,
|
||||
* as used by the default PSA backend.
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_CRYPTO_INVALID_KEY_REF
|
||||
#define OPENTHREAD_CONFIG_CRYPTO_INVALID_KEY_REF 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE
|
||||
*
|
||||
|
||||
@@ -167,6 +167,7 @@ OT_TOOL_WEAK otError otPlatCryptoAesCcmProcessOneShot(bool
|
||||
mbedtls_ccm_init(&ctx);
|
||||
|
||||
VerifyOrExit(aConfig != nullptr && aConfig->mNonce != nullptr && aData != nullptr, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aHeader != nullptr || aConfig->mHeaderLength == 0, error = kErrorInvalidArgs);
|
||||
|
||||
{
|
||||
const LiteralKey key(*static_cast<const Key *>(&aConfig->mKey));
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
#include "common/debug.hpp"
|
||||
#include "common/error.hpp"
|
||||
#include "common/new.hpp"
|
||||
#include "common/num_utils.hpp"
|
||||
#include "config/crypto.h"
|
||||
#include "crypto/ecdsa.hpp"
|
||||
#include "crypto/hmac_sha256.hpp"
|
||||
#include "crypto/storage.hpp"
|
||||
#include "instance/instance.hpp"
|
||||
|
||||
using namespace ot;
|
||||
@@ -75,6 +75,7 @@ static Error PsaToOtError(psa_status_t aStatus)
|
||||
error = kErrorNone;
|
||||
break;
|
||||
case PSA_ERROR_INVALID_ARGUMENT:
|
||||
case PSA_ERROR_INVALID_HANDLE:
|
||||
error = kErrorInvalidArgs;
|
||||
break;
|
||||
case PSA_ERROR_BUFFER_TOO_SMALL:
|
||||
@@ -254,6 +255,12 @@ OT_TOOL_WEAK void *otPlatCryptoCAlloc(size_t aNum, size_t aSize) { return otPlat
|
||||
OT_TOOL_WEAK void otPlatCryptoFree(void *aPtr) { otPlatFree(aPtr); }
|
||||
#endif
|
||||
|
||||
OT_TOOL_WEAK bool otPlatCryptoIsKeyRefValid(otCryptoKeyRef aKeyRef)
|
||||
{
|
||||
return IsValueInRange(aKeyRef, PSA_KEY_ID_USER_MIN, PSA_KEY_ID_USER_MAX) ||
|
||||
IsValueInRange(aKeyRef, PSA_KEY_ID_VENDOR_MIN, PSA_KEY_ID_VENDOR_MAX);
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef,
|
||||
otCryptoKeyType aKeyType,
|
||||
otCryptoKeyAlgorithm aKeyAlgorithm,
|
||||
@@ -290,6 +297,9 @@ OT_TOOL_WEAK otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef,
|
||||
switch (aKeyPersistence)
|
||||
{
|
||||
case OT_CRYPTO_KEY_STORAGE_PERSISTENT:
|
||||
// For persistent storage, the caller supplies the target `KeyRef` via `*aKeyRef`, so it must be validated
|
||||
// here. For volatile storage, `*aKeyRef` is a pure output populated by `psa_import_key()` below.
|
||||
VerifyOrExit(otPlatCryptoIsKeyRefValid(*aKeyRef), error = kErrorInvalidArgs);
|
||||
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_PERSISTENT);
|
||||
psa_set_key_id(&attributes, *aKeyRef);
|
||||
break;
|
||||
@@ -313,6 +323,7 @@ OT_TOOL_WEAK otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, uint8_t *aBuf
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(aBuffer != nullptr && aKeyLen != nullptr, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(otPlatCryptoIsKeyRefValid(aKeyRef), error = kErrorInvalidArgs);
|
||||
|
||||
error = PsaToOtError(psa_export_key(aKeyRef, aBuffer, aBufferLen, aKeyLen));
|
||||
|
||||
@@ -320,16 +331,28 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoDestroyKey(otCryptoKeyRef aKeyRef) { return PsaToOtError(psa_destroy_key(aKeyRef)); }
|
||||
OT_TOOL_WEAK otError otPlatCryptoDestroyKey(otCryptoKeyRef aKeyRef)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(otPlatCryptoIsKeyRefValid(aKeyRef), error = kErrorInvalidArgs);
|
||||
error = PsaToOtError(psa_destroy_key(aKeyRef));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK bool otPlatCryptoHasKey(otCryptoKeyRef aKeyRef)
|
||||
{
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_status_t status;
|
||||
psa_status_t status = PSA_ERROR_INVALID_HANDLE;
|
||||
|
||||
VerifyOrExit(otPlatCryptoIsKeyRefValid(aKeyRef));
|
||||
|
||||
status = psa_get_key_attributes(aKeyRef, &attributes);
|
||||
psa_reset_key_attributes(&attributes);
|
||||
|
||||
exit:
|
||||
return status == PSA_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -341,7 +364,7 @@ OT_TOOL_WEAK otError otPlatCryptoAesInit(otCryptoContext *aContext)
|
||||
SuccessOrExit(error = ValidateContext(aContext, sizeof(psa_key_id_t)));
|
||||
|
||||
keyRef = static_cast<psa_key_id_t *>(aContext->mContext);
|
||||
*keyRef = PSA_KEY_ID_NULL;
|
||||
*keyRef = PSA_KEY_ID_NULL; // Initialize the key reference to an invalid value.
|
||||
|
||||
exit:
|
||||
return error;
|
||||
@@ -353,7 +376,8 @@ OT_TOOL_WEAK otError otPlatCryptoAesSetKey(otCryptoContext *aContext, const otCr
|
||||
psa_key_id_t *keyRef;
|
||||
|
||||
SuccessOrExit(error = ValidateContext(aContext, sizeof(psa_key_id_t)));
|
||||
VerifyOrExit(aKey != nullptr, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aKey != nullptr && aKey->mKey == nullptr, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(otPlatCryptoIsKeyRefValid(aKey->mKeyRef), error = kErrorInvalidArgs);
|
||||
|
||||
keyRef = static_cast<psa_key_id_t *>(aContext->mContext);
|
||||
*keyRef = aKey->mKeyRef;
|
||||
@@ -374,6 +398,7 @@ OT_TOOL_WEAK otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uin
|
||||
VerifyOrExit(aInput != nullptr && aOutput != nullptr, error = kErrorInvalidArgs);
|
||||
|
||||
keyRef = static_cast<psa_key_id_t *>(aContext->mContext);
|
||||
VerifyOrExit(otPlatCryptoIsKeyRefValid(*keyRef), error = kErrorInvalidArgs);
|
||||
status = psa_cipher_encrypt(*keyRef, PSA_ALG_ECB_NO_PADDING, aInput, blockSize, aOutput, blockSize, &cipherLen);
|
||||
|
||||
error = PsaToOtError(status);
|
||||
@@ -403,6 +428,8 @@ OT_TOOL_WEAK otError otPlatCryptoAesCcmProcessOneShot(bool
|
||||
|
||||
VerifyOrExit(aConfig != nullptr && aConfig->mNonce != nullptr && aData != nullptr, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aConfig->mKey.mKey == nullptr, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(otPlatCryptoIsKeyRefValid(aConfig->mKey.mKeyRef), error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aHeader != nullptr || aConfig->mHeaderLength == 0, error = kErrorInvalidArgs);
|
||||
|
||||
algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, aConfig->mTagLength);
|
||||
|
||||
@@ -471,7 +498,8 @@ OT_TOOL_WEAK otError otPlatCryptoHmacSha256Start(otCryptoContext *aContext, cons
|
||||
psa_mac_operation_t *operation;
|
||||
|
||||
SuccessOrExit(error = ValidateContext(aContext, sizeof(psa_mac_operation_t)));
|
||||
VerifyOrExit(aKey != nullptr, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aKey != nullptr && aKey->mKey == nullptr, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(otPlatCryptoIsKeyRefValid(aKey->mKeyRef), error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_mac_operation_t *>(aContext->mContext);
|
||||
|
||||
@@ -547,7 +575,8 @@ OT_TOOL_WEAK otError otPlatCryptoHkdfExtract(otCryptoContext *aContext,
|
||||
uint8_t keyBuffer[kBufferSize];
|
||||
|
||||
SuccessOrExit(error = ValidateContext(aContext, sizeof(psa_key_derivation_operation_t)));
|
||||
VerifyOrExit(aInputKey != nullptr, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aInputKey != nullptr && aInputKey->mKey == nullptr, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(otPlatCryptoIsKeyRefValid(aInputKey->mKeyRef), error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_key_derivation_operation_t *>(aContext->mContext);
|
||||
|
||||
@@ -580,7 +609,10 @@ OT_TOOL_WEAK otError otPlatCryptoHkdfExtract(otCryptoContext *aContext,
|
||||
|
||||
exit:
|
||||
psa_reset_key_attributes(&attributes);
|
||||
psa_destroy_key(keyRef);
|
||||
if (otPlatCryptoIsKeyRefValid(keyRef))
|
||||
{
|
||||
psa_destroy_key(keyRef);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
@@ -722,8 +754,10 @@ OT_TOOL_WEAK otError otPlatCryptoRandomGet(uint8_t *aBuffer, uint16_t aSize)
|
||||
OT_TOOL_WEAK otError otPlatCryptoEcdsaGenerateAndImportKey(otCryptoKeyRef aKeyRef)
|
||||
{
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_status_t status;
|
||||
psa_key_id_t keyId = static_cast<psa_key_id_t>(aKeyRef);
|
||||
psa_status_t status = PSA_ERROR_INVALID_HANDLE;
|
||||
psa_key_id_t keyId = static_cast<psa_key_id_t>(aKeyRef);
|
||||
|
||||
VerifyOrExit(otPlatCryptoIsKeyRefValid(aKeyRef));
|
||||
|
||||
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_SIGN_HASH);
|
||||
psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
|
||||
@@ -743,10 +777,13 @@ exit:
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoEcdsaExportPublicKey(otCryptoKeyRef aKeyRef, otPlatCryptoEcdsaPublicKey *aPublicKey)
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_status_t status = PSA_ERROR_INVALID_HANDLE;
|
||||
size_t exportedLen;
|
||||
uint8_t buffer[1 + OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE];
|
||||
|
||||
VerifyOrExit(aPublicKey != nullptr, status = PSA_ERROR_INVALID_ARGUMENT);
|
||||
VerifyOrExit(otPlatCryptoIsKeyRefValid(aKeyRef));
|
||||
|
||||
status = psa_export_public_key(aKeyRef, buffer, sizeof(buffer), &exportedLen);
|
||||
VerifyOrExit(status == PSA_SUCCESS);
|
||||
|
||||
@@ -761,9 +798,12 @@ OT_TOOL_WEAK otError otPlatCryptoEcdsaSignUsingKeyRef(otCryptoKeyRef
|
||||
const otPlatCryptoSha256Hash *aHash,
|
||||
otPlatCryptoEcdsaSignature *aSignature)
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_status_t status = PSA_ERROR_INVALID_HANDLE;
|
||||
size_t signatureLen;
|
||||
|
||||
VerifyOrExit(aHash != nullptr && aSignature != nullptr, status = PSA_ERROR_INVALID_ARGUMENT);
|
||||
VerifyOrExit(otPlatCryptoIsKeyRefValid(aKeyRef));
|
||||
|
||||
status = psa_sign_hash(aKeyRef, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), aHash->m8, OT_CRYPTO_SHA256_HASH_SIZE,
|
||||
aSignature->m8, OT_CRYPTO_ECDSA_SIGNATURE_SIZE, &signatureLen);
|
||||
VerifyOrExit(status == PSA_SUCCESS);
|
||||
@@ -780,9 +820,12 @@ OT_TOOL_WEAK otError otPlatCryptoEcdsaVerify(const otPlatCryptoEcdsaPublicKey *a
|
||||
{
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_id_t keyId = PSA_KEY_ID_NULL;
|
||||
psa_status_t status;
|
||||
psa_status_t status = PSA_ERROR_INVALID_HANDLE;
|
||||
uint8_t buffer[1 + OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE];
|
||||
|
||||
VerifyOrExit(aPublicKey != nullptr && aHash != nullptr && aSignature != nullptr,
|
||||
status = PSA_ERROR_INVALID_ARGUMENT);
|
||||
|
||||
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH);
|
||||
psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
|
||||
psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
|
||||
@@ -811,7 +854,10 @@ OT_TOOL_WEAK otError otPlatCryptoEcdsaVerifyUsingKeyRef(otCryptoKeyRef
|
||||
const otPlatCryptoSha256Hash *aHash,
|
||||
const otPlatCryptoEcdsaSignature *aSignature)
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_status_t status = PSA_ERROR_INVALID_HANDLE;
|
||||
|
||||
VerifyOrExit(aHash != nullptr && aSignature != nullptr, status = PSA_ERROR_INVALID_ARGUMENT);
|
||||
VerifyOrExit(otPlatCryptoIsKeyRefValid(aKeyRef));
|
||||
|
||||
status = psa_verify_hash(aKeyRef, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), aHash->m8,
|
||||
OT_CRYPTO_SHA256_HASH_SIZE, aSignature->m8, OT_CRYPTO_ECDSA_SIGNATURE_SIZE);
|
||||
|
||||
@@ -99,7 +99,7 @@ enum StorageType : uint8_t
|
||||
*/
|
||||
typedef otCryptoKeyRef KeyRef;
|
||||
|
||||
constexpr KeyRef kInvalidKeyRef = 0x80000000; ///< Invalid `KeyRef` value (PSA_KEY_ID_VENDOR_MAX + 1).
|
||||
constexpr KeyRef kInvalidKeyRef = OPENTHREAD_CONFIG_CRYPTO_INVALID_KEY_REF; ///< Sentinel marking "no key set".
|
||||
|
||||
#if OPENTHREAD_FTD || OPENTHREAD_MTD
|
||||
|
||||
@@ -190,7 +190,7 @@ private:
|
||||
* @retval TRUE If @p aKeyRef is valid.
|
||||
* @retval FALSE If @p aKeyRef is not valid.
|
||||
*/
|
||||
inline bool IsKeyRefValid(KeyRef aKeyRef) { return (aKeyRef < kInvalidKeyRef); }
|
||||
inline bool IsKeyRefValid(KeyRef aKeyRef) { return otPlatCryptoIsKeyRefValid(aKeyRef); }
|
||||
|
||||
/**
|
||||
* Saves a key in secure storage.
|
||||
|
||||
@@ -544,6 +544,8 @@ OT_TOOL_WEAK void otPlatInfraIfDhcp6PdClientSend(otInstance *aInstance,
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
|
||||
|
||||
bool otPlatCryptoIsKeyRefValid(otCryptoKeyRef aKeyRef) { return (aKeyRef != OPENTHREAD_CONFIG_CRYPTO_INVALID_KEY_REF); }
|
||||
|
||||
otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef,
|
||||
otCryptoKeyType aKeyType,
|
||||
otCryptoKeyAlgorithm aKeyAlgorithm,
|
||||
|
||||
Reference in New Issue
Block a user