797 lines
27 KiB
C
797 lines
27 KiB
C
/*
|
|
* Copyright (c) 2023, 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 OpenThread platform abstraction for PSA.
|
|
*
|
|
*/
|
|
|
|
#include <openthread-core-config.h>
|
|
#include <openthread/error.h>
|
|
#include <openthread/platform/crypto.h>
|
|
|
|
#if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA
|
|
#include "security_manager.h"
|
|
#include "common/debug.hpp"
|
|
#include "utils/code_utils.h"
|
|
|
|
#include "em_device.h"
|
|
#include <mbedtls/ecdsa.h>
|
|
#include <mbedtls/md.h>
|
|
#include <mbedtls/pk.h>
|
|
#include "mbedtls/psa_util.h"
|
|
#if defined(_SILICON_LABS_32B_SERIES_2)
|
|
#include "em_system.h"
|
|
#else
|
|
#include "sl_hal_system.h"
|
|
#endif
|
|
#include "sl_psa_crypto.h"
|
|
|
|
#if defined(_SILICON_LABS_32B_SERIES_2)
|
|
#define GET_SECURITY_CAPABILITY SYSTEM_GetSecurityCapability
|
|
#define VAULT_ENABLED securityCapabilityVault
|
|
#else
|
|
#define GET_SECURITY_CAPABILITY sl_hal_system_get_security_capability
|
|
#define VAULT_ENABLED SL_SYSTEM_SECURITY_CAPABILITY_VAULT
|
|
#endif
|
|
|
|
#define PERSISTENCE_KEY_ID_USED_MAX (7)
|
|
#define MAX_HMAC_KEY_SIZE (32)
|
|
|
|
// Helper function to convert otCryptoKeyType to psa_key_type_t
|
|
static psa_key_type_t getPsaKeyType(otCryptoKeyType aKeyType)
|
|
{
|
|
psa_key_type_t aPsaKeyType = 0;
|
|
|
|
switch (aKeyType)
|
|
{
|
|
case OT_CRYPTO_KEY_TYPE_RAW:
|
|
aPsaKeyType = PSA_KEY_TYPE_RAW_DATA;
|
|
break;
|
|
|
|
case OT_CRYPTO_KEY_TYPE_AES:
|
|
aPsaKeyType = PSA_KEY_TYPE_AES;
|
|
break;
|
|
|
|
case OT_CRYPTO_KEY_TYPE_HMAC:
|
|
aPsaKeyType = PSA_KEY_TYPE_HMAC;
|
|
break;
|
|
|
|
case OT_CRYPTO_KEY_TYPE_ECDSA:
|
|
aPsaKeyType = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
|
|
break;
|
|
}
|
|
|
|
return aPsaKeyType;
|
|
}
|
|
|
|
// Helper function to convert aKeyAlgorithm to psa_algorithm_t
|
|
static psa_algorithm_t getPsaAlgorithm(otCryptoKeyAlgorithm aKeyAlgorithm)
|
|
{
|
|
psa_algorithm_t aPsaKeyAlgorithm = 0;
|
|
|
|
switch (aKeyAlgorithm)
|
|
{
|
|
case OT_CRYPTO_KEY_ALG_VENDOR:
|
|
aPsaKeyAlgorithm = PSA_ALG_VENDOR_FLAG;
|
|
break;
|
|
|
|
case OT_CRYPTO_KEY_ALG_AES_ECB:
|
|
aPsaKeyAlgorithm = PSA_ALG_ECB_NO_PADDING;
|
|
break;
|
|
|
|
case OT_CRYPTO_KEY_ALG_HMAC_SHA_256:
|
|
aPsaKeyAlgorithm = PSA_ALG_HMAC(PSA_ALG_SHA_256);
|
|
break;
|
|
|
|
case OT_CRYPTO_KEY_ALG_ECDSA:
|
|
aPsaKeyAlgorithm = PSA_ALG_ECDSA(PSA_ALG_ANY_HASH);
|
|
break;
|
|
}
|
|
|
|
return aPsaKeyAlgorithm;
|
|
}
|
|
|
|
// Helper function to convert aKeyUsage to psa_key_usage_t
|
|
static psa_key_usage_t getPsaKeyUsage(int aKeyUsage)
|
|
{
|
|
psa_key_usage_t aPsaKeyUsage = 0;
|
|
|
|
if (aKeyUsage & OT_CRYPTO_KEY_USAGE_EXPORT)
|
|
{
|
|
aPsaKeyUsage |= PSA_KEY_USAGE_EXPORT;
|
|
}
|
|
|
|
if (aKeyUsage & OT_CRYPTO_KEY_USAGE_ENCRYPT)
|
|
{
|
|
aPsaKeyUsage |= PSA_KEY_USAGE_ENCRYPT;
|
|
}
|
|
|
|
if (aKeyUsage & OT_CRYPTO_KEY_USAGE_DECRYPT)
|
|
{
|
|
aPsaKeyUsage |= PSA_KEY_USAGE_DECRYPT;
|
|
}
|
|
|
|
if (aKeyUsage & OT_CRYPTO_KEY_USAGE_SIGN_HASH)
|
|
{
|
|
aPsaKeyUsage |= PSA_KEY_USAGE_SIGN_HASH;
|
|
}
|
|
|
|
if (aKeyUsage & OT_CRYPTO_KEY_USAGE_VERIFY_HASH)
|
|
{
|
|
aPsaKeyUsage |= PSA_KEY_USAGE_VERIFY_HASH;
|
|
}
|
|
|
|
return aPsaKeyUsage;
|
|
}
|
|
|
|
// Helper function to convert otCryptoKeyStorage to psa_key_persistence_t
|
|
static psa_key_persistence_t getPsaKeyPersistence(otCryptoKeyStorage aKeyPersistence)
|
|
{
|
|
psa_key_persistence_t aPsaKeyPersistence = 0;
|
|
|
|
switch (aKeyPersistence)
|
|
{
|
|
case OT_CRYPTO_KEY_STORAGE_VOLATILE:
|
|
aPsaKeyPersistence = PSA_KEY_PERSISTENCE_VOLATILE;
|
|
break;
|
|
|
|
case OT_CRYPTO_KEY_STORAGE_PERSISTENT:
|
|
aPsaKeyPersistence = PSA_KEY_PERSISTENCE_DEFAULT;
|
|
break;
|
|
}
|
|
|
|
return aPsaKeyPersistence;
|
|
}
|
|
|
|
#if defined(SEMAILBOX_PRESENT) && !defined(SL_TRUSTZONE_NONSECURE)
|
|
static bool shouldWrap(psa_key_attributes_t *key_attr)
|
|
{
|
|
psa_key_location_t keyLocation = PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(key_attr));
|
|
psa_key_type_t keyType = psa_get_key_type(key_attr);
|
|
|
|
return ((keyLocation != SL_PSA_KEY_LOCATION_WRAPPED) && (keyType != PSA_KEY_TYPE_HMAC));
|
|
}
|
|
|
|
static void checkAndWrapKeys(void)
|
|
{
|
|
for (int index = 1; index <= PERSISTENCE_KEY_ID_USED_MAX; index++)
|
|
{
|
|
otCryptoKeyRef key_ref = OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET + index;
|
|
psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
|
|
|
|
// If there is a key present in the location..
|
|
if (sl_sec_man_get_key_attributes(key_ref, &key_attr) == PSA_SUCCESS)
|
|
{
|
|
if (shouldWrap(&key_attr))
|
|
{
|
|
// Wrap the key..
|
|
otCryptoKeyRef dst_key_ref = key_ref;
|
|
psa_key_lifetime_t key_lifetime =
|
|
PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_DEFAULT,
|
|
SL_PSA_KEY_LOCATION_WRAPPED);
|
|
|
|
psa_set_key_lifetime(&key_attr, key_lifetime);
|
|
sl_sec_man_copy_key(key_ref, &key_attr, &dst_key_ref);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // SEMAILBOX_PRESENT && !SL_TRUSTZONE_NONSECURE
|
|
|
|
void otPlatCryptoInit(void)
|
|
{
|
|
#if defined(SEMAILBOX_PRESENT) && !defined(SL_TRUSTZONE_NONSECURE)
|
|
if (GET_SECURITY_CAPABILITY() == VAULT_ENABLED)
|
|
{
|
|
checkAndWrapKeys();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static otError extractPrivateKeyFromDer(uint8_t *aPrivateKey, const uint8_t *aDer, uint8_t aDerLen)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
mbedtls_pk_context pk;
|
|
mbedtls_ecp_keypair *keyPair;
|
|
|
|
mbedtls_pk_init(&pk);
|
|
|
|
otEXPECT_ACTION(mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) == 0, error = OT_ERROR_FAILED);
|
|
|
|
#if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
|
|
otEXPECT_ACTION(mbedtls_pk_parse_key(&pk, aDer, aDerLen, NULL, 0, mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE)
|
|
== 0,
|
|
error = OT_ERROR_PARSE);
|
|
#else
|
|
otEXPECT_ACTION(mbedtls_pk_parse_key(&pk, aDer, aDerLen, NULL, 0) == 0, error = OT_ERROR_PARSE);
|
|
#endif
|
|
|
|
keyPair = mbedtls_pk_ec(pk);
|
|
mbedtls_mpi_write_binary(&keyPair->MBEDTLS_PRIVATE(d), aPrivateKey, SL_OPENTHREAD_ECDSA_PRIVATE_KEY_SIZE);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyId,
|
|
otCryptoKeyType aKeyType,
|
|
otCryptoKeyAlgorithm aKeyAlgorithm,
|
|
int aKeyUsage,
|
|
otCryptoKeyStorage aKeyPersistence,
|
|
const uint8_t *aKey,
|
|
size_t aKeyLen)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_status_t status;
|
|
uint8_t aPrivateKey[SL_OPENTHREAD_ECDSA_PRIVATE_KEY_SIZE];
|
|
const uint8_t *keyToImport = aKey;
|
|
size_t keySize = aKeyLen;
|
|
|
|
if (aKeyType == OT_CRYPTO_KEY_TYPE_ECDSA)
|
|
{
|
|
error = extractPrivateKeyFromDer(aPrivateKey, aKey, aKeyLen);
|
|
keyToImport = aPrivateKey;
|
|
keySize = SL_OPENTHREAD_ECDSA_PRIVATE_KEY_SIZE;
|
|
}
|
|
|
|
status = sl_sec_man_import_key(aKeyId,
|
|
getPsaKeyType(aKeyType),
|
|
getPsaAlgorithm(aKeyAlgorithm),
|
|
getPsaKeyUsage(aKeyUsage),
|
|
getPsaKeyPersistence(aKeyPersistence),
|
|
keyToImport,
|
|
keySize);
|
|
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoExportKey(otCryptoKeyRef aKeyId, uint8_t *aBuffer, size_t aBufferLen, size_t *aKeyLen)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_status_t status;
|
|
|
|
status = sl_sec_man_export_key(aKeyId, aBuffer, aBufferLen, aKeyLen);
|
|
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoDestroyKey(otCryptoKeyRef aKeyId)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_status_t status;
|
|
|
|
status = sl_sec_man_destroy_key(aKeyId);
|
|
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
bool otPlatCryptoHasKey(otCryptoKeyRef aKeyRef)
|
|
{
|
|
psa_key_attributes_t aAttr = PSA_KEY_ATTRIBUTES_INIT;
|
|
|
|
return (sl_sec_man_get_key_attributes(aKeyRef, &aAttr) == PSA_SUCCESS);
|
|
}
|
|
|
|
// AES Implementation
|
|
otError otPlatCryptoAesInit(otCryptoContext *aContext)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
(void)aContext;
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoAesSetKey(otCryptoContext *aContext, const otCryptoKey *aKey)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
otCryptoKeyRef *mKeyRef = NULL;
|
|
|
|
otEXPECT_ACTION((aContext != NULL) && (aContext->mContext != NULL), error = OT_ERROR_INVALID_ARGS);
|
|
|
|
mKeyRef = (otCryptoKeyRef *)aContext->mContext;
|
|
*mKeyRef = aKey->mKeyRef;
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, uint8_t *aOutput)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_status_t status;
|
|
otCryptoKeyRef *mKeyRef = NULL;
|
|
|
|
otEXPECT_ACTION(((aContext != NULL) && (aContext->mContext != NULL) && (aOutput != NULL) && (aInput != NULL)),
|
|
error = OT_ERROR_INVALID_ARGS);
|
|
mKeyRef = (otCryptoKeyRef *)aContext->mContext;
|
|
status = sl_sec_man_aes_encrypt(*mKeyRef, PSA_ALG_ECB_NO_PADDING, aInput, aOutput);
|
|
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoAesFree(otCryptoContext *aContext)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
(void)aContext;
|
|
return error;
|
|
}
|
|
|
|
// HMAC implementations
|
|
otError otPlatCryptoHmacSha256Init(otCryptoContext *aContext)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_mac_operation_t *mMacOperation = (psa_mac_operation_t *)aContext->mContext;
|
|
*mMacOperation = psa_mac_operation_init();
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoHmacSha256Deinit(otCryptoContext *aContext)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_mac_operation_t *mMacOperation = (psa_mac_operation_t *)aContext->mContext;
|
|
psa_status_t status;
|
|
|
|
status = sl_sec_man_hmac_deinit(mMacOperation);
|
|
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
static psa_status_t reImportUnwrapped(const otCryptoKey *aKey, otCryptoKeyRef *aHmacKeyRef)
|
|
{
|
|
psa_status_t status = PSA_SUCCESS;
|
|
|
|
#if defined(SEMAILBOX_PRESENT)
|
|
uint8_t hmacKeyBytes[MAX_HMAC_KEY_SIZE];
|
|
size_t key_size;
|
|
psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
|
|
|
|
status = sl_sec_man_get_key_attributes(aKey->mKeyRef, &key_attr);
|
|
|
|
otEXPECT(status == PSA_SUCCESS);
|
|
|
|
status = sl_sec_man_export_key(aKey->mKeyRef, hmacKeyBytes, sizeof(hmacKeyBytes), &key_size);
|
|
|
|
otEXPECT(status == PSA_SUCCESS);
|
|
|
|
status = sl_sec_man_import_key(aHmacKeyRef,
|
|
psa_get_key_type(&key_attr),
|
|
psa_get_key_algorithm(&key_attr),
|
|
psa_get_key_usage_flags(&key_attr),
|
|
PSA_KEY_PERSISTENCE_VOLATILE,
|
|
hmacKeyBytes,
|
|
key_size);
|
|
|
|
memset(hmacKeyBytes, 0, sizeof(hmacKeyBytes));
|
|
|
|
otEXPECT(status == PSA_SUCCESS);
|
|
|
|
exit:
|
|
#else
|
|
*aHmacKeyRef = aKey->mKeyRef;
|
|
#endif
|
|
return status;
|
|
}
|
|
|
|
otError otPlatCryptoHmacSha256Start(otCryptoContext *aContext, const otCryptoKey *aKey)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_mac_operation_t *mMacOperation = (psa_mac_operation_t *)aContext->mContext;
|
|
psa_status_t status;
|
|
otCryptoKeyRef hmacKeyRef;
|
|
|
|
status = reImportUnwrapped(aKey, &hmacKeyRef);
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
status = sl_sec_man_hmac_start(mMacOperation, hmacKeyRef);
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
#if defined(SEMAILBOX_PRESENT)
|
|
sl_sec_man_destroy_key(hmacKeyRef);
|
|
#else
|
|
hmacKeyRef = 0;
|
|
#endif
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, const void *aBuf, uint16_t aBufLength)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_mac_operation_t *mMacOperation = (psa_mac_operation_t *)aContext->mContext;
|
|
psa_status_t status;
|
|
|
|
status = sl_sec_man_hmac_update(mMacOperation, (const uint8_t *)aBuf, (size_t)aBufLength);
|
|
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoHmacSha256Finish(otCryptoContext *aContext, uint8_t *aBuf, size_t aBufLength)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_mac_operation_t *mMacOperation = (psa_mac_operation_t *)aContext->mContext;
|
|
psa_status_t status;
|
|
|
|
status = sl_sec_man_hmac_finish(mMacOperation, aBuf, aBufLength);
|
|
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
// HKDF platform implementations
|
|
// As the HKDF does not actually use mbedTLS APIs but uses HMAC module, this feature is not implemented.
|
|
otError otPlatCryptoHkdfExpand(otCryptoContext *aContext,
|
|
const uint8_t *aInfo,
|
|
uint16_t aInfoLength,
|
|
uint8_t *aOutputKey,
|
|
uint16_t aOutputKeyLength)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_status_t status;
|
|
|
|
otEXPECT_ACTION(((aContext != NULL) && (aContext->mContext != NULL) && (aInfo != NULL) && (aOutputKey != NULL)),
|
|
error = OT_ERROR_INVALID_ARGS);
|
|
|
|
status = sl_sec_man_key_derivation_expand(aContext->mContext, aInfo, aInfoLength, aOutputKey, aOutputKeyLength);
|
|
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoHkdfExtract(otCryptoContext *aContext,
|
|
const uint8_t *aSalt,
|
|
uint16_t aSaltLength,
|
|
const otCryptoKey *aKey)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_status_t status;
|
|
|
|
otEXPECT_ACTION(
|
|
((aContext != NULL) && (aContext->mContext != NULL) && (aKey != NULL) && (aSalt != NULL) && (aSaltLength != 0)),
|
|
error = OT_ERROR_INVALID_ARGS);
|
|
|
|
status = sl_sec_man_key_derivation_extract(aContext->mContext, PSA_ALG_SHA_256, aKey->mKeyRef, aSalt, aSaltLength);
|
|
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
// SHA256 platform implementations
|
|
otError otPlatCryptoSha256Init(otCryptoContext *aContext)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
otEXPECT_ACTION((aContext != NULL), error = OT_ERROR_INVALID_ARGS);
|
|
psa_hash_operation_t *ctx = (psa_hash_operation_t *)aContext->mContext;
|
|
|
|
otEXPECT_ACTION((ctx != NULL), error = OT_ERROR_INVALID_ARGS);
|
|
|
|
*ctx = sl_sec_man_hash_init();
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoSha256Deinit(otCryptoContext *aContext)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
otEXPECT_ACTION((aContext != NULL), error = OT_ERROR_INVALID_ARGS);
|
|
psa_hash_operation_t *ctx = (psa_hash_operation_t *)aContext->mContext;
|
|
|
|
otEXPECT_ACTION((ctx != NULL), error = OT_ERROR_INVALID_ARGS);
|
|
otEXPECT_ACTION((sl_sec_man_hash_deinit(ctx) == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoSha256Start(otCryptoContext *aContext)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
otEXPECT_ACTION((aContext != NULL), error = OT_ERROR_INVALID_ARGS);
|
|
psa_hash_operation_t *ctx = (psa_hash_operation_t *)aContext->mContext;
|
|
|
|
otEXPECT_ACTION((ctx != NULL), error = OT_ERROR_INVALID_ARGS);
|
|
otEXPECT_ACTION((sl_sec_man_hash_start(ctx, PSA_ALG_SHA_256) == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoSha256Update(otCryptoContext *aContext, const void *aBuf, uint16_t aBufLength)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
otEXPECT_ACTION((aContext != NULL), error = OT_ERROR_INVALID_ARGS);
|
|
psa_hash_operation_t *ctx = (psa_hash_operation_t *)aContext->mContext;
|
|
|
|
otEXPECT_ACTION(((ctx != NULL) && (aBuf != NULL)), error = OT_ERROR_INVALID_ARGS);
|
|
otEXPECT_ACTION((sl_sec_man_hash_update(ctx, (uint8_t *)aBuf, aBufLength) == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoSha256Finish(otCryptoContext *aContext, uint8_t *aHash, uint16_t aHashSize)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
size_t aHashLength = 0;
|
|
otEXPECT_ACTION((aContext != NULL), error = OT_ERROR_INVALID_ARGS);
|
|
psa_hash_operation_t *ctx = (psa_hash_operation_t *)aContext->mContext;
|
|
|
|
otEXPECT_ACTION(((ctx != NULL) && (aHash != NULL)), error = OT_ERROR_INVALID_ARGS);
|
|
otEXPECT_ACTION((sl_sec_man_hash_finish(ctx, aHash, aHashSize, &aHashLength) == PSA_SUCCESS),
|
|
error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoEcdsaGenerateAndImportKey(otCryptoKeyRef aKeyRef)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
size_t aKeyLength = 256;
|
|
psa_status_t status;
|
|
|
|
status = sl_sec_man_generate_key(&aKeyRef,
|
|
PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1),
|
|
PSA_ALG_ECDSA(PSA_ALG_ANY_HASH),
|
|
(PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH),
|
|
PSA_KEY_LIFETIME_PERSISTENT,
|
|
aKeyLength);
|
|
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoEcdsaExportPublicKey(otCryptoKeyRef aKeyRef, otPlatCryptoEcdsaPublicKey *aPublicKey)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
size_t aKeyLength;
|
|
psa_status_t status;
|
|
uint8_t aByteArray[OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE + 1];
|
|
|
|
otEXPECT_ACTION((aPublicKey != NULL), error = OT_ERROR_INVALID_ARGS);
|
|
|
|
// Use byte array to get the public key because PSA adds a encoding header at the beginning of the array.
|
|
// It is easier to export it to a byte array and copy only the public key to output array.
|
|
status = sl_sec_man_export_public_key(aKeyRef, aByteArray, sizeof(aByteArray), &aKeyLength);
|
|
|
|
memcpy(aPublicKey->m8, &aByteArray[1], OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE);
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoEcdsaSignUsingKeyRef(otCryptoKeyRef aKeyRef,
|
|
const otPlatCryptoSha256Hash *aHash,
|
|
otPlatCryptoEcdsaSignature *aSignature)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
size_t aSignatureLength;
|
|
psa_status_t status;
|
|
bool aIsHash = true;
|
|
|
|
otEXPECT_ACTION(((aHash != NULL) && (aSignature != NULL)), error = OT_ERROR_INVALID_ARGS);
|
|
|
|
status = sl_sec_man_sign(aKeyRef,
|
|
PSA_ALG_ECDSA(PSA_ALG_SHA_256),
|
|
aHash->m8,
|
|
sizeof(aHash->m8),
|
|
aSignature->m8,
|
|
sizeof(aSignature->m8),
|
|
&aSignatureLength,
|
|
aIsHash);
|
|
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoEcdsaVerifyUsingKeyRef(otCryptoKeyRef aKeyRef,
|
|
const otPlatCryptoSha256Hash *aHash,
|
|
const otPlatCryptoEcdsaSignature *aSignature)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_status_t status;
|
|
bool aIsHash = true;
|
|
|
|
otEXPECT_ACTION(((aHash != NULL) && (aSignature != NULL)), error = OT_ERROR_INVALID_ARGS);
|
|
|
|
// Verify the signature.
|
|
status = sl_sec_man_verify(aKeyRef,
|
|
PSA_ALG_ECDSA(PSA_ALG_SHA_256),
|
|
aHash->m8,
|
|
sizeof(aHash->m8),
|
|
aSignature->m8,
|
|
sizeof(aSignature->m8),
|
|
aIsHash);
|
|
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
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)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_status_t status;
|
|
size_t outSize;
|
|
psa_key_id_t passwordKeyId = 0;
|
|
psa_key_id_t saltKeyId = 0;
|
|
psa_key_id_t keyId = 0;
|
|
|
|
// Algorithm is PBKDF2-AES-CMAC-PRF-128
|
|
psa_algorithm_t algo = PSA_ALG_PBKDF2_AES_CMAC_PRF_128;
|
|
|
|
// Initialize key derivation
|
|
psa_key_derivation_operation_t operation = psa_key_derivation_operation_init();
|
|
status = psa_key_derivation_setup(&operation, algo);
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
// Set capacity
|
|
status = psa_key_derivation_set_capacity(&operation, aKeyLen);
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
// Set iteration count as cost
|
|
status = psa_key_derivation_input_integer(&operation, PSA_KEY_DERIVATION_INPUT_COST, aIterationCounter);
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
// Create salt as a key
|
|
psa_key_attributes_t saltKeyAttr = psa_key_attributes_init();
|
|
psa_set_key_usage_flags(&saltKeyAttr, PSA_KEY_USAGE_DERIVE);
|
|
psa_set_key_type(&saltKeyAttr, PSA_KEY_TYPE_RAW_DATA);
|
|
psa_set_key_algorithm(&saltKeyAttr, algo);
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
status = psa_import_key(&saltKeyAttr, aSalt, aSaltLen, &saltKeyId);
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
// Provide salt
|
|
status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_SALT, saltKeyId);
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
// Create key for password (key)
|
|
psa_key_attributes_t passwordKeyAttr = psa_key_attributes_init();
|
|
psa_set_key_usage_flags(&passwordKeyAttr, PSA_KEY_USAGE_DERIVE);
|
|
psa_set_key_type(&passwordKeyAttr, PSA_KEY_TYPE_PASSWORD);
|
|
psa_set_key_algorithm(&passwordKeyAttr, algo);
|
|
|
|
status = psa_import_key(&passwordKeyAttr, aPassword, aPasswordLen, &passwordKeyId);
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
// Provide password (key)
|
|
status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, passwordKeyId);
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
// Configure output as a key
|
|
psa_key_attributes_t keyAttrResult = psa_key_attributes_init();
|
|
psa_set_key_bits(&keyAttrResult, (8 * aKeyLen));
|
|
psa_set_key_usage_flags(&keyAttrResult, PSA_KEY_USAGE_EXPORT);
|
|
psa_set_key_type(&keyAttrResult, PSA_KEY_TYPE_RAW_DATA);
|
|
psa_set_key_algorithm(&keyAttrResult, PSA_ALG_CTR);
|
|
|
|
status = psa_key_derivation_output_key(&keyAttrResult, &operation, &keyId);
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
// Export output key
|
|
status = psa_export_key(keyId, aKey, aKeyLen, &outSize);
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
// Release keys used
|
|
psa_destroy_key(keyId);
|
|
psa_destroy_key(saltKeyId);
|
|
psa_destroy_key(passwordKeyId);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
otError otPlatCryptoEcdsaVerify(const otPlatCryptoEcdsaPublicKey *aPublicKey,
|
|
const otPlatCryptoSha256Hash *aHash,
|
|
const otPlatCryptoEcdsaSignature *aSignature)
|
|
{
|
|
otError error = OT_ERROR_NONE;
|
|
psa_status_t status;
|
|
bool aIsHash = true;
|
|
uint8_t aByteArray[OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE + 1];
|
|
otCryptoKeyRef aKeyId;
|
|
|
|
otEXPECT_ACTION(((aPublicKey != NULL) && (aHash != NULL) && (aSignature != NULL)), error = OT_ERROR_INVALID_ARGS);
|
|
|
|
// Public key needs a extra byt of encoding header, which has a value of 0x04, to be included for PSA to validate
|
|
// and process the publc key. Copy the key into a new temp array and append the encoding header to it.
|
|
aByteArray[0] = 0x04;
|
|
memcpy(&aByteArray[1], aPublicKey, OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE);
|
|
|
|
// Import the public key into a temp slot.
|
|
status = sl_sec_man_import_key(&aKeyId,
|
|
PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1),
|
|
PSA_ALG_ECDSA(PSA_ALG_ANY_HASH),
|
|
PSA_KEY_USAGE_VERIFY_HASH,
|
|
PSA_KEY_PERSISTENCE_VOLATILE,
|
|
aByteArray,
|
|
OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE + 1); // To account for the padded byte.
|
|
|
|
// If key import fails, assert, as we cannot proceed
|
|
OT_ASSERT(status == PSA_SUCCESS);
|
|
|
|
// Verify the signature.
|
|
status = sl_sec_man_verify(aKeyId,
|
|
PSA_ALG_ECDSA(PSA_ALG_SHA_256),
|
|
aHash->m8,
|
|
sizeof(aHash->m8),
|
|
aSignature->m8,
|
|
sizeof(aSignature->m8),
|
|
aIsHash);
|
|
|
|
// Destroy the temp key.
|
|
sl_sec_man_destroy_key(aKeyId);
|
|
|
|
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
#endif // OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA
|