PSA Crypto (key derivation) fault on NRF54L15 when called from BLE callbacks

Dear Nordic Team,

I have to use PSA Crypto key derivation in my NRF54L15 firmware during BLE communication with BLE Central, however, I am experiencing a problem when I am trying to call key derivation from any of Bluetooth callbacks - the call to  simply resets the device with USAGE FAULT.  I have tried to wrap it into a worker call, however, it didn't help. 

Here is the test function, which works fine when it is called from the main() loop, however, once I put it into any BLE callback (e.g. characteristic write callback or even connection state callback, it results in immediate fault. I have done some debugging and it seems that the fault occurs/takes place somewhere inside psa_key_derivation_setup(&operation, alg) call. 

void test_psa_key_derivation_setup_impl(void)
{
    LOG_INF("Starting psa_key_derivation_setup test...");

    psa_status_t status;

    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_algorithm_t alg = PSA_ALG_HKDF(PSA_ALG_SHA_256);
    psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;

    // Initialize PSA Crypto if needed

    status = psa_crypto_init();

    if (status != PSA_SUCCESS) {
        LOG_ERR("Failed to initialize PSA crypto for test");
        return;
    }
   
    // Get current auth key
    uint8_t auth_key[AUTH_KEY_SIZE];
    int err = flash_storage_get_auth_key_from_memory(auth_key);
    if (err) {
        LOG_ERR("Failed to get auth key for test: %d", err);
        return;
    }
   
    // Generate random nonces for testing
    uint8_t nonce1[NONCE_SIZE];
    uint8_t nonce2[NONCE_SIZE];
   
    // Use simple pseudo-random generation for testing
    for (int i = 0; i < NONCE_SIZE; i++) {
        nonce1[i] = (uint8_t)(k_uptime_get_32() + i) ^ 0xAA;
        nonce2[i] = (uint8_t)(k_uptime_get_32() + i + 100) ^ 0x55;
    }
   

    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
    psa_set_key_algorithm(&attributes, alg);
    psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE);

   
    psa_reset_key_attributes(&attributes);

    // Now test the actual psa_key_derivation_setup call
    LOG_INF("Calling psa_key_derivation_setup...");
   
    status = psa_key_derivation_setup(&operation, alg);
   
    if (status != PSA_SUCCESS) {
        LOG_ERR("psa_key_derivation_setup FAILED with status: %d", status);
        return;
    } else
    {
        LOG_INF("psa_key_derivation_setup SUCCESS!");
    }
   

        // Combine nonces for salt
       uint8_t salt[NONCE_SIZE + NONCE_SIZE];
       memcpy(salt, nonce1, NONCE_SIZE);
       memcpy(salt + NONCE_SIZE, nonce2, NONCE_SIZE);

       // Set salt
       status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT,
                                        salt, sizeof(salt));

    if (status != PSA_SUCCESS)
    {
       LOG_ERR("PSA HKDF salt input failed");
       psa_key_derivation_abort(&operation);
       return;
    }
 
      // Set secret (auth key)
     status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SECRET,
                                    auth_key, AUTH_KEY_SIZE);


    if (status != PSA_SUCCESS) {
      LOG_ERR("PSA HKDF secret input failed: %d", status);
      psa_key_derivation_abort(&operation);
      return;
    }

 // Set info
 const char *info = "session_key";
 status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_INFO,
                                        (const uint8_t *)info, strlen(info));
 if (status != PSA_SUCCESS)
 {
     LOG_ERR("PSA HKDF info input failed: %d", status);
     psa_key_derivation_abort(&operation);
     return;
 }

 // Derive session key
 uint8_t session_key[SESSION_KEY_SIZE];

 status = psa_key_derivation_output_bytes(&operation, session_key, SESSION_KEY_SIZE);
 
 if (status != PSA_SUCCESS)
 {
     LOG_ERR("PSA HKDF output failed: %d", status);
     psa_key_derivation_abort(&operation);
     return;
 }

 
    LOG_INF("psa_key_derivation_setup test completed");

    LOG_INF("Session key: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
            session_key[0], session_key[1], session_key[2], session_key[3], session_key[4], session_key[5], session_key[6], session_key[7],
            session_key[8], session_key[9], session_key[10], session_key[11], session_key[12], session_key[13], session_key[14], session_key[15]);

    psa_key_derivation_abort(&operation);    
}
My K Configuration is as following:
CONFIG_NRF_SECURITY=y
CONFIG_PSA_CRYPTO_DRIVER_CRACEN=y
CONFIG_MBEDTLS_PSA_CRYPTO_C=y

CONFIG_PSA_WANT_ALG_CCM=y
CONFIG_PSA_WANT_ALG_HKDF=y
CONFIG_PSA_WANT_ALG_SHA_256=y
CONFIG_PSA_WANT_ALG_HMAC=y
CONFIG_PSA_WANT_KEY_TYPE_AES=y
CONFIG_PSA_WANT_KEY_TYPE_RAW_DATA=y
Please help! Thanks in advance.
Parents
  • Hi Alex, 

    You are right that the PSA API is supposed to run in thread context, not in event handler context. But it's quite strange that even with a worker call you still see the problem. 
    Could you try to do a test to first start the work in main() then try to start the same work in the BLE event handler. 

    Please send us the log when you see the assert. 
    And please send us the sample that does the test above so we can test here. 

Reply
  • Hi Alex, 

    You are right that the PSA API is supposed to run in thread context, not in event handler context. But it's quite strange that even with a worker call you still see the problem. 
    Could you try to do a test to first start the work in main() then try to start the same work in the BLE event handler. 

    Please send us the log when you see the assert. 
    And please send us the sample that does the test above so we can test here. 

Children
Related