################# TF-M builtin keys ################# :Author: Raef Coles :Organization: Arm Limited :Contact: raef.coles@arm.com ************ Introduction ************ 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): 1) The Hardware Unique Key (HUK) 2) 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: 1) ``tfm_key_loader_get_builtin_key`` 2) ``tfm_key_loader_get_builtin_key_len`` The flow for these functions being used is: 1) A request is made to a PSA Crypto API that references a key by a key handle. 2) 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`` via ``TFM_BUILTIN_KEY_LOADER_KEY_LOCATION``. The function also returns a slot number, which is a driver-specific index to specify the key. 3) 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 ``tfm_key_loader_get_builtin_key``. 4) 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 partition), ``crypto_keys.h`` defines a function ``tfm_plat_load_builtin_keys`` which is responsible for loading all builtin keys into and driver that requires loading. ***************** Technical details ***************** ------------------------------ Builtin key IDs and overriding ------------------------------ TF-M builtin key IDs are defined in ``interface/include/tfm_crypto_defs.h`` by the enum ``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 setting the ``PLATFORM_DEFAULT_CRYPTO_KEYS`` variable to ``OFF``, creating the header ``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 function ``tfm_plat_builtin_key_get_usage`` (part of ``crypto_keys.h``). This 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. .. Note:: If the NS client ID feature is disabled, all NS callers share a partition ID of ``-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 access. --------------------------------- 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 ``PSA_KEY_LOCATION_LOCAL_STORAGE``. -------------- *Copyright (c) 2022, Arm Limited. All rights reserved.*