/* * 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 #include #include #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 #include #include #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