| ################# |
| 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.* |