|  | /* | 
|  | * Copyright (c) 2021 Nordic Semiconductor ASA | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #include <openthread/platform/crypto.h> | 
|  |  | 
|  | #include <psa/crypto.h> | 
|  |  | 
|  | #include <zephyr/sys/__assert.h> | 
|  |  | 
|  | #if !defined(CONFIG_BUILD_WITH_TFM) && defined(CONFIG_OPENTHREAD_CRYPTO_PSA) | 
|  | #include <zephyr/settings/settings.h> | 
|  | #endif | 
|  |  | 
|  | #if defined(CONFIG_OPENTHREAD_ECDSA) | 
|  | #include <string.h> | 
|  | #include <mbedtls/asn1.h> | 
|  | #endif | 
|  |  | 
|  | static otError psaToOtError(psa_status_t aStatus) | 
|  | { | 
|  | switch (aStatus) { | 
|  | case PSA_SUCCESS: | 
|  | return OT_ERROR_NONE; | 
|  | case PSA_ERROR_INVALID_ARGUMENT: | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | case PSA_ERROR_BUFFER_TOO_SMALL: | 
|  | return OT_ERROR_NO_BUFS; | 
|  | default: | 
|  | return OT_ERROR_FAILED; | 
|  | } | 
|  | } | 
|  |  | 
|  | 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); | 
|  | 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); | 
|  | default: | 
|  | /* | 
|  | * There is currently no constant like PSA_ALG_NONE, but 0 is used | 
|  | * to indicate an unknown algorithm. | 
|  | */ | 
|  | return (psa_algorithm_t)0; | 
|  | } | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | return usage; | 
|  | } | 
|  |  | 
|  | static bool checkKeyUsage(int aUsage) | 
|  | { | 
|  | /* Check if only supported flags have been passed */ | 
|  | int supported_flags = 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; | 
|  |  | 
|  | return (aUsage & ~supported_flags) == 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 != NULL && aContext->mContext != NULL && aContext->mContextSize >= aMinSize; | 
|  | } | 
|  |  | 
|  | void otPlatCryptoInit(void) | 
|  | { | 
|  | psa_crypto_init(); | 
|  |  | 
|  | #if !defined(CONFIG_BUILD_WITH_TFM) && defined(CONFIG_OPENTHREAD_CRYPTO_PSA) | 
|  | /* | 
|  | * In OpenThread, Settings are initialized after KeyManager by default. If device uses | 
|  | * PSA with emulated TFM, Settings have to be initialized at the end of otPlatCryptoInit(), | 
|  | * to be available before storing Network Key. | 
|  | */ | 
|  | __ASSERT_EVAL((void)settings_subsys_init(), int err = settings_subsys_init(), !err, | 
|  | "Failed to initialize settings"); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, otCryptoKeyType aKeyType, | 
|  | otCryptoKeyAlgorithm aKeyAlgorithm, int aKeyUsage, | 
|  | otCryptoKeyStorage aKeyPersistence, const uint8_t *aKey, | 
|  | size_t aKeyLen) | 
|  | { | 
|  | #if defined(CONFIG_OPENTHREAD_ECDSA) | 
|  | int version; | 
|  | size_t len; | 
|  | unsigned char *p = (unsigned char *)aKey; | 
|  | unsigned char *end; | 
|  | #endif | 
|  |  | 
|  | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; | 
|  | psa_status_t status = 0; | 
|  |  | 
|  | if (aKeyRef == NULL || aKey == NULL || !checkKeyUsage(aKeyUsage)) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | #if defined(CONFIG_OPENTHREAD_ECDSA) | 
|  | /* Check if key is ECDSA pair and extract private key from it since PSA expects it. */ | 
|  | if (aKeyType == OT_CRYPTO_KEY_TYPE_ECDSA) { | 
|  |  | 
|  | end = p + aKeyLen; | 
|  | status = mbedtls_asn1_get_tag(&p, end, &len, | 
|  | MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); | 
|  | if (status != 0) { | 
|  | return OT_ERROR_FAILED; | 
|  | } | 
|  |  | 
|  | end = p + len; | 
|  | status = mbedtls_asn1_get_int(&p, end, &version); | 
|  | if (status != 0) { | 
|  | return OT_ERROR_FAILED; | 
|  | } | 
|  |  | 
|  | status = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); | 
|  | if (status != 0 || len != 32) { | 
|  | return OT_ERROR_FAILED; | 
|  | } | 
|  |  | 
|  | aKey = p; | 
|  | aKeyLen = len; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | status = psa_import_key(&attributes, aKey, aKeyLen, aKeyRef); | 
|  | psa_reset_key_attributes(&attributes); | 
|  |  | 
|  | return psaToOtError(status); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, uint8_t *aBuffer, size_t aBufferLen, | 
|  | size_t *aKeyLen) | 
|  | { | 
|  | if (aBuffer == NULL) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | return psaToOtError(psa_export_key(aKeyRef, aBuffer, aBufferLen, aKeyLen)); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoDestroyKey(otCryptoKeyRef aKeyRef) | 
|  | { | 
|  | return psaToOtError(psa_destroy_key(aKeyRef)); | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoHmacSha256Init(otCryptoContext *aContext) | 
|  | { | 
|  | psa_mac_operation_t *operation; | 
|  |  | 
|  | if (!checkContext(aContext, sizeof(psa_mac_operation_t))) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | operation = aContext->mContext; | 
|  | memset(operation, 0, sizeof(*operation)); | 
|  |  | 
|  | return OT_ERROR_NONE; | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoHmacSha256Deinit(otCryptoContext *aContext) | 
|  | { | 
|  | psa_mac_operation_t *operation; | 
|  |  | 
|  | if (!checkContext(aContext, sizeof(psa_mac_operation_t))) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | operation = aContext->mContext; | 
|  |  | 
|  | return psaToOtError(psa_mac_abort(operation)); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoHmacSha256Start(otCryptoContext *aContext, const otCryptoKey *aKey) | 
|  | { | 
|  | psa_mac_operation_t *operation; | 
|  | psa_status_t status; | 
|  |  | 
|  | if (aKey == NULL || !checkContext(aContext, sizeof(psa_mac_operation_t))) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | operation = aContext->mContext; | 
|  | status = psa_mac_sign_setup(operation, aKey->mKeyRef, PSA_ALG_HMAC(PSA_ALG_SHA_256)); | 
|  |  | 
|  | return psaToOtError(status); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, const void *aBuf, | 
|  | uint16_t aBufLength) | 
|  | { | 
|  | psa_mac_operation_t *operation; | 
|  |  | 
|  | if (aBuf == NULL || !checkContext(aContext, sizeof(psa_mac_operation_t))) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | operation = aContext->mContext; | 
|  |  | 
|  | return psaToOtError(psa_mac_update(operation, (const uint8_t *)aBuf, aBufLength)); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoHmacSha256Finish(otCryptoContext *aContext, uint8_t *aBuf, size_t aBufLength) | 
|  | { | 
|  | psa_mac_operation_t *operation; | 
|  | size_t mac_length; | 
|  |  | 
|  | if (aBuf == NULL || !checkContext(aContext, sizeof(psa_mac_operation_t))) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | operation = aContext->mContext; | 
|  |  | 
|  | return psaToOtError(psa_mac_sign_finish(operation, aBuf, aBufLength, &mac_length)); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoAesInit(otCryptoContext *aContext) | 
|  | { | 
|  | psa_key_id_t *key_ref; | 
|  |  | 
|  | if (!checkContext(aContext, sizeof(psa_key_id_t))) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | key_ref = aContext->mContext; | 
|  | *key_ref = (psa_key_id_t)0; /* In TF-M 1.5.0 this can be replaced with PSA_KEY_ID_NULL */ | 
|  |  | 
|  | return OT_ERROR_NONE; | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoAesSetKey(otCryptoContext *aContext, const otCryptoKey *aKey) | 
|  | { | 
|  | psa_key_id_t *key_ref; | 
|  |  | 
|  | if (aKey == NULL || !checkContext(aContext, sizeof(psa_key_id_t))) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | key_ref = aContext->mContext; | 
|  | *key_ref = aKey->mKeyRef; | 
|  |  | 
|  | return OT_ERROR_NONE; | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, uint8_t *aOutput) | 
|  | { | 
|  | const size_t block_size = PSA_BLOCK_CIPHER_BLOCK_LENGTH(PSA_KEY_TYPE_AES); | 
|  | psa_status_t status = PSA_SUCCESS; | 
|  | psa_key_id_t *key_ref; | 
|  | size_t cipher_length; | 
|  |  | 
|  | if (aInput == NULL || aOutput == NULL || !checkContext(aContext, sizeof(psa_key_id_t))) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | key_ref = aContext->mContext; | 
|  | status = psa_cipher_encrypt(*key_ref, PSA_ALG_ECB_NO_PADDING, aInput, block_size, aOutput, | 
|  | block_size, &cipher_length); | 
|  |  | 
|  | return psaToOtError(status); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoAesFree(otCryptoContext *aContext) | 
|  | { | 
|  | return OT_ERROR_NONE; | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoSha256Init(otCryptoContext *aContext) | 
|  | { | 
|  | psa_hash_operation_t *operation; | 
|  |  | 
|  | if (!checkContext(aContext, sizeof(psa_hash_operation_t))) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | operation = aContext->mContext; | 
|  | memset(operation, 0, sizeof(*operation)); | 
|  |  | 
|  | return OT_ERROR_NONE; | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoSha256Deinit(otCryptoContext *aContext) | 
|  | { | 
|  | psa_hash_operation_t *operation; | 
|  |  | 
|  | if (!checkContext(aContext, sizeof(psa_hash_operation_t))) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | operation = aContext->mContext; | 
|  |  | 
|  | return psaToOtError(psa_hash_abort(operation)); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoSha256Start(otCryptoContext *aContext) | 
|  | { | 
|  | psa_hash_operation_t *operation; | 
|  |  | 
|  | if (!checkContext(aContext, sizeof(psa_hash_operation_t))) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | operation = aContext->mContext; | 
|  |  | 
|  | return psaToOtError(psa_hash_setup(operation, PSA_ALG_SHA_256)); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoSha256Update(otCryptoContext *aContext, const void *aBuf, uint16_t aBufLength) | 
|  | { | 
|  | psa_hash_operation_t *operation; | 
|  |  | 
|  | if (aBuf == NULL || !checkContext(aContext, sizeof(psa_hash_operation_t))) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | operation = aContext->mContext; | 
|  |  | 
|  | return psaToOtError(psa_hash_update(operation, (const uint8_t *)aBuf, aBufLength)); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoSha256Finish(otCryptoContext *aContext, uint8_t *aHash, uint16_t aHashSize) | 
|  | { | 
|  | psa_hash_operation_t *operation; | 
|  | size_t hash_size; | 
|  |  | 
|  | if (aHash == NULL || !checkContext(aContext, sizeof(psa_hash_operation_t))) { | 
|  | return OT_ERROR_INVALID_ARGS; | 
|  | } | 
|  |  | 
|  | operation = aContext->mContext; | 
|  |  | 
|  | return psaToOtError(psa_hash_finish(operation, aHash, aHashSize, &hash_size)); | 
|  | } | 
|  |  | 
|  | void otPlatCryptoRandomInit(void) | 
|  | { | 
|  | psa_crypto_init(); | 
|  | } | 
|  |  | 
|  | void otPlatCryptoRandomDeinit(void) | 
|  | { | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoRandomGet(uint8_t *aBuffer, uint16_t aSize) | 
|  | { | 
|  | return psaToOtError(psa_generate_random(aBuffer, aSize)); | 
|  | } | 
|  |  | 
|  | #if defined(CONFIG_OPENTHREAD_ECDSA) | 
|  |  | 
|  | otError otPlatCryptoEcdsaGenerateKey(otPlatCryptoEcdsaKeyPair *aKeyPair) | 
|  | { | 
|  | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; | 
|  | psa_key_id_t key_id = 0; | 
|  | psa_status_t status; | 
|  | size_t exported_length; | 
|  |  | 
|  | psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_EXPORT); | 
|  | 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_bits(&attributes, 256); | 
|  |  | 
|  | status = psa_generate_key(&attributes, &key_id); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | status = psa_export_key(key_id, aKeyPair->mDerBytes, OT_CRYPTO_ECDSA_MAX_DER_SIZE, | 
|  | &exported_length); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  | aKeyPair->mDerLength = exported_length; | 
|  |  | 
|  | out: | 
|  | psa_reset_key_attributes(&attributes); | 
|  | psa_destroy_key(key_id); | 
|  |  | 
|  | return psaToOtError(status); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoEcdsaSign(const otPlatCryptoEcdsaKeyPair *aKeyPair, | 
|  | const otPlatCryptoSha256Hash *aHash, | 
|  | otPlatCryptoEcdsaSignature *aSignature) | 
|  | { | 
|  | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; | 
|  | psa_key_id_t key_id; | 
|  | psa_status_t status; | 
|  | size_t signature_length; | 
|  |  | 
|  | psa_set_key_usage_flags(&attributes, 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_bits(&attributes, 256); | 
|  |  | 
|  | status = psa_import_key(&attributes, aKeyPair->mDerBytes, aKeyPair->mDerLength, &key_id); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | status = psa_sign_hash(key_id, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), aHash->m8, | 
|  | OT_CRYPTO_SHA256_HASH_SIZE, aSignature->m8, | 
|  | OT_CRYPTO_ECDSA_SIGNATURE_SIZE, &signature_length); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | out: | 
|  | psa_reset_key_attributes(&attributes); | 
|  | psa_destroy_key(key_id); | 
|  |  | 
|  | return psaToOtError(status); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoEcdsaVerify(const otPlatCryptoEcdsaPublicKey *aPublicKey, | 
|  | const otPlatCryptoSha256Hash *aHash, | 
|  | const otPlatCryptoEcdsaSignature *aSignature) | 
|  | { | 
|  | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; | 
|  | psa_key_id_t key_id; | 
|  | 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), &key_id); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | status = psa_verify_hash(key_id, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), aHash->m8, | 
|  | OT_CRYPTO_SHA256_HASH_SIZE, aSignature->m8, | 
|  | OT_CRYPTO_ECDSA_SIGNATURE_SIZE); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | out: | 
|  | psa_reset_key_attributes(&attributes); | 
|  | psa_destroy_key(key_id); | 
|  |  | 
|  | return psaToOtError(status); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoEcdsaSignUsingKeyRef(otCryptoKeyRef aKeyRef, | 
|  | const otPlatCryptoSha256Hash *aHash, | 
|  | otPlatCryptoEcdsaSignature *aSignature) | 
|  | { | 
|  | psa_status_t status; | 
|  | size_t signature_length; | 
|  |  | 
|  | 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, &signature_length); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | __ASSERT_NO_MSG(signature_length == OT_CRYPTO_ECDSA_SIGNATURE_SIZE); | 
|  | out: | 
|  | return psaToOtError(status); | 
|  | } | 
|  |  | 
|  | 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); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | out: | 
|  | return psaToOtError(status); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoEcdsaExportPublicKey(otCryptoKeyRef aKeyRef, | 
|  | otPlatCryptoEcdsaPublicKey *aPublicKey) | 
|  | { | 
|  | psa_status_t status; | 
|  | size_t exported_length; | 
|  | uint8_t buffer[1 + OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE]; | 
|  |  | 
|  | status = psa_export_public_key(aKeyRef, buffer, sizeof(buffer), &exported_length); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | __ASSERT_NO_MSG(exported_length == sizeof(buffer)); | 
|  | memcpy(aPublicKey->m8, buffer + 1, OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE); | 
|  |  | 
|  | out: | 
|  | return psaToOtError(status); | 
|  | } | 
|  |  | 
|  | otError otPlatCryptoEcdsaGenerateAndImportKey(otCryptoKeyRef aKeyRef) | 
|  | { | 
|  | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; | 
|  | psa_status_t status; | 
|  | psa_key_id_t key_id = (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, key_id); | 
|  | psa_set_key_bits(&attributes, 256); | 
|  |  | 
|  | status = psa_generate_key(&attributes, &key_id); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | out: | 
|  | psa_reset_key_attributes(&attributes); | 
|  |  | 
|  | return psaToOtError(status); | 
|  | } | 
|  |  | 
|  | 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); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | status = psa_key_derivation_setup(&operation, algorithm); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | status = psa_key_derivation_input_integer(&operation, PSA_KEY_DERIVATION_INPUT_COST, | 
|  | aIterationCounter); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT, | 
|  | aSalt, aSaltLen); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, | 
|  | key_id); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | status = psa_key_derivation_output_bytes(&operation, aKey, aKeyLen); | 
|  | if (status != PSA_SUCCESS) { | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | out: | 
|  | psa_reset_key_attributes(&attributes); | 
|  | psa_key_derivation_abort(&operation); | 
|  | psa_destroy_key(key_id); | 
|  |  | 
|  | __ASSERT_NO_MSG(status == PSA_SUCCESS); | 
|  | return psaToOtError(status); | 
|  | } | 
|  |  | 
|  | #endif /* #if CONFIG_OPENTHREAD_ECDSA */ |