Secure storage of ECC private key

Environment:

  • nRF Connect SDK 2.1.0
  • nRF5340DK (build config: nrf5340dk_nrf5340_cpuapp)

We are implementing asymmetric security for a connected device using the nRF5340 and are looking to determine the best approach for storing the device’s own private identity key.

The intention is to have the device generate its own random key internally during initial provisioning.

We need to protect the key from exposure/extraction including by parties with physical access. Ideally not relying only on APPROTECT.

These are the approaches we have identified so far:

1. PSA Key Storage API using NVS backend.

This stores private key unencrypted in flash with ASCII header ‘PSA KEY’, which is not ideal.

Possible work-around to use encrypted internal trusted storage (requires TF-M / build with _ns config) [thread] – not out of the question, but adds complexity as we are currently not building with TF-M.

2. KMU–CryptoCell Push (seems like ideal option)

The KMU can store ECC private keys using multiple slots, however, according to this thread it is not possible to push an asymmetric key directly to the CryptoCell. I am trying to understand this limitation. According to documentation:

    • CryptoCell DMA transaction size limit is 2^16 - 1 bytes [source]
    • ECC secp256r1 private key size is 32 bytes, so would take 2 128bit slots
    • KMU can push keys split across multiple slots by incrementing the DEST address in meta data by 4 words (128 bits) [source]

Note: A key value distributed over multiple key slots should use the same key slot configuration in its key headers, but the secure destination address for each key slot instance must be incremented by 4 words (128 bits) for each key slot instance spanned.

Note: If a key value is distributed over multiple key slots due to its key size, exceeding the maximum 128-bit key value limitation, then each distributed key slot must be pushed individually in order to transfer the entire key value over secure APB.

Given the key size is well within the max DMA transaction limit, and 256 bit AES keys can be pushed directly, why is it not possible for a 256 bit ECC key to be pushed for signing and verification operations?

3. KMU storage-only (seems like next best solution and easier than encrypted internal trusted storage, since we are not currently building with TF-M)

a. Readable key (e.g., KMU_IDENTITY_KEY_PERMISSIONS)

Will the key be exposed in UICR or FLASH dump?

Is there any protection of the key data at rest, or could it easily be extracted by someone with physical access and a debug probe?

b. Readable key encrypted w/ Hardware Unique Key

My assumption is that both HUK and Identity Key are stored in the UICR key storage region, with the HUK being push-only, and the encrypted Identity Key being readable.

[Identity key generation — nRF Connect SDK 2.1.0 documentation (nordicsemi.com)]

It seems this can be used without TF-M / secure boot.

Where are the keys actually stored?

In summary – my two main questions are:

  • Is option 2 possible?
  • If not, is option 3 the next best solution – assuming no external secure element is added, and am I understanding the protections offered by option 3 correctly?

Thanks

  • The reason the KMU works perfectly for AES is that the AES KEY registers of the CC312 are write-only. That way it is possible to have a secret AES key programmed in the KMU and let the CC312 encrypt/decrypt data using this key, without the CPU ever being able to get access to the key.

    The PKA memory on the other hand of the CC312 can be both read and written by the CPU, so that's why you can not hide the private key from the CPU. The register interface of the PKA (one register is used for the CC312's internal SRAM address and then another register is used for continuously reading/writing to this location, see https://github.com/ARM-software/cryptocell-312-runtime/blob/91539d62a67662e40e7d925694e55bbc7e679f84/codesafe/src/crypto_api/pki/common/pka.c#L785) is also not compatible with the KMU. Furthermore, for ECC, the CC312 is used as a hw accelerator for big integers, where the host cpu drives and schedules the operations, but the ECDH/ECDSA algorithms are constructed so that the private key defines the order of the mathematical operations, so the private key is actually stored in the CPU and not in the PKA memory.

    To still make the best of what is available on that hardware, you can use the TF-M (https://developer.nordicsemi.com/nRF_Connect_SDK/doc/2.2.0/nrf/samples/crypto/persistent_key_usage/README.html) as suggested in the thread you linked to. The idea is to have a secure and non-secure region of the memory map, where most of your application code is run in the non-secure region, only elevating to the secure region when you for example want to sign data with a private key. This is similar to modern operating systems like Linux work, where applications run in a limited environment and must go through the kernel for basically everything. The important thing here is then that the code running in the secure region does not have any security bugs. But as you say, this would still "only" be as secure as "APPROTECT".

  • Thanks, this clarifies a lot.

    As for the third approach I listed -- based on the identity key generation sample -- as I understand it, this can be used either with secure boot + TF-M, or with the entire application running in secure mode.

    The trade-offs seem to be:

    • with or without TF-M, the private key is protected "at rest" due to being encrypted by the HUK which cannot be extracted from the KMU
    • the private key could be extracted by an attacker who is able to run code on the CPU (e.g. due to a software vulnerability) and therefore decrypt the private key using the HUK.
      •  TF-M makes this more difficult as there is only a small portion of the app which has access to the KMU
    • If an attacker had physical access, and the ability to bypass APPROTECT (e.g. due to HW vulnerability) they would be able to extract the key (albeit with more difficulty than if it were simply stored unencrypted in flash)

    Does this sound right?

Related