Hi Nordic Team,
in our project we want to write/read cryptographic keys to/from the KMU.
One of the algorithms we are going to use is ECDSA.
My naive approach was to just modify the existing nrf/samples/crypto/ecdsa code.
Another ticket in the developer zone (see https://devzone.nordicsemi.com/f/nordic-q-a/118434/kmu-psa-persistent-key-generation) reveals, that there's a bug in SDK v2.9.0.
Therefore, I switched ncs to the main branch (commit a95e127c906afef92e36e79120d2ec127c250b87).
My prj.conf equals:
# # Copyright (c) 2024 Nordic Semiconductor ASA # # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause # # The Zephyr CMSIS emulation assumes that ticks are ms, currently CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 CONFIG_MAIN_STACK_SIZE=4096 CONFIG_HEAP_MEM_POOL_SIZE=4096 CONFIG_REBOOT=y # Enable logging CONFIG_CONSOLE=y CONFIG_LOG=y # Enable nordic security backend and PSA APIs CONFIG_NRF_SECURITY=y CONFIG_MBEDTLS_PSA_CRYPTO_C=y # Enable persistent storage APIs CONFIG_MBEDTLS_PSA_CRYPTO_STORAGE_C=y # Mbedtls configuration CONFIG_MBEDTLS_ENABLE_HEAP=y CONFIG_MBEDTLS_HEAP_SIZE=8192 # Using hardware crypto accelerator CONFIG_PSA_CRYPTO_DRIVER_OBERON=n CONFIG_PSA_CRYPTO_DRIVER_CRACEN=y CONFIG_PSA_WANT_GENERATE_RANDOM=y # ECDSA support CONFIG_PSA_WANT_ALG_ECDSA=y CONFIG_PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE=y CONFIG_PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT=y CONFIG_PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT=y CONFIG_PSA_WANT_ECC_SECP_R1_256=y CONFIG_PSA_WANT_ALG_SHA_256=y # Use TRUSTED_STORAGE because this is a non-TF-M board target. CONFIG_TRUSTED_STORAGE=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y CONFIG_ZMS=y CONFIG_SETTINGS=y CONFIG_DEBUG=y
My modified generate_ecdsa_keypair() succeeds to generate a new keypair in the KMU resp. read an existing keypair from the KMU:
int generate_ecdsa_keypair(void) { psa_status_t status; size_t olen; LOG_INF("Generating/read random persistent ECDSA key pair..."); /* Configure the key attributes */ psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE); psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)); psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); psa_set_key_bits(&key_attributes, 256); psa_set_key_lifetime( &key_attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( PSA_KEY_PERSISTENCE_DEFAULT, PSA_KEY_LOCATION_CRACEN_KMU ) ); psa_set_key_id( &key_attributes, PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT( CRACEN_KMU_KEY_USAGE_SCHEME_RAW, 8 ) ); status = psa_generate_key(&key_attributes, &ecdsa_keypair_id); if(status == PSA_SUCCESS) { // nothing to do } else if(status == PSA_ERROR_ALREADY_EXISTS) { LOG_INF("ECDSA keypair already exists!"); ecdsa_keypair_id = PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, 8); } else { LOG_INF("psa_generate_key failed! (Error: %d)", status); return APP_ERROR; } /* Export the public ECDSA key */ status = psa_export_public_key(ecdsa_keypair_id, m_ecdsa_pub_key, sizeof(m_ecdsa_pub_key), &olen); if(status != PSA_SUCCESS) { LOG_INF("failed to export ECDSA public key (Error: %d)", status); return APP_ERROR; } PRINT_HEX("ECDSA pub key", m_ecdsa_pub_key, sizeof(m_ecdsa_pub_key)); /* After the key handle is acquired the attributes are not needed */ psa_reset_key_attributes(&key_attributes); LOG_INF("ECDSA keypair generated/read successfully!"); return APP_SUCCESS; }
But my modified import_ecdsa_pub_key() function fails:
int import_ecdsa_pub_key(void) { /* Configure the key attributes */ psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_status_t status; /* Configure the key attributes */ psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE); psa_set_key_lifetime( &key_attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( PSA_KEY_PERSISTENCE_DEFAULT, PSA_KEY_LOCATION_CRACEN_KMU ) ); psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(PSA_ALG_ANY_HASH)); psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); psa_set_key_bits(&key_attributes, 256); psa_set_key_id( &key_attributes, PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT( CRACEN_KMU_KEY_USAGE_SCHEME_RAW, 8 ) ); status = psa_import_key(&key_attributes, m_ecdsa_pub_key, sizeof(m_ecdsa_pub_key), &ecdsa_pub_key_id); if (status != PSA_SUCCESS) { LOG_INF("psa_import_key failed! (Error: %d)", status); return APP_ERROR; } /* Reset key attributes and free any allocated resources. */ psa_reset_key_attributes(&key_attributes); return APP_SUCCESS; }
psa_import_key() returns PSA_ERROR_INVALID_ARGUMENT.
The error code comes from nrf/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/kmu.c:837ff
case CRACEN_KMU_KEY_USAGE_SCHEME_RAW: push_address = (uint8_t *)kmu_push_area; if (key_buffer_size != 16 && key_buffer_size != 24 && key_buffer_size != 32) { return PSA_ERROR_INVALID_ARGUMENT; } break;
The buffer size for the ECDSA public key (i.e. m_ecdsa_pub_key) is 65 bytes.
Am I doing something wrong?
Best regards,
Christian