Provisioning PSK at Manufacturing

Hi,

I'm working on provisioning a Pre-Shared Key (PSK) during manufacturing for an nRF5340 device. The device needs access to the PSK at runtime to generate authentication tokens with various nonces.

Setup:

  • Device: nRF5340
  • SDK: nRF Connect SDK v2.5.3
  • Architecture: TF-M with secure/non-secure partitions
  • Programming method: nrfjprog via JTAG during manufacturing


I've been exploring the Key Management Unit (KMU) as a potential solution. I can successfully write to the KMU destination and configuration registers, but encounter firmware crashes when attempting to read from the KMU location following the documentation guidelines

I am on nRF SDK v2.5.3 which blocks _ns application reading from the UICR as default, do I need to add the ranges as suggested for reading UICR OTP in this post RE: Programming and reading OTP ?


Even if this way works I feel its not an optimal solution as we're moving the key from secure storage to the application. Is there another way this functionality can be achieved?

Is there a recommended secure method for provisioning and accessing PSKs at manufacturing time with TF-M?

Thanks,

Parents
  • Hello,

    For NCS v2.5.3, the secure and recommended method is to use the TF-M provisioning image to inject PSKs and other secrets into secure storage at manufacturing time, disable dummy provisioning, and use the PSA Crypto API for all key access. This ensures that PSKs are never exposed outside the secure environment and are protected throughout the device lifecycle. This should set the HUK properly.

    If you need step-by-step details, refer to the TF-M provisioning documentation and the TF-M: Provisioning image sample.

    Kind regards,
    Andreas

  • Hi Andreas,

    I did look at HUK but thought it was unsuitable for our functionality - the PSK needs to fed into the device from an external PC (via Jlink) and also saved in our cloud for future device verification. 

    Are we able to write directly to the KMU from the PC and read in application code?

    I've tried adapting the persistent key usage sample to "open" an existing key instead of generating new and writing the key using memwr commands in nrfjprog but psa_open_key fails.

    Thanks,

  • Hi Benjamin, 

    The only supportable way to factory-provision per-device PSKs on nRF53 + TF-M is to use the TF-M provisioning image (psa_import_key over a secure channel) and then access them at runtime via the PSA Crypto API. All other hacks/workarounds like UICR, raw KMU writes from NS are either blocked by the MPU or leave you without a PSA handle. If you truely must use the KMU directly (which we do not recommend) then you still need a secure shim that calls psa_set_key_policy() and psa_import_key into that slot. Bypassing the TF-M provisioning image just moves the complexity into your own secure code.

  • Hi Susheel,

    Thanks for your reply. 

    If I understand correctly you're saying to implement something like provisioning image example  and use a secure channel e.g UART connected to PC to receive the keys and then store the keys using the PSA crypto library. This provisioning image would be flashed before my application binary at manufacturing. 

    Won't the KMU be overwritten when I flash the application binary after the TF-M provisioning image?

    When calling psa_import_key, is the key stored in persistent storage?

  • I am not an expert in this but think of your device’s KMU slots like a locked safe that you load up during manufacturing. When you run the TF-M provisioning image, it puts your Pre-Shared Key into that safe, and as long as you only flash your application code afterward without doing a full chip erase, everything inside the safe stays right where it belongs. Means, you can update your app as often as you like and the KMU will still hold your key properly.

    Behind the scenes, TF-M’s psa_import_key() call doesn’t just scribble your key onto flash; it tucks it away in Internal Trusted Storage (ITS) and then scrambles it with a Master Key Encryption Key (MKEK) that lives in the KMU. From your application’s point of view, it simply asks “Hey TF-M, give me handle #42” using psa_open_key(), and TF-M hands back a ticket to use the key without ever exposing your raw secret to the non-secure world. You get persistence across resets and firmware updates, plus hardware-backed confidentiality, all in one neat package.

    So at manufacturing you flash the provisioning image, feed it your PSK over UART or J-Link, let it import and encrypt your key behind TF-M, and then switch over to your regular firmware. From there on out, your app just opens the key handle whenever it needs to generate tokens or signatures—no MPU hacks, no UICR gymnastics, and no chance of accidentally wiping out that crucial secret. Your PSK stays secure yet always available for your authentication flows.

  • Thanks for the detailed explanation. This looks like it could fit our needs, I'll investigate the TF-M provisioning approach you've outlined.

Reply Children
No Data
Related