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.