blob: 699826a5d59b9b4465982f806620dbefbbedee17 [file] [log] [blame] [view]
Aditya Deshpandee41f7e42023-01-12 16:29:02 +00001# PSA Cryptoprocessor driver development examples
2
3As of Mbed TLS 3.3.0, the PSA Driver Interface has only been partially implemented. As a result, the deliverables for writing a driver and the method for integrating a driver with Mbed TLS will vary depending on the operation being accelerated. This document describes how to write and integrate cryptoprocessor drivers depending on which operation or driver type is being implemented.
4
5The `docs/proposed/` directory contains three documents which pertain to the proposed, work-in-progress driver system. The [PSA Driver Interface](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-interface.md) describes how drivers will interface with Mbed TLS in the future, as well as driver types, operation types, and entry points. As many key terms and concepts used in the examples in this document are defined in the PSA Driver Interface, it is recommended that developers read it prior to starting work on implementing drivers.
6The PSA Driver [Developer](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-developer-guide.md) Guide describes the deliverables for writing a driver that can be used with Mbed TLS, and the PSA Driver [Integration](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-integration-guide.md) Guide describes how a driver can be built alongside Mbed TLS.
7
Aditya Deshpandeabf4bf32023-01-23 14:47:03 +00008## Contents:
9[Background on how Mbed TLS calls drivers](#background-on-how-mbed-tls-calls-drivers)\
10[Process for Entry Points where auto-generation is implemented](#process-for-entry-points-where-auto-generation-is-implemented) \
11[Process for Entry Points where auto-generation is not implemented](#process-for-entry-points-where-auto-generation-is-not-implemented) \
12[Example: Manually integrating a software accelerator alongside Mbed TLS](#example-manually-integrating-a-software-accelerator-alongside-mbed-tls)
13
Aditya Deshpandee41f7e42023-01-12 16:29:02 +000014## Background on how Mbed TLS calls drivers
15
16The PSA Driver Interface specification specifies which cryptographic operations can be accelerated by third-party drivers. Operations that are completed within one step (one function call), such as verifying a signature, are called *Single-Part Operations*. On the other hand, operations that consist of multiple steps implemented by different functions called sequentially are called *Multi-Part Operations*. Single-part operations implemented by a driver will have one entry point, while multi-part operations will have multiple: one for each step.
17
18There are two types of drivers: *transparent* or *opaque*. See below an excerpt from the PSA Driver Interface specification defining them:
19* **Transparent** drivers implement cryptographic operations on keys that are provided in cleartext at the beginning of each operation. They are typically used for hardware **accelerators**. When a transparent driver is available for a particular combination of parameters (cryptographic algorithm, key type and size, etc.), it is used instead of the default software implementation. Transparent drivers can also be pure software implementations that are distributed as plug-ins to a PSA Cryptography implementation (for example, an alternative implementation with different performance characteristics, or a certified implementation).
20* **Opaque** drivers implement cryptographic operations on keys that can only be used inside a protected environment such as a **secure element**, a hardware security module, a smartcard, a secure enclave, etc. An opaque driver is invoked for the specific [key location](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-interface.md#lifetimes-and-locations) that the driver is registered for: the dispatch is based on the key's lifetime.
21
22Mbed TLS contains a **driver dispatch layer** (also called a driver wrapper layer). For each cryptographic operation that supports driver acceleration (or sub-part of a multi-part operation), the library calls the corresponding function in the driver wrapper. Using flags set at compile time, the driver wrapper ascertains whether any present drivers support the operation. When no such driver is present, the built-in library implementation is called as a fallback (if allowed). When a compatible driver is present, the driver wrapper calls the driver entry point function provided by the driver author.
23
24The long-term goal is for the driver dispatch layer to be auto-generated using a JSON driver description file provided by the driver author.
25For some cryptographic operations, this auto-generation logic has already been implemented. When accelerating these operations, the instructions in the above documents can be followed. For the remaining operations which do not yet support auto-generation of the driver wrapper, developers will have to manually edit the driver dispatch layer and call their driver's entry point functions from there.
26
27Auto-generation of the driver wrapper is supported for the operation entry points specified in the table below. Certain operations are only permitted for opaque drivers. All other operation entry points do not support auto-generation of the driver wrapper.
28
29| Transparent Driver | Opaque Driver |
30|---------------------|---------------------|
31| `import_key` | `import_key` |
32| `export_key` | `export_key` |
33| `export_public_key` | `export_public_key` |
34| | `copy_key` |
35| | `get_builtin_key` |
36
37### Process for Entry Points where auto-generation is implemented
38
39If the driver is accelerating operations whose entry points are in the above table, the instructions in the driver [developer](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-developer-guide.md) and [integration](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-integration-guide.md) guides should be followed.
40
41**TODO: Provide brief summary of the method using the Mbed TLS test driver as an example**
42
43
44### Process for Entry Points where auto-generation is not implemented
45
46If the driver is accelerating operations whose entry points are not present in the table, a different process is followed where the developer manually edits the driver dispatch layer. In general, the following steps must be taken **for each single-part operation** or **for each sub-part of a multi-part operation**:
47
48**1. Choose a driver prefix and a macro name that indicates whether the driver is enabled** \
49A driver prefix is simply a word (often the name of the driver) that all functions/macros associated with the driver should begin with. This is similar to how most functions/macros in Mbed TLS begin with `PSA_XXX/psa_xx` or `MBEDTLS_XXX/mbedtls_xxx`. The macro name can follow the form `DRIVER_PREFIX_ENABLED` or something similar; it will be used to indicate the driver is available to be called. When building with the driver present, define this macro at compile time. For example, when using `make`, this is done using the `-D` flag.
50
51**2. Locate the function in the driver dispatch layer that corresponds to the entry point of the operation being accelerated.** \
52The file `psa_crypto_driver_wrappers.c.jinja` contains the driver wrapper functions. For the entry points that have driver wrapper auto-generation implemented, the functions have been replaced with `jinja` templating logic. While the file has a `.jinja` extension, the driver wrapper functions for the remaining entry points are simple C functions. The names of these functions are of the form `psa_driver_wrapper` followed by the entry point name. So, for example, the function `psa_driver_wrapper_sign_hash()` corresponds to the `sign_hash` entry point.
53
54**3. If a driver entry point function has been provided then ensure it has the same signature as the driver wrapper function.** \
Aditya Deshpande277690e2023-01-18 11:27:26 +000055If one has not been provided then write one. Its name should begin with the driver prefix, followed by transparent/opaque (depending on driver type), and end with the entry point name. It should have the same signature as the driver wrapper function. The purpose of the entry point function is to take arguments in PSA format for the implemented operation and return outputs/status codes in PSA format. \
56*Return Codes:*
57* `PSA_SUCCESS`: Successful Execution
58* `PSA_ERROR_NOT_SUPPORTED`: Input arguments are correct, but the driver does not support the operation. If a transparent driver returns this
Aditya Deshpandee41f7e42023-01-12 16:29:02 +000059
60**4. Include the following in one of the driver header files:**
61```
62#if defined(DRIVER_PREFIX_ENABLED)
63#ifndef PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
64#define PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
65#endif
66```
67
68**5. Conditionally include header files required by the driver**
69Include any header files required by the driver in `psa_crypto_driver_wrappers.h`, placing the `#include` statements within an `#if defined` block which checks if the driver is available:
70```
71#if defined(DRIVER_PREFIX_ENABLED)
72#include ...
73#endif
74```
75
76**6. Modify the driver wrapper function** \
77Each driver wrapper function contains a `switch` statement which checks the location of the key. If the key is stored in local storage, then operations are performed by a transparent driver. If it is stored elsewhere, then operations are performed by an opaque driver.
Aditya Deshpande277690e2023-01-18 11:27:26 +000078 * **Transparent drivers:** Calls to driver entry points go under `case PSA_KEY_LOCATION_LOCAL_STORAGE`.
79 * **Opaque Drivers** Calls to driver entry points go in a separate `case` block corresponding to the key location.
Aditya Deshpandee41f7e42023-01-12 16:29:02 +000080
81
Aditya Deshpande277690e2023-01-18 11:27:26 +000082The diagram below shows the layout of a driver wrapper function which can dispatch to two transparent drivers `Foo` and `Bar`, and one opaque driver `Baz`.
83
84 ```
85psa_driver_wrapper_xxx()
86├── switch(location)
87| |
88│ ├── case PSA_KEY_LOCATION_LOCAL_STORAGE //transparent driver
89| | ├── #if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
90| | | ├── #if defined(FOO_DRIVER_PREFIX_ENABLED)
91| | | | ├── if(//conditions for foo driver capibilities)
92| | | | ├── foo_driver_transparent_xxx() //call to driver entry point
93| | | | ├── if (status != PSA_ERROR_NOT_SUPPORTED) return status
94| | | ├── #endif
95| | | ├── #if defined(BAR_DRIVER_PREFIX_ENABLED)
96| | | | ├── if(//conditions for bar driver capibilities)
97| | | | ├── bar_driver_transparent_xxx() //call to driver entry point
98| | | | ├── if (status != PSA_ERROR_NOT_SUPPORTED) return status
99| | | ├── #endif
100| | ├── #endif
101| |
102│ ├── case SECURE_ELEMENT_LOCATION //opaque driver
103| | ├── #if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
104| | | ├── #if defined(BAZ_DRIVER_PREFIX_ENABLED)
105| | | | ├── if(//conditions for baz driver capibilities)
106| | | | ├── baz_driver_opaque_xxx() //call to driver entry point
107| | | | ├── if (status != PSA_ERROR_NOT_SUPPORTED) return status
108| | | ├── #endif
109| | ├── #endif
110└── return psa_xxx_builtin() // fall back to built in implementation
111 ```
Aditya Deshpandee41f7e42023-01-12 16:29:02 +0000112
113
Aditya Deshpande277690e2023-01-18 11:27:26 +0000114All code related to driver calls within each `case` must be contained between `#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)` and a corresponding `#endif`. Within this block, each individual driver's compatibility checks and call to the entry point must be contained between `#if defined(DRIVER_PREFIX_ENABLED)` and a corresponding `#endif`. Checks that involve accessing key material using PSA macros, such as determining the key type or number of bits, must be done in the driver wrapper.
115
116**7. Build Mbed TLS with the driver**
117This guide assumes you are building Mbed TLS from source alongside your project. If building with a driver present, the chosen driver macro (`DRIVER_PREFIX_ENABLED`) must be defined. This can be done in two ways:
118* *At compile time via flags.* This is the preferred option when your project uses Mbed TLS mostly out-of-the-box without significantly modifying the configuration. When building with Make this can be done by passing the macro name to Make with the `-D` flag. When building with CMake this can be done by modifying `CMakeLists.txt`.
119* *Providing a user config file.* This is the preferred option when your project requires a custom configuration that is significantly different to the default. Define the macro for the driver, along with any other custom configurations in a separate header file, then use `config.py`, to set `MBEDTLS_USER_CONFIG_FILE`, providing the path to the defined header file. This will include your custom config file after the default. If you wish to completely replace the default config file, set `MBEDTLS_CONFIG_FILE` instead.
Aditya Deshpandeabf4bf32023-01-23 14:47:03 +0000120
121### Example: Manually integrating a software accelerator alongside Mbed TLS
122
123[p256-m](https://github.com/mpg/p256-m) is a minimalistic implementation of ECDH and ECDSA on NIST P-256 curves, specifically optimized for use in constrained 32-bit environments. As such, it serves as a software accelerator. This section demonstrates the integration of `p256-m` as a transparent driver alongside Mbed TLS, serving as a guide for implementation.
124The code for p256-m can be found in `3rdparty/p256-m/p256m`. In this demonstration, p256-m is built from source alongside Mbed TLS.
125
126**1. Driver Prefix/Macro** \