Product: nRF54L15, SDK: V2.9.0
Application: Matter + BLE multi-protocol
Hi,
we want to store X509 certificates in secure storage. I went went through Nordic supplied materials, Dev Zone and tried an implementation without success.
Material went through:
- https://docs.nordicsemi.com/bundle/ncs-2.9.1/page/nrf/app_dev/device_guides/nrf54l/cryptography.html#ug-nrf54l-crypto-configuration
- https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/persistent-storage-of-keys-and-data-using-the-nrf-connect-sdk?utm_source=chatgpt.com
- The above one is good one, and it would help more if there would be sample application. The one provided is not easy one.
- Sample example: Hardware Unique Key, psa related etc.
- Nordic Dev Zone past tickets but can not find much help.
psa_ps_set() fails for PSA protected storage without TF-M
I added the below code in the matter + BLE application which was based on Nordic's Matter door lock example. I started with certificates initially, the stack crash occurred and then switch to the below simple example, which apparently someone else also tried.
psa_status_t status;
status = psa_crypto_init();
if (status != PSA_SUCCESS)
{
printk("Issue with initializing crypto engine\n");
}
else
{
printk(" Crypto Initialized \n");
}
MtiCryptoKeysInit(); // see the code below attachement. This one generates HUK and MEKE
int rc = settings_subsys_init(); // added this based on a previous Nordic ticket, I don't think it is needed. Matter enables this by default
if (rc) {
printk("settings subsys initialization: fail (err %d)\n", rc);
}
uint32_t flags = psa_ps_get_support(); // this works
mti_debug_printk("psa_ps_get_support: %x (%d) - %x", flags, flags, PSA_STORAGE_SUPPORT_SET_EXTENDED);
status = psa_ps_set(1, sizeof("HELLO"), "HELLO", PSA_STORAGE_FLAG_NONE);
if (status != PSA_SUCCESS) {
printk("Failed to store data! (%d)\n", status);
}
else printk("SUccess in storing Helllo --->");
-----
Debug output:
psa_ps_get_support: 0 (0) - 1Store CA cert: uid=1 size=6 ->uid=1 p_data_state=0 data_length=6 ->trusted back end step 2 -> step 3 -> step 4 -> step 5in trusted storage_get Key - before hw unique key dervive key --> in HW uniqueKey: S1 -> in HW uniqueKey: S2 -> in HW uniqueKey: S3 -> in HW uniqueKey: S4 -> in HW uniqueKey: S5 -> in HW uniqueKey: S6 -> in HW uniqueKey: S7op=0 length=32 ->In T0: State=67 ->In T1 ->In S7:T2 ->In S7:T3, State=67 ->In S7:T31 ->In S7:T32 ->In S7:T32 state=6800->E: ***** USAGE FAULT *****
E: Stack overflow (context area not valid)
E: r0/a1: 0xaaaaaaaa r1/a2: 0xaaaaaaaa r2/a3: 0xaaaaaaaa
E: r3/a4: 0xaaaaaaaa r12/ip: 0x00042f78 r14/lr: 0x69000200
E: xpsr: 0x2002fa00
E: Faulting instruction address (r15/pc): 0xaaaaaaaa
E: >>> ZEPHYR FATAL ERROR 2: Stack overflow on CPU 0
E: Current thread: 0x20012bf0 (main)
E: Halting system
I traced the code and found that the stack crash occurs when cracen_key_derivation_cmac_ctr_generate_K_0(operation) is called from /opt/nordic/ncs/v2.9.0/nrf/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_derivation.c, line no 1134. I have added the printk's and I see the printk("In S7:T32 state=%d->",operation->state * 100) getting printed. I have another printk and it does not get executed.
printk("In S7:T3, State=%d ->", operation->state);
if (IS_ENABLED(PSA_NEED_CRACEN_SP800_108_COUNTER_CMAC) &&
(operation->alg == PSA_ALG_SP800_108_COUNTER_CMAC)) {
if (operation->state == CRACEN_KD_STATE_CMAC_CTR_KEY_LOADED ||
operation->state == CRACEN_KD_STATE_CMAC_CTR_INPUT_LABEL ||
operation->state == CRACEN_KD_STATE_CMAC_CTR_INPUT_CONTEXT ||
operation->state == CRACEN_KD_STATE_CMAC_CTR_OUTPUT) { printk("In S7:T31 ->");
if (operation->state != CRACEN_KD_STATE_CMAC_CTR_OUTPUT) { printk("In S7:T32 ->");
operation->state = CRACEN_KD_STATE_CMAC_CTR_OUTPUT; printk("In S7:T32 state=%d->",operation->state * 100);
psa_status_t status =
cracen_key_derivation_cmac_ctr_generate_K_0(operation);
if (status != PSA_SUCCESS) {
return status;
}
} printk("In S7:T33 ->");
The prj.conf settings are:
CONFIG_NCS_SAMPLE_MATTER_PERSISTENT_STORAGE=y CONFIG_NCS_SAMPLE_MATTER_SETTINGS_STORAGE_BACKEND=y CONFIG_NCS_SAMPLE_MATTER_SECURE_STORAGE_BACKEND=y CONFIG_TRUSTED_STORAGE_BACKEND_AEAD_MAX_DATA_SIZE=2048 CONFIG_SETTINGS=y CONFIG_ZMS=y CONFIG_NVS=n CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y CONFIG_NRF_SECURITY=y CONFIG_PSA_CRYPTO_DRIVER_CRACEN=y CONFIG_PSA_CRYPTO_DRIVER_OBERON=n CONFIG_MBEDTLS_PSA_CRYPTO_C=y
I have also added the code to generate HUK and MKEK - below is the code. The below functions calls the same function and completes successfully.
psa_status_t derive_key()
{
uint8_t key_out[PSA_BITS_TO_BYTES(256)];
psa_key_id_t key_id;
static psa_key_id_t key_id_out;
#define ENCRYPT_ALG PSA_ALG_GCM
psa_status_t status;
int err;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
uint8_t key_label[] = "HUK derivation sample label";
LOG_INF("Generating MKEK key");
/* Set the key attributes for the storage key */
psa_set_key_usage_flags(&attributes,
(PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT));
psa_set_key_algorithm(&attributes, ENCRYPT_ALG);
psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
psa_set_key_bits(&attributes, 256);
key_id_out = PSA_KEY_ID_NULL;
printk("\n Generating MKEK ------->");
err = hw_unique_key_derive_key(KEYSLOT, NULL, 0,
key_label, sizeof(key_label),
key_out, sizeof(key_out));
if (err != HW_UNIQUE_KEY_SUCCESS) {
LOG_INF("hw_unique_key_derive_key returned error: %d", err);
return PSA_ERROR_HARDWARE_FAILURE;
}
else printk("Success in MKEK gen ");
PRINT_HEX("Key", key_out, sizeof(key_out));
status = psa_import_key(&attributes, key_out, sizeof(key_out), &key_id);
if (status != PSA_SUCCESS) {
LOG_INF("psa_import_key returned error: %d", status);
return status;
}
else printk("Imported the key \n");
key_id_out = key_id;
return PSA_SUCCESS;
}
bool MtiCryptoKeysInit()
{
psa_status_t status;
mti_debug_printk("Storing Hardware Unique Keys --> Starting");
#if !defined(CONFIG_BUILD_WITH_TFM)
int result;
#if defined(HUK_HAS_CC310) || defined(HUK_HAS_CC312)
result = nrf_cc3xx_platform_init();
if (result != NRF_CC3XX_PLATFORM_SUCCESS)
{
LOG_INF("nrf_cc3xx_platform_init returned error: %d", result);
return APP_ERROR;
}
#endif
if (!hw_unique_key_are_any_written())
{
mti_debug_printk("No pre-existing HUK: Writing random keys to KMU");
result = hw_unique_key_write_random();
if (result != HW_UNIQUE_KEY_SUCCESS)
{
mti_debug_printk("hw_unique_key_write_random returned error: %d", result);
return (false);
}
#if !defined(HUK_HAS_KMU)
/* Reboot to allow the bootloader to load the key into CryptoCell. */
sys_reboot(0);
#endif /* !defined(HUK_HAS_KMU) */
}
#endif /* !defined(CONFIG_BUILD_WITH_TFM) */
mti_debug_printk("Success (result=%d) in storing HUK!", result);
derive_key();
return (true);
}
- The purpose is to store X509 certificates securely. Is there a better method and an sample solution available.
- If what I am pursuing is the correct method, then please advise a solution to overcome the stack crash. I feel that I am missing something, since the same functions are used/working when I try to derive a key based on HUK.