mirror of
https://github.com/espressif/openthread.git
synced 2026-07-25 05:24:08 +00:00
[crypto] PSA API: introduce default OpenThread crypto platform port
This commit adds a default implementation of the OpenThread crypto platform API for the PSA Crypto API. Signed-off-by: Łukasz Duda <lukasz.duda@nordicsemi.no>
This commit is contained in:
@@ -300,6 +300,10 @@ if(ot_index EQUAL -1)
|
||||
message(FATAL_ERROR "Invalid value for OT_PLATFORM - valid values are:" "${OT_PLATFORM_VALUES}")
|
||||
endif()
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
set(OT_CRYPTO_LIB_VALUES "MBEDTLS" "PSA" "PLATFORM")
|
||||
ot_multi_option(OT_CRYPTO_LIB OT_CRYPTO_LIB_VALUES OPENTHREAD_CONFIG_CRYPTO_LIB OPENTHREAD_CONFIG_CRYPTO_LIB_ "set Crypto backend library")
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
set(OT_THREAD_VERSION_VALUES "1.1" "1.2" "1.3" "1.3.1" "1.4")
|
||||
set(OT_THREAD_VERSION "1.4" CACHE STRING "set Thread version")
|
||||
@@ -357,7 +361,7 @@ ot_int_option(OT_RCP_TX_WAIT_TIME_SECS OPENTHREAD_SPINEL_CONFIG_RCP_TX_WAIT_TIME
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if(NOT OT_EXTERNAL_MBEDTLS)
|
||||
set(OT_MBEDTLS mbedtls)
|
||||
set(OT_MBEDTLS mbedtls mbedcrypto)
|
||||
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_ENABLE_BUILTIN_MBEDTLS=1")
|
||||
else()
|
||||
set(OT_MBEDTLS ${OT_EXTERNAL_MBEDTLS})
|
||||
|
||||
+4
-2
@@ -481,7 +481,8 @@ openthread_core_files = [
|
||||
"crypto/aes_ecb.cpp",
|
||||
"crypto/aes_ecb.hpp",
|
||||
"crypto/context_size.hpp",
|
||||
"crypto/crypto_platform.cpp",
|
||||
"crypto/crypto_platform_mbedtls.cpp",
|
||||
"crypto/crypto_platform_psa.cpp",
|
||||
"crypto/ecdsa.hpp",
|
||||
"crypto/hkdf_sha256.cpp",
|
||||
"crypto/hkdf_sha256.hpp",
|
||||
@@ -803,7 +804,8 @@ openthread_radio_sources = [
|
||||
"common/uptime.cpp",
|
||||
"crypto/aes_ccm.cpp",
|
||||
"crypto/aes_ecb.cpp",
|
||||
"crypto/crypto_platform.cpp",
|
||||
"crypto/crypto_platform_mbedtls.cpp",
|
||||
"crypto/crypto_platform_psa.cpp",
|
||||
"crypto/storage.cpp",
|
||||
"diags/factory_diags.cpp",
|
||||
"instance/instance.cpp",
|
||||
|
||||
@@ -135,7 +135,8 @@ set(COMMON_SOURCES
|
||||
common/uptime.cpp
|
||||
crypto/aes_ccm.cpp
|
||||
crypto/aes_ecb.cpp
|
||||
crypto/crypto_platform.cpp
|
||||
crypto/crypto_platform_mbedtls.cpp
|
||||
crypto/crypto_platform_psa.cpp
|
||||
crypto/hkdf_sha256.cpp
|
||||
crypto/hmac_sha256.cpp
|
||||
crypto/mbedtls.cpp
|
||||
@@ -307,7 +308,8 @@ set(RADIO_COMMON_SOURCES
|
||||
common/uptime.cpp
|
||||
crypto/aes_ccm.cpp
|
||||
crypto/aes_ecb.cpp
|
||||
crypto/crypto_platform.cpp
|
||||
crypto/crypto_platform_mbedtls.cpp
|
||||
crypto/crypto_platform_psa.cpp
|
||||
crypto/storage.cpp
|
||||
diags/factory_diags.cpp
|
||||
instance/instance.cpp
|
||||
|
||||
@@ -749,74 +749,4 @@ exit:
|
||||
|
||||
#endif // #if OPENTHREAD_FTD
|
||||
|
||||
#elif OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA
|
||||
|
||||
#if OPENTHREAD_FTD || OPENTHREAD_MTD
|
||||
#if OPENTHREAD_CONFIG_ECDSA_ENABLE
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoEcdsaGenerateKey(otPlatCryptoEcdsaKeyPair *aKeyPair)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aKeyPair);
|
||||
|
||||
return OT_ERROR_NOT_CAPABLE;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoEcdsaGetPublicKey(const otPlatCryptoEcdsaKeyPair *aKeyPair,
|
||||
otPlatCryptoEcdsaPublicKey *aPublicKey)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aKeyPair);
|
||||
OT_UNUSED_VARIABLE(aPublicKey);
|
||||
|
||||
return OT_ERROR_NOT_CAPABLE;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoEcdsaSign(const otPlatCryptoEcdsaKeyPair *aKeyPair,
|
||||
const otPlatCryptoSha256Hash *aHash,
|
||||
otPlatCryptoEcdsaSignature *aSignature)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aKeyPair);
|
||||
OT_UNUSED_VARIABLE(aHash);
|
||||
OT_UNUSED_VARIABLE(aSignature);
|
||||
|
||||
return OT_ERROR_NOT_CAPABLE;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoEcdsaVerify(const otPlatCryptoEcdsaPublicKey *aPublicKey,
|
||||
const otPlatCryptoSha256Hash *aHash,
|
||||
const otPlatCryptoEcdsaSignature *aSignature)
|
||||
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aPublicKey);
|
||||
OT_UNUSED_VARIABLE(aHash);
|
||||
OT_UNUSED_VARIABLE(aSignature);
|
||||
|
||||
return OT_ERROR_NOT_CAPABLE;
|
||||
}
|
||||
#endif // #if OPENTHREAD_CONFIG_ECDSA_ENABLE
|
||||
|
||||
#endif // #if OPENTHREAD_FTD || OPENTHREAD_MTD
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoPbkdf2GenerateKey(const uint8_t *aPassword,
|
||||
uint16_t aPasswordLen,
|
||||
const uint8_t *aSalt,
|
||||
uint16_t aSaltLen,
|
||||
uint32_t aIterationCounter,
|
||||
uint16_t aKeyLen,
|
||||
uint8_t *aKey)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aPassword);
|
||||
OT_UNUSED_VARIABLE(aPasswordLen);
|
||||
OT_UNUSED_VARIABLE(aSalt);
|
||||
OT_UNUSED_VARIABLE(aSaltLen);
|
||||
OT_UNUSED_VARIABLE(aIterationCounter);
|
||||
OT_UNUSED_VARIABLE(aKeyLen);
|
||||
OT_UNUSED_VARIABLE(aKey);
|
||||
|
||||
return OT_ERROR_NOT_CAPABLE;
|
||||
}
|
||||
|
||||
#endif // #if OPENTHREAD_FTD
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_MBEDTLS
|
||||
@@ -0,0 +1,761 @@
|
||||
/*
|
||||
* Copyright (c) 2025, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements the default/weak Crypto platform APIs using ARM PSA API.
|
||||
*/
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <mbedtls/asn1.h>
|
||||
#include <psa/crypto.h>
|
||||
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/platform/crypto.h>
|
||||
#include <openthread/platform/entropy.h>
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "common/new.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;
|
||||
using namespace Crypto;
|
||||
|
||||
#if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Default/weak implementation of crypto platform APIs
|
||||
|
||||
static otError psaToOtError(psa_status_t aStatus)
|
||||
{
|
||||
switch (aStatus)
|
||||
{
|
||||
case PSA_SUCCESS:
|
||||
return kErrorNone;
|
||||
case PSA_ERROR_INVALID_ARGUMENT:
|
||||
return kErrorInvalidArgs;
|
||||
case PSA_ERROR_BUFFER_TOO_SMALL:
|
||||
return kErrorNoBufs;
|
||||
default:
|
||||
return kErrorFailed;
|
||||
}
|
||||
}
|
||||
|
||||
static psa_key_type_t toPsaKeyType(otCryptoKeyType aType)
|
||||
{
|
||||
switch (aType)
|
||||
{
|
||||
case OT_CRYPTO_KEY_TYPE_RAW:
|
||||
return PSA_KEY_TYPE_RAW_DATA;
|
||||
case OT_CRYPTO_KEY_TYPE_AES:
|
||||
return PSA_KEY_TYPE_AES;
|
||||
case OT_CRYPTO_KEY_TYPE_HMAC:
|
||||
return PSA_KEY_TYPE_HMAC;
|
||||
case OT_CRYPTO_KEY_TYPE_ECDSA:
|
||||
return PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
|
||||
case OT_CRYPTO_KEY_TYPE_DERIVE:
|
||||
return PSA_KEY_TYPE_DERIVE;
|
||||
default:
|
||||
return PSA_KEY_TYPE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static psa_algorithm_t toPsaAlgorithm(otCryptoKeyAlgorithm aAlgorithm)
|
||||
{
|
||||
switch (aAlgorithm)
|
||||
{
|
||||
case OT_CRYPTO_KEY_ALG_AES_ECB:
|
||||
return PSA_ALG_ECB_NO_PADDING;
|
||||
case OT_CRYPTO_KEY_ALG_HMAC_SHA_256:
|
||||
return PSA_ALG_HMAC(PSA_ALG_SHA_256);
|
||||
case OT_CRYPTO_KEY_ALG_ECDSA:
|
||||
return PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256);
|
||||
case OT_CRYPTO_KEY_ALG_HKDF_SHA256:
|
||||
return PSA_ALG_HKDF(PSA_ALG_SHA_256);
|
||||
default:
|
||||
return PSA_ALG_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static psa_key_usage_t toPsaKeyUsage(int aUsage)
|
||||
{
|
||||
psa_key_usage_t usage = 0;
|
||||
|
||||
if (aUsage & OT_CRYPTO_KEY_USAGE_EXPORT)
|
||||
{
|
||||
usage |= PSA_KEY_USAGE_EXPORT;
|
||||
}
|
||||
|
||||
if (aUsage & OT_CRYPTO_KEY_USAGE_ENCRYPT)
|
||||
{
|
||||
usage |= PSA_KEY_USAGE_ENCRYPT;
|
||||
}
|
||||
|
||||
if (aUsage & OT_CRYPTO_KEY_USAGE_DECRYPT)
|
||||
{
|
||||
usage |= PSA_KEY_USAGE_DECRYPT;
|
||||
}
|
||||
|
||||
if (aUsage & OT_CRYPTO_KEY_USAGE_SIGN_HASH)
|
||||
{
|
||||
usage |= PSA_KEY_USAGE_SIGN_HASH;
|
||||
}
|
||||
|
||||
if (aUsage & OT_CRYPTO_KEY_USAGE_VERIFY_HASH)
|
||||
{
|
||||
usage |= PSA_KEY_USAGE_VERIFY_HASH;
|
||||
}
|
||||
|
||||
if (aUsage & OT_CRYPTO_KEY_USAGE_DERIVE)
|
||||
{
|
||||
usage |= PSA_KEY_USAGE_DERIVE;
|
||||
}
|
||||
|
||||
return usage;
|
||||
}
|
||||
|
||||
static bool checkKeyUsage(int aUsage)
|
||||
{
|
||||
/* Check if only supported flags have been passed */
|
||||
int supportedFlags = OT_CRYPTO_KEY_USAGE_EXPORT | OT_CRYPTO_KEY_USAGE_ENCRYPT | OT_CRYPTO_KEY_USAGE_DECRYPT |
|
||||
OT_CRYPTO_KEY_USAGE_SIGN_HASH | OT_CRYPTO_KEY_USAGE_VERIFY_HASH | OT_CRYPTO_KEY_USAGE_DERIVE;
|
||||
|
||||
return (aUsage & ~supportedFlags) == 0;
|
||||
}
|
||||
|
||||
static bool checkContext(otCryptoContext *aContext, size_t aMinSize)
|
||||
{
|
||||
/* Verify that the passed context is initialized and points to a big enough buffer */
|
||||
return aContext != nullptr && aContext->mContext != nullptr && aContext->mContextSize >= aMinSize;
|
||||
}
|
||||
|
||||
static otError extractPrivateKeyInfo(const uint8_t *aAsn1KeyPair,
|
||||
size_t aAsn1KeyPairLen,
|
||||
size_t *aKeyOffset,
|
||||
size_t *aKeyLen)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
unsigned char *p = const_cast<unsigned char *>(aAsn1KeyPair);
|
||||
const unsigned char *end = p + aAsn1KeyPairLen;
|
||||
size_t len;
|
||||
|
||||
// Parse the ASN.1 SEQUENCE headers
|
||||
int ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
|
||||
VerifyOrExit(ret == 0, error = kErrorInvalidArgs);
|
||||
|
||||
// Parse the version (INTEGER)
|
||||
ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER);
|
||||
VerifyOrExit(ret == 0, error = kErrorInvalidArgs);
|
||||
|
||||
// Skip the version.
|
||||
p += len;
|
||||
|
||||
// Parse the private key (OCTET STRING)
|
||||
ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
|
||||
VerifyOrExit(ret == 0, error = kErrorInvalidArgs);
|
||||
|
||||
// Check if the private key includes a padding byte (0x00)
|
||||
if (*p == 0x00)
|
||||
{
|
||||
p++;
|
||||
len--; // Skip the padding byte and reduce length by 1
|
||||
}
|
||||
|
||||
*aKeyOffset = (p - aAsn1KeyPair);
|
||||
*aKeyLen = len;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK void otPlatCryptoInit(void) { psa_crypto_init(); }
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef,
|
||||
otCryptoKeyType aKeyType,
|
||||
otCryptoKeyAlgorithm aKeyAlgorithm,
|
||||
int aKeyUsage,
|
||||
otCryptoKeyStorage aKeyPersistence,
|
||||
const uint8_t *aKey,
|
||||
size_t aKeyLen)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
|
||||
VerifyOrExit(checkKeyUsage(aKeyUsage), error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aKeyRef != nullptr && aKey != nullptr, error = kErrorInvalidArgs);
|
||||
|
||||
// PSA Crypto API expects the private key to be provided, not the full ASN1 buffer.
|
||||
if (aKeyType == OT_CRYPTO_KEY_TYPE_ECDSA)
|
||||
{
|
||||
size_t pkOffset;
|
||||
size_t pkLength;
|
||||
|
||||
SuccessOrExit(error = extractPrivateKeyInfo(aKey, aKeyLen, &pkOffset, &pkLength));
|
||||
|
||||
// Overwrite the content of the key.
|
||||
aKey += pkOffset;
|
||||
aKeyLen = pkLength;
|
||||
|
||||
psa_set_key_bits(&attributes, 256);
|
||||
}
|
||||
|
||||
psa_set_key_type(&attributes, toPsaKeyType(aKeyType));
|
||||
psa_set_key_algorithm(&attributes, toPsaAlgorithm(aKeyAlgorithm));
|
||||
psa_set_key_usage_flags(&attributes, toPsaKeyUsage(aKeyUsage));
|
||||
|
||||
switch (aKeyPersistence)
|
||||
{
|
||||
case OT_CRYPTO_KEY_STORAGE_PERSISTENT:
|
||||
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_PERSISTENT);
|
||||
psa_set_key_id(&attributes, *aKeyRef);
|
||||
break;
|
||||
case OT_CRYPTO_KEY_STORAGE_VOLATILE:
|
||||
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
|
||||
break;
|
||||
default:
|
||||
OT_ASSERT(false);
|
||||
}
|
||||
|
||||
status = psa_import_key(&attributes, aKey, aKeyLen, aKeyRef);
|
||||
|
||||
exit:
|
||||
psa_reset_key_attributes(&attributes);
|
||||
|
||||
if (error != kErrorNone)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
return psaToOtError(status);
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, uint8_t *aBuffer, size_t aBufferLen, size_t *aKeyLen)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(aBuffer != nullptr && aKeyLen != nullptr, error = kErrorInvalidArgs);
|
||||
|
||||
error = psaToOtError(psa_export_key(aKeyRef, aBuffer, aBufferLen, aKeyLen));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoDestroyKey(otCryptoKeyRef aKeyRef) { return psaToOtError(psa_destroy_key(aKeyRef)); }
|
||||
|
||||
OT_TOOL_WEAK bool otPlatCryptoHasKey(otCryptoKeyRef aKeyRef)
|
||||
{
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_status_t status;
|
||||
|
||||
status = psa_get_key_attributes(aKeyRef, &attributes);
|
||||
psa_reset_key_attributes(&attributes);
|
||||
|
||||
return status == PSA_SUCCESS;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoAesInit(otCryptoContext *aContext)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_key_id_t *keyRef;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_key_id_t)), error = kErrorInvalidArgs);
|
||||
|
||||
keyRef = static_cast<psa_key_id_t *>(aContext->mContext);
|
||||
*keyRef = PSA_KEY_ID_NULL;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoAesSetKey(otCryptoContext *aContext, const otCryptoKey *aKey)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_key_id_t *keyRef;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_key_id_t)), error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aKey != nullptr, error = kErrorInvalidArgs);
|
||||
|
||||
keyRef = static_cast<psa_key_id_t *>(aContext->mContext);
|
||||
*keyRef = aKey->mKeyRef;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, uint8_t *aOutput)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
const size_t blockSize = PSA_BLOCK_CIPHER_BLOCK_LENGTH(PSA_KEY_TYPE_AES);
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
psa_key_id_t *keyRef;
|
||||
size_t cipherLen;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_key_id_t)), error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aInput != nullptr && aOutput != nullptr, error = kErrorInvalidArgs);
|
||||
|
||||
keyRef = static_cast<psa_key_id_t *>(aContext->mContext);
|
||||
status = psa_cipher_encrypt(*keyRef, PSA_ALG_ECB_NO_PADDING, aInput, blockSize, aOutput, blockSize, &cipherLen);
|
||||
|
||||
error = psaToOtError(status);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoAesFree(otCryptoContext *aContext)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aContext);
|
||||
|
||||
return kErrorNone;
|
||||
}
|
||||
|
||||
#if !OPENTHREAD_RADIO
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoHmacSha256Init(otCryptoContext *aContext)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_mac_operation_t *operation;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_mac_operation_t)), error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_mac_operation_t *>(aContext->mContext);
|
||||
|
||||
// Initialize the structure using memset as documented alternative for psa_mac_operation_init().
|
||||
memset(operation, 0, sizeof(*operation));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoHmacSha256Deinit(otCryptoContext *aContext)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_mac_operation_t *operation;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_mac_operation_t)), error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_mac_operation_t *>(aContext->mContext);
|
||||
|
||||
error = psaToOtError(psa_mac_abort(operation));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoHmacSha256Start(otCryptoContext *aContext, const otCryptoKey *aKey)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_mac_operation_t *operation;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_mac_operation_t)), error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aKey != nullptr, error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_mac_operation_t *>(aContext->mContext);
|
||||
|
||||
error = psaToOtError(psa_mac_sign_setup(operation, aKey->mKeyRef, PSA_ALG_HMAC(PSA_ALG_SHA_256)));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, const void *aBuf, uint16_t aBufLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_mac_operation_t *operation;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_mac_operation_t)), error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aBuf != nullptr, error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_mac_operation_t *>(aContext->mContext);
|
||||
|
||||
error = psaToOtError(psa_mac_update(operation, static_cast<const uint8_t *>(aBuf), aBufLength));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoHmacSha256Finish(otCryptoContext *aContext, uint8_t *aBuf, size_t aBufLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_mac_operation_t *operation;
|
||||
size_t macLength;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_mac_operation_t)), error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aBuf != nullptr, error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_mac_operation_t *>(aContext->mContext);
|
||||
|
||||
error = psaToOtError(psa_mac_sign_finish(operation, aBuf, aBufLength, &macLength));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoHkdfInit(otCryptoContext *aContext)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_key_derivation_operation_t *operation;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_key_derivation_operation_t)), error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_key_derivation_operation_t *>(aContext->mContext);
|
||||
|
||||
*operation = PSA_KEY_DERIVATION_OPERATION_INIT;
|
||||
|
||||
error = psaToOtError(psa_key_derivation_setup(operation, PSA_ALG_HKDF(PSA_ALG_SHA_256)));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoHkdfExtract(otCryptoContext *aContext,
|
||||
const uint8_t *aSalt,
|
||||
uint16_t aSaltLength,
|
||||
const otCryptoKey *aInputKey)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
psa_key_derivation_operation_t *operation;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_key_derivation_operation_t)), error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aInputKey != nullptr, error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_key_derivation_operation_t *>(aContext->mContext);
|
||||
|
||||
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);
|
||||
SuccessOrExit(error = psaToOtError(status));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoHkdfExpand(otCryptoContext *aContext,
|
||||
const uint8_t *aInfo,
|
||||
uint16_t aInfoLength,
|
||||
uint8_t *aOutputKey,
|
||||
uint16_t aOutputKeyLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
psa_key_derivation_operation_t *operation;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_key_derivation_operation_t)), error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aOutputKey != nullptr, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aOutputKeyLength != 0, error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_key_derivation_operation_t *>(aContext->mContext);
|
||||
|
||||
status = psa_key_derivation_input_bytes(operation, PSA_KEY_DERIVATION_INPUT_INFO, aInfo, aInfoLength);
|
||||
SuccessOrExit(error = psaToOtError(status));
|
||||
|
||||
status = psa_key_derivation_output_bytes(operation, aOutputKey, aOutputKeyLength);
|
||||
SuccessOrExit(error = psaToOtError(status));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoHkdfDeinit(otCryptoContext *aContext)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_key_derivation_operation_t *operation;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_key_derivation_operation_t)), error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_key_derivation_operation_t *>(aContext->mContext);
|
||||
|
||||
error = psaToOtError(psa_key_derivation_abort(operation));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoSha256Init(otCryptoContext *aContext)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_hash_operation_t *operation;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_hash_operation_t)), error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_hash_operation_t *>(aContext->mContext);
|
||||
|
||||
// Initialize the structure using memset as documented alternative for psa_hash_operation_init().
|
||||
memset(operation, 0, sizeof(*operation));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoSha256Deinit(otCryptoContext *aContext)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_hash_operation_t *operation;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_hash_operation_t)), error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_hash_operation_t *>(aContext->mContext);
|
||||
|
||||
error = psaToOtError(psa_hash_abort(operation));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoSha256Start(otCryptoContext *aContext)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_hash_operation_t *operation;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_hash_operation_t)), error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_hash_operation_t *>(aContext->mContext);
|
||||
|
||||
error = psaToOtError(psa_hash_setup(operation, PSA_ALG_SHA_256));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoSha256Update(otCryptoContext *aContext, const void *aBuf, uint16_t aBufLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_hash_operation_t *operation;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_hash_operation_t)), error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aBuf != nullptr, error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_hash_operation_t *>(aContext->mContext);
|
||||
|
||||
error = psaToOtError(psa_hash_update(operation, static_cast<const uint8_t *>(aBuf), aBufLength));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoSha256Finish(otCryptoContext *aContext, uint8_t *aHash, uint16_t aHashSize)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
psa_hash_operation_t *operation;
|
||||
size_t hashSize;
|
||||
|
||||
VerifyOrExit(checkContext(aContext, sizeof(psa_hash_operation_t)), error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aHash != nullptr, error = kErrorInvalidArgs);
|
||||
|
||||
operation = static_cast<psa_hash_operation_t *>(aContext->mContext);
|
||||
|
||||
error = psaToOtError(psa_hash_finish(operation, aHash, aHashSize, &hashSize));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK void otPlatCryptoRandomInit(void) { psa_crypto_init(); }
|
||||
|
||||
OT_TOOL_WEAK void otPlatCryptoRandomDeinit(void)
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoRandomGet(uint8_t *aBuffer, uint16_t aSize)
|
||||
{
|
||||
return psaToOtError(psa_generate_random(aBuffer, aSize));
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ECDSA_ENABLE
|
||||
|
||||
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_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));
|
||||
psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
|
||||
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_PERSISTENT);
|
||||
psa_set_key_id(&attributes, keyId);
|
||||
psa_set_key_bits(&attributes, 256);
|
||||
|
||||
status = psa_generate_key(&attributes, &keyId);
|
||||
VerifyOrExit(status == PSA_SUCCESS);
|
||||
|
||||
exit:
|
||||
psa_reset_key_attributes(&attributes);
|
||||
|
||||
return psaToOtError(status);
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoEcdsaExportPublicKey(otCryptoKeyRef aKeyRef, otPlatCryptoEcdsaPublicKey *aPublicKey)
|
||||
{
|
||||
psa_status_t status;
|
||||
size_t exportedLen;
|
||||
uint8_t buffer[1 + OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE];
|
||||
|
||||
status = psa_export_public_key(aKeyRef, buffer, sizeof(buffer), &exportedLen);
|
||||
VerifyOrExit(status == PSA_SUCCESS);
|
||||
|
||||
OT_ASSERT(exportedLen == sizeof(buffer));
|
||||
memcpy(aPublicKey->m8, buffer + 1, OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE);
|
||||
|
||||
exit:
|
||||
return psaToOtError(status);
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoEcdsaSignUsingKeyRef(otCryptoKeyRef aKeyRef,
|
||||
const otPlatCryptoSha256Hash *aHash,
|
||||
otPlatCryptoEcdsaSignature *aSignature)
|
||||
{
|
||||
psa_status_t status;
|
||||
size_t signatureLen;
|
||||
|
||||
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);
|
||||
|
||||
OT_ASSERT(signatureLen == OT_CRYPTO_ECDSA_SIGNATURE_SIZE);
|
||||
|
||||
exit:
|
||||
return psaToOtError(status);
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoEcdsaVerify(const otPlatCryptoEcdsaPublicKey *aPublicKey,
|
||||
const otPlatCryptoSha256Hash *aHash,
|
||||
const otPlatCryptoEcdsaSignature *aSignature)
|
||||
{
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_id_t keyId = PSA_KEY_ID_NULL;
|
||||
psa_status_t status;
|
||||
uint8_t buffer[1 + OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE];
|
||||
|
||||
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));
|
||||
psa_set_key_bits(&attributes, 256);
|
||||
|
||||
/*
|
||||
* `psa_import_key` expects a key format as specified by SEC1 §2.3.3 for the
|
||||
* uncompressed representation of the ECPoint.
|
||||
*/
|
||||
buffer[0] = 0x04;
|
||||
memcpy(buffer + 1, aPublicKey->m8, OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE);
|
||||
|
||||
status = psa_import_key(&attributes, buffer, sizeof(buffer), &keyId);
|
||||
VerifyOrExit(status == PSA_SUCCESS);
|
||||
|
||||
status = psa_verify_hash(keyId, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), aHash->m8, OT_CRYPTO_SHA256_HASH_SIZE,
|
||||
aSignature->m8, OT_CRYPTO_ECDSA_SIGNATURE_SIZE);
|
||||
VerifyOrExit(status == PSA_SUCCESS);
|
||||
|
||||
exit:
|
||||
psa_reset_key_attributes(&attributes);
|
||||
psa_destroy_key(keyId);
|
||||
|
||||
return psaToOtError(status);
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoEcdsaVerifyUsingKeyRef(otCryptoKeyRef aKeyRef,
|
||||
const otPlatCryptoSha256Hash *aHash,
|
||||
const otPlatCryptoEcdsaSignature *aSignature)
|
||||
{
|
||||
psa_status_t status;
|
||||
|
||||
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);
|
||||
VerifyOrExit(status == PSA_SUCCESS);
|
||||
|
||||
exit:
|
||||
return psaToOtError(status);
|
||||
}
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_ECDSA_ENABLE
|
||||
|
||||
#endif // #if !OPENTHREAD_RADIO
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
OT_TOOL_WEAK otError otPlatCryptoPbkdf2GenerateKey(const uint8_t *aPassword,
|
||||
uint16_t aPasswordLen,
|
||||
const uint8_t *aSalt,
|
||||
uint16_t aSaltLen,
|
||||
uint32_t aIterationCounter,
|
||||
uint16_t aKeyLen,
|
||||
uint8_t *aKey)
|
||||
{
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
psa_key_id_t key_id = PSA_KEY_ID_NULL;
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_algorithm_t algorithm = PSA_ALG_PBKDF2_AES_CMAC_PRF_128;
|
||||
psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
|
||||
|
||||
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
|
||||
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
|
||||
psa_set_key_algorithm(&attributes, algorithm);
|
||||
psa_set_key_type(&attributes, PSA_KEY_TYPE_PASSWORD);
|
||||
psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(aPasswordLen));
|
||||
|
||||
status = psa_import_key(&attributes, aPassword, aPasswordLen, &key_id);
|
||||
VerifyOrExit(status == PSA_SUCCESS);
|
||||
|
||||
status = psa_key_derivation_setup(&operation, algorithm);
|
||||
VerifyOrExit(status == PSA_SUCCESS);
|
||||
|
||||
status = psa_key_derivation_input_integer(&operation, PSA_KEY_DERIVATION_INPUT_COST, aIterationCounter);
|
||||
VerifyOrExit(status == PSA_SUCCESS);
|
||||
|
||||
status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT, aSalt, aSaltLen);
|
||||
VerifyOrExit(status == PSA_SUCCESS);
|
||||
|
||||
status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, key_id);
|
||||
VerifyOrExit(status == PSA_SUCCESS);
|
||||
|
||||
status = psa_key_derivation_output_bytes(&operation, aKey, aKeyLen);
|
||||
VerifyOrExit(status == PSA_SUCCESS);
|
||||
|
||||
exit:
|
||||
psa_reset_key_attributes(&attributes);
|
||||
psa_key_derivation_abort(&operation);
|
||||
psa_destroy_key(key_id);
|
||||
|
||||
return psaToOtError(status);
|
||||
}
|
||||
|
||||
#endif // #if OPENTHREAD_FTD
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA
|
||||
Reference in New Issue
Block a user