Stack Crash when used psa_ps_set (not */ns build) to store a certificate

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:

  1. https://docs.nordicsemi.com/bundle/ncs-2.9.1/page/nrf/app_dev/device_guides/nrf54l/cryptography.html#ug-nrf54l-crypto-configuration
  2. 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
    1. The above one is good one, and it would help more if there would be sample application. The one provided is not easy one.
  3. Sample example: Hardware Unique Key, psa related etc.
  4. 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);
}

  1. The purpose is to store X509 certificates securely. Is there  a better method and an sample solution available.
  2. 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.
Related