TF-M builtin keys
TF-M has several keys that are bound to the device itself instead of a secure partition. These keys must be accessed through a HAL function, either loading them from OTP or another platform-specific location. These keys are henceforth referred to as “builtin keys”, and include (but are not limited to):
The Hardware Unique Key (HUK)
The Initial Attestation Key (IAK)
Currently, the IAK is loaded by the attestation partition as a transient key, which requires some key-loading logic to be implemented by that partition. The HUK is not loaded in the crypto service, and is instead used by an implementation of a TF-M specific KDF algorithm which then loads the key and invokes Mbed TLS directly.
PSA builtin keys
The PSA Cryptographic API provides a mechanism for accessing keys that are stored in platform-specific locations (often hardware accelerators or OTP). One of the properties of builtin keys is that they are accessed via a predefined handle, which can be leveraged to allow TF-M to define a set of handles for the builtin keys that it provides.
Defining these constant handles allows these keys to be used by secure partition and non-secure callers (subject to access policy), via the standard PSA crypto interfaces.
Ideally, it would be possible to just have PSA builtin keys that are stored in crypto service RAM, in the same way that volatile keys are. Mbed TLS does not support this and only supports builtin keys as part of the code flow that interfaces with hardware accelerators.
PSA crypto driver API
The PSA crypto driver API allows most PSA Crypto APIs to defer their operation to an accelerator driver in preference of the software implementation. It also adds the concept of storage locations for keys, which is used to access keys stored on hardware accelerators.
The TF-M builtin keys code leverages the PSA crypto driver API by creating a new driver that provides no acceleration, only a key storage location. This storage location is not backed by hardware, but is instead inside the RAM of the crypto partition.
This is done by hooking two functions into the
library/psa_crypto_driver_wrappers.c file. These functions are:
The flow for these functions being used is:
A request is made to a PSA Crypto API that references a key by a key handle.
- The PSA Crypto core layer checks that the handle is inside the builtin keys
region, and then if the key has not yet been loaded into a transient Mbed TLS keyslot calls
tfm_plat_builtin_key_get_lifetime_and_slot(which is a wrapper around
mbedtls_psa_platform_get_builtin_key), which is defined in
crypto_keys.h. This function maps each builtin key to a driver, which in most cases is the default
TFM_BUILTIN_KEY_LOADER_KEY_LOCATION. The function also returns a slot number, which is a driver-specific index to specify the key.
This location and slot index then calls
psa_driver_wrapper_get_builtin_key, which for the key location
TFM_BUILTIN_KEY_LOADER_KEY_LOCATION(the new location value that is bound to the TF-M builtin keys driver) calls the previously hooked function
This function, along with its counterpart
tfm_key_loader_get_builtin_key_len, allow Mbed TLS to copy the key material into an internal keyslot, which is then used whenever further calls to using that same builtin key ID are made.
In order to load the keys into the tfm_key_loader memory (in the crypto
crypto_keys.h defines a function
which is responsible for loading all builtin keys into and driver that requires
Builtin key IDs and overriding
TF-M builtin key IDs are defined in
tfm_key_id_builtin_t. They are allocated inside the range that PSA
considers to be builtin keys. A platform can specify extra builtin key IDs by
PLATFORM_DEFAULT_CRYPTO_KEYS variable to
OFF, creating the
platform_builtin_key_ids.h, and specifying new keys and IDs.
Builtin key access control
Builtin keys by default can be used by any caller since the key handle is
public information. TF-M must mediate access to the keys, which is done in the
tfm_plat_builtin_key_get_usage (part of
function maps the caller ID to a particular key usage, which allows granular key
permissions. The function returns
PSA_ERROR_NOT_PERMITTED if a caller does
not have permission to use the key.
Multi-partition key derivation
The HUK is used for key derivation by any secure partition or NS caller that requires keys that are bound to a particular context. For example, Protected Storage derives keys uniquely for each user of the service which are used to encrypt each user’s files. In order to provide HUK derivation to every secure partition / NS caller, it must be ensured that no service that utilises HUK derivation can derive the same key as another service (simply by inputting the same KDF inputs).
This is accomplished by deriving a further “platform key” for each builtin key that can be used for key derivation. These platform keys are derived from the builtin key, using the partition ID as a KDF input, and can then be used for further derivation by the partition (or NS caller) with the further derived keys being unique for each partition even if the KDF inputs are the same.
If the NS client ID feature is disabled, all NS callers share a partition ID
-1, and therefore will share a platform key and be therefore be able
to derive the same keys as other NS callers.
For keys that are not exposed outside the device, this is transparent to the service that is using the key derivation, as they have no access to the builtin key material and cannot distinguish between keys derived directly from it and keys derived from the platform key. For some builtin keys, deriving platform keys is not acceptable, as the key is used outside the device (i.e. the IAK public key is used to verify attestation tokens) so the actual builtin key is used.
The decision has been taken to derive platform keys for any key that can be used
for key derivation (
PSA_KEY_USAGE_DERIVE), and not derive platform keys
otherwise. For builtin keys that do not derive platform keys but are directly
used, care must be taken with access control where multiple partitions have
Mbed TLS transparent builtin keys
Mbed TLS does not natively support transparent builtin keys (transparent keys
are keys where the key material is directly accessible to the PSA Crypto core),
so some modifications had to be made. Opaque keyslots have the same basic
structure as standard transparent keyslots, and can be passed to the functions
usually reserved for transparent keys, though this behaviour is not defined and
may not continue to work in future versions. Therefore, the only modification
required currently is to force keys that have the location
TFM_BUILTIN_KEY_LOADER_KEY_LOCATION to be passed to the functions that only
usually accept keys with the location
Copyright (c) 2022, Arm Limited. All rights reserved.