Raef Coles | 6b69255 | 2022-03-15 13:38:16 +0000 | [diff] [blame] | 1 | ################# |
| 2 | TF-M builtin keys |
| 3 | ################# |
| 4 | |
| 5 | :Author: Raef Coles |
| 6 | :Organization: Arm Limited |
| 7 | :Contact: raef.coles@arm.com |
| 8 | |
| 9 | ************ |
| 10 | Introduction |
| 11 | ************ |
| 12 | |
| 13 | TF-M has several keys that are bound to the device itself instead of a secure |
| 14 | partition. These keys must be accessed through a HAL function, either loading |
| 15 | them from OTP or another platform-specific location. These keys are henceforth |
| 16 | referred to as "builtin keys", and include (but are not limited to): |
| 17 | |
| 18 | 1) The Hardware Unique Key (HUK) |
| 19 | 2) The Initial Attestation Key (IAK) |
| 20 | |
| 21 | Currently, the IAK is loaded by the attestation partition as a transient key, |
| 22 | which requires some key-loading logic to be implemented by that partition. The |
| 23 | HUK is not loaded in the crypto service, and is instead used by an |
| 24 | implementation of a TF-M specific KDF algorithm which then loads the key and |
| 25 | invokes Mbed TLS directly. |
| 26 | |
| 27 | **************** |
| 28 | PSA builtin keys |
| 29 | **************** |
| 30 | |
| 31 | The PSA Cryptographic API provides a mechanism for accessing keys that are |
| 32 | stored in platform-specific locations (often hardware accelerators or OTP). One |
| 33 | of the properties of builtin keys is that they are accessed via a predefined |
| 34 | handle, which can be leveraged to allow TF-M to define a set of handles for the |
| 35 | builtin keys that it provides. |
| 36 | |
| 37 | Defining these constant handles allows these keys to be used by secure partition |
| 38 | and non-secure callers (subject to access policy), via the standard PSA crypto |
| 39 | interfaces. |
| 40 | |
| 41 | Ideally, it would be possible to just have PSA builtin keys that are stored in |
| 42 | crypto service RAM, in the same way that volatile keys are. Mbed TLS does not |
| 43 | support this and only supports builtin keys as part of the code flow that |
| 44 | interfaces with hardware accelerators. |
| 45 | |
| 46 | ********************* |
| 47 | PSA crypto driver API |
| 48 | ********************* |
| 49 | |
| 50 | The PSA crypto driver API allows most PSA Crypto APIs to defer their operation |
| 51 | to an accelerator driver in preference of the software implementation. It also |
| 52 | adds the concept of storage locations for keys, which is used to access keys |
| 53 | stored on hardware accelerators. |
| 54 | |
| 55 | The TF-M builtin keys code leverages the PSA crypto driver API by creating a new |
| 56 | driver that provides no acceleration, only a key storage location. This storage |
| 57 | location is not backed by hardware, but is instead inside the RAM of the crypto |
| 58 | partition. |
| 59 | |
| 60 | This is done by hooking two functions into the |
| 61 | ``library/psa_crypto_driver_wrappers.c`` file. These functions are: |
| 62 | |
| 63 | 1) ``tfm_key_loader_get_builtin_key`` |
| 64 | 2) ``tfm_key_loader_get_builtin_key_len`` |
| 65 | |
| 66 | The flow for these functions being used is: |
| 67 | |
| 68 | 1) A request is made to a PSA Crypto API that references a key by a key |
| 69 | handle. |
| 70 | 2) The PSA Crypto core layer checks that the handle is inside the builtin keys |
| 71 | region, and then if the key has not yet been loaded into a transient Mbed |
| 72 | TLS keyslot calls ``tfm_plat_builtin_key_get_lifetime_and_slot`` (which is a |
| 73 | wrapper around ``mbedtls_psa_platform_get_builtin_key``), which is defined |
| 74 | in ``crypto_keys.h``. This function maps each builtin key to a driver, which |
| 75 | in most cases is the default ``tfm_builtin_key_loader`` via |
| 76 | ``TFM_BUILTIN_KEY_LOADER_KEY_LOCATION``. The function also returns a slot |
| 77 | number, which is a driver-specific index to specify the key. |
| 78 | 3) This location and slot index then calls |
| 79 | ``psa_driver_wrapper_get_builtin_key``, which for the key location |
| 80 | ``TFM_BUILTIN_KEY_LOADER_KEY_LOCATION`` (the new location value that is bound |
| 81 | to the TF-M builtin keys driver) calls the previously hooked function |
| 82 | ``tfm_key_loader_get_builtin_key``. |
| 83 | 4) This function, along with its counterpart |
| 84 | ``tfm_key_loader_get_builtin_key_len``, allow Mbed TLS to copy the |
| 85 | key material into an internal keyslot, which is then used whenever further |
| 86 | calls to using that same builtin key ID are made. |
| 87 | |
| 88 | In order to load the keys into the tfm_key_loader memory (in the crypto |
| 89 | partition), ``crypto_keys.h`` defines a function ``tfm_plat_load_builtin_keys`` |
| 90 | which is responsible for loading all builtin keys into and driver that requires |
| 91 | loading. |
| 92 | |
| 93 | ***************** |
| 94 | Technical details |
| 95 | ***************** |
| 96 | |
| 97 | ------------------------------ |
| 98 | Builtin key IDs and overriding |
| 99 | ------------------------------ |
| 100 | |
| 101 | TF-M builtin key IDs are defined in ``interface/include/tfm_crypto_defs.h`` by |
| 102 | the enum ``tfm_key_id_builtin_t``. They are allocated inside the range that PSA |
| 103 | considers to be builtin keys. A platform can specify extra builtin key IDs by |
| 104 | setting the ``PLATFORM_DEFAULT_CRYPTO_KEYS`` variable to ``OFF``, creating the |
| 105 | header ``platform_builtin_key_ids.h``, and specifying new keys and IDs. |
| 106 | |
| 107 | -------------------------- |
| 108 | Builtin key access control |
| 109 | -------------------------- |
| 110 | |
| 111 | Builtin keys by default can be used by any caller since the key handle is |
| 112 | public information. TF-M must mediate access to the keys, which is done in the |
| 113 | function ``tfm_plat_builtin_key_get_usage`` (part of ``crypto_keys.h``). This |
| 114 | function maps the caller ID to a particular key usage, which allows granular key |
| 115 | permissions. The function returns ``PSA_ERROR_NOT_PERMITTED`` if a caller does |
| 116 | not have permission to use the key. |
| 117 | |
| 118 | ------------------------------ |
| 119 | Multi-partition key derivation |
| 120 | ------------------------------ |
| 121 | |
| 122 | The HUK is used for key derivation by any secure partition or NS caller that |
| 123 | requires keys that are bound to a particular context. For example, Protected |
| 124 | Storage derives keys uniquely for each user of the service which are used to |
| 125 | encrypt each user's files. In order to provide HUK derivation to every secure |
| 126 | partition / NS caller, it must be ensured that no service that utilises HUK |
| 127 | derivation can derive the same key as another service (simply by inputting the |
| 128 | same KDF inputs). |
| 129 | |
| 130 | This is accomplished by deriving a further "platform key" for each builtin key |
| 131 | that can be used for key derivation. These platform keys are derived from the |
| 132 | builtin key, using the partition ID as a KDF input, and can then be used for |
| 133 | further derivation by the partition (or NS caller) with the further derived keys |
| 134 | being unique for each partition even if the KDF inputs are the same. |
| 135 | |
| 136 | .. Note:: |
| 137 | If the NS client ID feature is disabled, all NS callers share a partition ID |
| 138 | of ``-1``, and therefore will share a platform key and be therefore be able |
| 139 | to derive the same keys as other NS callers. |
| 140 | |
| 141 | For keys that are not exposed outside the device, this is transparent to the |
| 142 | service that is using the key derivation, as they have no access to the builtin |
| 143 | key material and cannot distinguish between keys derived directly from it and |
| 144 | keys derived from the platform key. For some builtin keys, deriving platform |
| 145 | keys is not acceptable, as the key is used outside the device (i.e. the IAK |
| 146 | public key is used to verify attestation tokens) so the actual builtin key is |
| 147 | used. |
| 148 | |
| 149 | The decision has been taken to derive platform keys for any key that can be used |
| 150 | for key derivation (``PSA_KEY_USAGE_DERIVE``), and not derive platform keys |
| 151 | otherwise. For builtin keys that do not derive platform keys but are directly |
| 152 | used, care must be taken with access control where multiple partitions have |
| 153 | access. |
| 154 | |
| 155 | --------------------------------- |
| 156 | Mbed TLS transparent builtin keys |
| 157 | --------------------------------- |
| 158 | |
| 159 | Mbed TLS does not natively support transparent builtin keys (transparent keys |
| 160 | are keys where the key material is directly accessible to the PSA Crypto core), |
| 161 | so some modifications had to be made. Opaque keyslots have the same basic |
| 162 | structure as standard transparent keyslots, and can be passed to the functions |
| 163 | usually reserved for transparent keys, though this behaviour is not defined and |
| 164 | may not continue to work in future versions. Therefore, the only modification |
| 165 | required currently is to force keys that have the location |
| 166 | ``TFM_BUILTIN_KEY_LOADER_KEY_LOCATION`` to be passed to the functions that only |
| 167 | usually accept keys with the location ``PSA_KEY_LOCATION_LOCAL_STORAGE``. |
| 168 | |
| 169 | -------------- |
| 170 | |
| 171 | *Copyright (c) 2022, Arm Limited. All rights reserved.* |