Crypto: Refactor the tfm_builtin_key_loader and HAL interaction
This patch refactors the entry points of the tfm_builtin_key_loader
driver to simplify its interaction with crypto keys HAL layer and
the rest of the TF-M Crypto service and PSA Crypto core layer.
* Decouple as much as possible each module from mbed TLS specific
types, and makes sure all library interactions are abstracted in
the crypto_library module of the crypto service
* Simplify the HAL requirements to provide platform builtin keys
as described in tfm_plat_crypto_keys.h
* Update the documentation to reflect the design change
* Fix minor issues and typos, include paths, etc
* Regenerate mbed TLS patches on top of 3.3.0 tag to be applied
Signed-off-by: Antonio de Angelis <antonio.deangelis@arm.com>
Change-Id: Id26ff0b88da87075490d17a4c8af8f209bb34a08
diff --git a/docs/design_docs/tfm_builtin_keys.rst b/docs/design_docs/tfm_builtin_keys.rst
index c27d2ca..d68f51f 100644
--- a/docs/design_docs/tfm_builtin_keys.rst
+++ b/docs/design_docs/tfm_builtin_keys.rst
@@ -10,85 +10,141 @@
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):
+When TF-M is integrated on a platform, the platform itself can provide several
+keys for usage which are bound to the device instead of being owned by a
+specific secure partition. When those keys are readable by the secure
+processing environment, the platform must provide a function to load these keys
+in the HAL layer, either loading them from OTP or another platform specific
+location or subsystem. These keys are henceforth referred to as "builtin keys",
+and might include (but are not limited to) the following:
-1) The Hardware Unique Key (HUK)
-2) The Initial Attestation Key (IAK)
+ 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.
+The ``tfm_builtin_key_loader`` component implements a mechanism to discover
+those keys and make them available to the PSA Crypto APIs for usage. Note that
+if a key is stored in a subsystem which can't be read by the secure
+processing environment, a full opaque driver must be used to be able to use
+those keys through the PSA Crypto APIs. This document focuses only on the case
+where the keys can be read by the SPE and processed by the driver described in
+this document.
+
+In TF-M's legacy solution, the IAK is loaded by the attestation service as a
+volatile 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. Both solutions are far from ideal as they require an
+effort to load (and duplicate) the keys per each user, or require a dedicated
+code in TF-M that directly interacts with the HAL layer and invokes functions
+from the crypto library bypassing the PSA Crypto interface. The aim of the
+``tfm_builtin_key_loader`` driver is to provide a uniform interface to use the
+builtin keys available in a platform.
+
+Implementing a driver to deal with builtin keys allows to expand the legacy
+solution for dealing with this type of keys in several ways. For example, it
+avoid the need for partitions to implement dedicated mechanisms for probing the
+HAL layer for builtin keys and load them as volatile. It removes the need to
+have implementation specific call flows for deriving keys from the HUK (as that
+requirement now is fulfilled by the driver itself transparently). It allows
+uniform access to the keys also from the NS world (in any case, subject to the
+policy dictated by the platform). Correctly abstracts away details of the key
+handling mechanism from TF-M partitions into the PSA Crypto core key management
+subsystem.
****************
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.
+stored in platform-specific locations (often hardware accelerators or OTP). A
+builtin key is assigned a specific key_id, i.e. a handle, which is hardcoded at
+build time and must be selected in the range [MBEDTLS_PSA_KEY_ID_BUILTIN_MIN,
+MBEDLTS_PSA_KEY_ID_BUILTIN_MAX]. A user of the PSA Crypto API can reference
+those keys directly by using these handles. It is up to the platform to specify
+policy restrictions for specific users of the keys, e.g. an NS entity, or a
+secure partition. The PSA Crypto core will then check those policies to grant
+or deny access to the builtin key for that user.
-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.
+******************************
+PSA cryptoprocessor driver API
+******************************
-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.
+The PSA specification allows the PSA Crypto APIs to defer their operation to an
+accelerator driver, through a mechanism described in the PSA cryptoprocessor
+driver interface specification [1]_. This specification defines the concept of
+PSA Crypto core, i.e. "An implementation of the PSA Cryptography API is
+composed of a core and zero or more drivers". The PSA specification also has
+the concept of storage locations for keys, through the type
+``psa_key_location_t``, which is used to access keys that don't have local
+storage [2]_. This is leveraged mainly by opaque drivers mainly that use keys
+for which the key material is not readable by the PSA crypto core layer.
-*********************
-PSA crypto driver API
-*********************
+TF-M defines a software driver called ``tfm_builtin_key_loader`` that provides
+no acceleration but just defines a dedicated key location defined through the
+``TFM_BUILTIN_KEY_LOADER_KEY_LOCATION`` define. By resorting to the entry points
+provided by this driver, the PSA Crypto core slot management subsystem can
+access keys stored in the underlying platform, validate key usage policies and
+allow PSA Crypto APIs to uniformly access builtin keys using the same call flows
+used with traditional local-storage keys.
-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.
+This is implemented by hooking the entry points defined by the driver into the
+``library/psa_crypto_driver_wrappers.c`` file provided by the PSA Crypto core.
+This is currently done manually but eventually could be just autogenerated by
+parsing a description of the driver entry points in the JSON format. These entry
+points are:
-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.
+ 1. ``tfm_builtin_key_loader_init``
+ 2. ``tfm_builtin_key_loader_get_key_buffer_size``
+ 3. ``tfm_builtin_key_loader_get_builtin_key``
-This is done by hooking two functions into the
-``library/psa_crypto_driver_wrappers.c`` file. These functions are:
+The call flow for the entry points from the driver wrapper layer is as follows:
-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.
+ 1. During the driver initialisation phase started by the PSA Crypto Core init,
+ the ``tfm_builtin_key_loader_init`` function is called to probe the
+ platform HAL and retrieve the builtin keys. Those keys are described by
+ the types defined in the HAL layer interface header
+ ``tfm_plat_crypto_keys.h``. In particular global tables describing key
+ properties and user policies must be implemented by each platform and are
+ retrieved by the two accessor functions
+ ``tfm_plat_builtin_key_get_desc_table_ptr()`` and
+ ``tfm_plat_builtin_key_get_policy_table_ptr()``. The keys are loaded from
+ the platform in secure RAM in the TF-M Crypto partition with associated
+ metadata. It's worth to note that the keys are loaded through callback
+ functions which the platform lists in the key descriptor table.
+ 2. Once the TF-M Crypto service is initialised, at runtime it might receive a
+ request through an API call to use one of the builtin key IDs. Those IDs
+ are described in the ``tfm_builtin_key_ids.h`` header. Platforms can
+ override the default values providing their own header.
+ 3. When the PSA Crypto core in the ``psa_get_and_lock_key_slot()`` function
+ checks that the ``key_id`` being requested is in the builtin range region,
+ it probes the platform through the function
+ ``mbedtls_psa_platform_get_builtin_key`` which must be implemented by the
+ TF-M Crypto service library abstraction layer. This function just checks
+ the key descriptor table from the HAL to understand if such ``key_id`` is
+ available in the platform and what are the corresponding ``slot`` and
+ ``lifetime`` values associated to it. The lifetime contains the location of
+ the key, which determines which driver is responsible for dealing with it
+ (for the ``tfm_builtin_key_loader`` driver, that is
+ ``TFM_BUILTIN_KEY_LOADER_KEY_LOCATION``), while the ``slot`` value maps the
+ key to the slot in the driver internal storage.
+ 4. At this point, the PSA Crypto core knows that the key exists and is bound
+ to the location associated to the driver. By calling into the driver
+ wrappers layer is then able to retrieve the key attributes stored in the
+ platform for that key ID, and the size required to allocate in its
+ internal slot management system in order to load the key material in the
+ core. This is done by calling ``tfm_builtin_key_loader_get_builtin_key``
+ just with a valid key attributes pointer (and nothing else), to retrieve
+ the attributes. Once the attributes are available, the required size is
+ retrieved through the driver wrapper by calling
+ ``tfm_builtin_key_loader_get_key_buffer_size``.
+ 5. At this stage, the slot management subsystem calls again into the driver
+ wrapper layer through ``tfm_builtin_key_loader_get_builtin_key`` with a
+ valid buffer to hold the key material returned by the
+ ``tfm_builtin_key_loader`` driver. When loading the key, the user
+ requiring that key_id is validated by the driver code against the policies
+ defined by the platform. If the policies match, the builtin key material
+ and metadata is loaded and is used like a transparent key available to the
+ PSA Crypto core slot management subsystem.
*****************
Technical details
@@ -98,22 +154,25 @@
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.
+TF-M builtin key IDs are defined in
+``interface/include/crypto_keys/tfm_builtin_key_ids.h`` through the enum
+``tfm_key_id_builtin_t``. They are allocated inside the range that PSA
+specifies for the builtin keys, i.e. between ``MBEDTLS_PSA_KEY_ID_BUILTIN_MIN``
+and ``MBEDLTS_PSA_KEY_ID_BUILTIN_MAX``. A platform can specify extra builtin key
+IDs by setting the ``PLATFORM_DEFAULT_CRYPTO_KEYS`` variable to ``OFF``,
+creating the header ``tfm_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.
+A builtin key is accessible by all callers since the ``key_id`` associated to it
+is public information. Access to the keys must be mediated, which is done by
+matching the user requesting the ``key_id`` against the policies available for
+that user on that particular key in the policy table. If no policies are
+specified for a specific combination of user and ``key_id``, the usage flags in
+the key attributes will be all set to zeros, meaning the key will be unusable
+for any operation for that particular user.
------------------------------
Multi-partition key derivation
@@ -122,16 +181,17 @@
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
+encrypt user 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).
+derivation can derive the same key as another service (simply by using the same
+inputs for the KDF APIs, i.e. accessing the same base key for derivation).
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.
+that has ``PSA_KEY_USAGE_DERIVE`` set in its attributes. These platform keys
+are derived from the builtin key, using the partition ID as a KDF input, and
+can then be used for safely for further derivations by the user, without risks
+to derive the same keys as other users. This is enforced directly by the
+``tfm_builtin_key_loader`` driver.
.. Note::
If the NS client ID feature is disabled, all NS callers share a partition ID
@@ -150,22 +210,35 @@
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.
+access to the same raw key material.
---------------------------------
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),
+are keys where the key material is directly accessible by 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``.
+structure as standard transparent key slots, and can be passed to the functions
+usually reserved for transparent keys, though this is a private implementation
+detail of the mbed TLS library and is not specified in the driver interface.
+Therefore, the only modification required currently is to allow keys that have
+the location ``TFM_BUILTIN_KEY_LOADER_KEY_LOCATION`` to be passed to the
+functions that usually accept transparent keys only, i.e. with the location
+``PSA_KEY_LOCATION_LOCAL_STORAGE``. This is due to the fact that the standard
+assumption of the PSA Crypto core is that, if a driver that provides an
+additional location, will also provide dedicated cryptographic mechanisms to act
+on those keys, but this is not the case of the ``tfm_builtin_key_loader``, as it
+just provides a mechanism to load keys (which act as a transparent key with
+local storage, once loaded), but mbed TLS does not support such "transparent
+builtin key" concept.
+
+References
+----------
+
+.. [1] PSA cryptoprocessor driver interface: \ https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-interface.md
+.. [2] Definition of psa_key_location_t type in the PSA spec: \ https://armmbed.github.io/mbed-crypto/html/api/keys/lifetimes.html#c.psa_key_location_t
--------------
-*Copyright (c) 2022, Arm Limited. All rights reserved.*
+*Copyright (c) 2022-2023, Arm Limited. All rights reserved.*