This document is a proposed interface for deciding at build time which cryptographic mechanisms to include in the PSA Cryptography interface.
This is currently a proposal for Mbed TLS. It is not currently on track for standardization in PSA.
The PSA Cryptography API specification specifies the interface between a PSA Cryptography implementation and an application. The interface defines a number of categories of cryptographic algorithms (hashes, MAC, signatures, etc.). In each category, a typical implementation offers many algorithms (e.g. for signatures: RSA-PKCS#1v1.5, RSA-PSS, ECDSA). When building the implementation for a specific use case, it is often desirable to include only a subset of the available cryptographic mechanisms, primarily in order to reduce the code footprint of the compiled system.
The present document proposes a way for an application using the PSA cryptography interface to declare which mechanisms it requires.
Mbed TLS offers a way to select which cryptographic mechanisms are included in a build through its configuration file (
mbedtls_config.h). This mechanism is based on two main sets of symbols:
MBEDTLS_xxx_C controls the availability of the mechanism to the application, and
MBEDTLS_xxx_ALT controls the availability of an alternative implementation, so the software implementation is only included if
MBEDTLS_xxx_C is defined but not
In the PSA cryptography interface, the core (built-in implementations of cryptographic mechanisms) can be augmented with drivers. Transparent drivers replace the built-in implementation of a cryptographic mechanism (or, with fallback, the built-in implementation is tried if the driver only has partial support for the mechanism). Opaque drivers implement cryptographic mechanisms on keys which are stored in a separate domain such as a secure element, for which the core only does key management and dispatch using wrapped key blobs or key identifiers.
The current model is difficult to adapt to the PSA interface for several reasons. The
MBEDTLS_xxx_ALT symbols are somewhat inconsistent, and in particular do not work well for asymmetric cryptography. For example, many parts of the ECC code have no
MBEDTLS_xxx_ALT symbol, so a platform with ECC acceleration that can perform all ECDSA and ECDH operations in the accelerator would still embark the
bignum module and large parts of the
ecdsa modules. Also the availability of a transparent driver for a mechanism does not translate directly to
[Req.interface] The application can declare which cryptographic mechanisms it needs.
[Req.inclusion] If the application does not require a mechanism, a suitably configured Mbed TLS build must not include it. The granularity of mechanisms must work for typical use cases and has acceptable limitations.
[Req.drivers] If a PSA driver is available in the build, a suitably configured Mbed TLS build must not include the corresponding software code (unless a software fallback is needed).
[Req.c] The configuration mechanism consists of C preprocessor definitions, and the build does not require tools other than a C compiler. This is necessary to allow building an application and Mbed TLS in development environments that do not allow third-party tools.
[Req.adaptability] The implementation of the mechanism must be adaptable with future evolution of the PSA cryptography specifications and Mbed TLS. Therefore the interface must remain sufficiently simple and abstract.
[Limitation.matrix] If a mechanism is defined by a combination of algorithms and key types, for example a block cipher mode (CBC, CTR, CFB, …) and a block permutation (AES, CAMELLIA, ARIA, …), there is no requirement to include only specific combinations.
[Limitation.direction] For mechanisms that have multiple directions (for example encrypt/decrypt, sign/verify), there is no requirement to include only one direction.
[Limitation.size] There is no requirement to include only support for certain key sizes.
[Limitation.multipart] Where there are multiple ways to perform an operation, for example single-part and multi-part, there is no mechanism to select only one or a subset of the possible ways.
The PSA Crypto configuration file
psa/crypto_config.h defines a series of symbols of the form
xxx describes the feature that the symbol enables. The symbols are documented in the section “PSA Crypto configuration symbols” below.
mbedtls/mbedtls_config.h determines whether
psa/crypto_config.h is used.
MBEDTLS_PSA_CRYPTO_CONFIGis unset, which is the default at least in Mbed TLS 2.x versions, things are as they are today: the PSA subsystem includes generic code unconditionally, and includes support for specific mechanisms conditionally based on the existing
MBEDTLS_PSA_CRYPTO_CONFIGis set, the necessary software implementations of cryptographic algorithms are included based on both the content of the PSA Crypto configuration file and the Mbed TLS configuration file. For example, the code in
aes.cis enabled if either
A PSA Crypto configuration symbol is a C preprocessor symbol whose name starts with
1, the corresponding feature is included.
The presence of a symbol
PSA_WANT_xxx in the Mbed TLS configuration determines whether a feature is available through the PSA API. These symbols should be used in any place that requires conditional compilation based on the availability of a cryptographic mechanism through the PSA API, including:
MBEDTLS_USE_PSA_CRYPTO, for example in TLS to determine which cipher suites to enable.
If a feature is not requested for inclusion in the PSA Crypto configuration file, it may still be included in the build, either because the feature has been requested in some other way, or because the library does not support the exclusion of this feature. Mbed TLS should make a best effort to support the exclusion of all features, but in some cases this may be judged too much effort for too little benefit.
For each constant or constructor macro of the form
PSA_KEY_TYPE_xxx, the symbol
PSA_WANT_KEY_TYPE_xxx indicates that support for this key type is desired.
For asymmetric cryptography,
PSA_WANT_KEY_TYPE_xxx_KEY_PAIR determines whether private-key operations are desired, and
PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY determines whether public-key operations are desired.
PSA_WANT_KEY_TYPE_xxx_KEY_PAIR implicitly enables
PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY: there is no way to only include private-key operations (which typically saves little code).
For elliptic curve key types, only the specified curves are included. To include a curve, include a symbol of the form
PSA_WANT_ECC_family_size. For example:
PSA_WANT_ECC_SECP_R1_256 for secp256r1,
PSA_WANT_ECC_MONTGOMERY_255 for Curve25519. It is an error to require an ECC key type but no curve, and Mbed TLS will reject this at compile time.
Rationale: this is a deviation of the general principle that
PSA_ECC_FAMILY_xxx would have a corresponding symbol
PSA_WANT_ECC_FAMILY_xxx. This deviation is justified by the fact that it is very common to wish to include only certain curves in a family, and that can lead to a significant gain in code size.
There are no configuration symbols for Diffie-Hellman groups (
Rationale: Finite-field Diffie-Hellman code is usually not specialized for any particular group, so reducing the number of available groups at compile time only saves a little code space. Constrained implementations tend to omit FFDH anyway, so the small code size gain is not important.
For each constant or constructor macro of the form
PSA_ALG_xxx, the symbol
PSA_WANT_ALG_xxx indicates that support for this algorithm is desired.
For parametrized algorithms, the
PSA_WANT_ALG_xxx symbol indicates whether the base mechanism is supported. Parameters must themselves be included through their own
PSA_WANT_ALG_xxx symbols. It is an error to include a base mechanism without at least one possible parameter, and Mbed TLS will reject this at compile time. For example,
PSA_WANT_ALG_ECDSA requires the inclusion of randomized ECDSA for all hash algorithms whose corresponding symbol
PSA_WANT_ALG_xxx is enabled.
In addition to the configuration symbols, we need two parallel or mostly parallel sets of symbols:
MBEDTLS_PSA_ACCEL_xxxindicates whether a fully-featured, fallback-free transparent driver is available.
MBEDTLS_PSA_BUILTIN_xxxindicates whether the software implementation is needed.
MBEDTLS_PSA_ACCEL_xxx is one of the outputs of the transpilation of a driver description, alongside the glue code for calling the drivers.
MBEDTLS_PSA_BUILTIN_xxx is enabled when
PSA_WANT_xxx is enabled and
MBEDTLS_PSA_ACCEL_xxx is disabled.
These symbols are not part of the public interface of Mbed TLS towards applications or to drivers, regardless of whether the symbols are actually visible.
MBEDTLS_PSA_CRYPTO_CONFIG is set, the header file
mbedtls/mbedtls_config.h needs to define all the
MBEDTLS_xxx_C configuration symbols, including the ones deduced from the PSA Crypto configuration. It does this by including the new header file
mbedtls/config_psa.h, which defines the
MBEDTLS_PSA_BUILTIN_xxx symbols and deduces the corresponding
MBEDTLS_xxx_C (and other) symbols.
psa/crypto_config.h, the user-editable file that defines application requirements.
MBEDTLS_PSA_CRYPTO_CONFIG is not set, the configuration of Mbed TLS works as before, and the inclusion of non-PSA code only depends on
MBEDTLS_xxx symbols defined (or not) in
mbedtls/mbedtls_config.h. Furthermore, the new header file
mbedtls/config_psa.h deduces PSA configuration symbols (
MBEDTLS_PSA_BUILTIN_xxx) from classic configuration symbols (
PSA_WANT_xxx definitions in
mbedtls/config_psa.h are needed not only to build the PSA parts of the library, but also to build code that uses these parts. This includes structure definitions in
psa/crypto_struct.h, size calculations in
psa/crypto_sizes.h, and application code that's specific to a given cryptographic mechanism. In Mbed TLS itself, code under
MBEDTLS_USE_PSA_CRYPTO and conditional compilation guards in tests and sample programs need
Since some existing applications use a handwritten
mbedtls/mbedtls_config.h or an edited copy of
mbedtls/mbedtls_config.h from an earlier version of Mbed TLS,
mbedtls/config_psa.h must be included via an already existing header that is not
mbedtls/mbedtls_config.h, so it is included via
psa/crypto.h (for example from
MBEDTLS_PSA_CRYPTO_CONFIG is set or not,
mbedtls/crypto_drivers.h, a header file generated by the transpilation of the driver descriptions. It defines
MBEDTLS_PSA_ACCEL_xxx symbols according to the availability of transparent drivers without fallback.
The following table summarizes where symbols are defined depending on the configuration mode.
|Symbols||With ||Without |
MBEDTLS_PSA_BUILTIN_xxx symbols should not be visible to application code or driver code, since they are not part of the public interface of the library. However these symbols are needed to deduce whether to include library modules (for example
MBEDTLS_AES_C has to be enabled if
MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES is enabled), which makes it difficult to keep them private.
The header file
library/psa_check_config.h applies sanity checks to the configuration, throwing
#error if something is wrong.
A mechanism similar to
mbedtls/check_config.h detects errors such as enabling ECDSA but no curve.
Since configuration symbols must be undefined or 1, any other value should trigger an
A lot of the preprocessor symbol manipulation is systematic calculations that analyze the configuration.
library/psa_check_config.h should be generated automatically, in the same manner as
An entry point can be eliminated entirely if no algorithm requires it.
Code that is specific to certain key types or to certain algorithms must be guarded by the applicable symbols:
PSA_WANT_xxx for code that is independent of the application, and
MBEDTLS_PSA_BUILTIN_xxx for code that calls an Mbed TLS software implementation.
At the time of writing, the preferred configuration mechanism for a PSA service is in JSON syntax. The translation from JSON to build instructions is not specified by PSA.
For PSA Crypto, the preferred configuration mechanism would be similar to capability specifications of transparent drivers. The same JSON properties that are used to mean “this driver can perform that mechanism” in a driver description would be used to mean “the application wants to perform that mechanism” in the application configuration.
The JSON capability language allows a more fine-grained selection than the C mechanism proposed here. For example, it allows requesting only single-part mechanisms, only certain key sizes, or only certain combinations of algorithms and key types.
The JSON capability language can be translated approximately to the boolean symbol mechanism proposed here. The approximation considers a feature to be enabled if any part of it is enabled. For example, if there is a capability for AES-CTR and one for CAMELLIA-GCM, the translation to boolean symbols will also include AES-GCM and CAMELLIA-CTR. If there is a capability for AES-128, the translation will also include AES-192 and AES-256.
The boolean symbol mechanism proposed here can be translated to a list of JSON capabilities: for each included algorithm, include a capability with that algorithm, the key types that apply to that algorithm, no size restriction, and all the entry points that apply to that algorithm.
The names of elliptic curve symbols are a bit weird:
SECP_R1_256 instead of
MONTGOMERY_255 instead of
CURVE25519. Should we make them more classical, but less systematic?
What does it mean to have
PSA_WANT_ALG_ECDSA enabled but with only Curve25519? Is it a mandatory error?
Way to request only specific groups? Not a priority: constrained devices don't do FFDH. Specify it as may change in future versions.
The two mechanisms have very different designs. Is there serious potential for confusion? Do we understand how the combinations work?
Is it realistic to mandate a compile-time error if a key type is required, but no matching algorithm, or vice versa? Is it always the right thing, for example if there is an opaque driver that manipulates this key type?
If a mechanism should only be supported in an opaque driver, what does the core need to know about it? Do we have all the information we need?
This is especially relevant to suppress a mechanism completely if there is no matching algorithm. For example, if there is no transparent implementation of RSA or ECDSA,
psa_verify_hash may still be needed if there is an opaque signature driver.
Is this proposal decently testable? There are a lot of combinations. What combinations should we test?