mbedtls/docs/driver-only-builds.md
Gilles Peskine ff3b8211ff Driver-only FFDH is not good enough for DHE support in TLS 1.2
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
2024-04-30 16:20:20 +02:00

20 KiB

This document explains how to create builds of Mbed TLS where some cryptographic mechanisms are provided only by PSA drivers (that is, no built-in implementation of those algorithms), from a user's perspective.

This is useful to save code size for people who are using either a hardware accelerator, or an alternative software implementation that is more aggressively optimized for code size than the default one in Mbed TLS.

General considerations

This document assumes that you already have a working driver. Otherwise, please see the PSA driver example and guide for information on writing a driver.

In order to have some mechanism provided only by a driver, you'll want the following compile-time configuration options enabled:

  • MBEDTLS_PSA_CRYPTO_C (enabled by default) - this enables PSA Crypto.
  • MBEDTLS_USE_PSA_CRYPTO (disabled by default) - this makes PK, X.509 and TLS use PSA Crypto. You need to enable this if you're using PK, X.509 or TLS and want them to have access to the algorithms provided by your driver. (See the dedicated document for details.)
  • MBEDTLS_PSA_CRYPTO_CONFIG (disabled by default) - this enables configuration of cryptographic algorithms using PSA_WANT macros in include/psa/crypto_config.h. See Conditional inclusion of cryptographic mechanism through the PSA API in Mbed TLS for details.

In addition, for each mechanism you want provided only by your driver:

  • Define the corresponding PSA_WANT macro in psa/crypto_config.h - this means the algorithm will be available in the PSA Crypto API.
  • Define the corresponding MBEDTLS_PSA_ACCEL in your build. This could be defined in psa/crypto_config.h or your compiler's command line. This informs the PSA code that an accelerator is available for this mechanism.
  • Undefine / comment out the corresponding MBEDTLS_xxx_C macro in mbedtls/mbedtls_config.h. This ensures the built-in implementation is not included in the build.

For example, if you want SHA-256 to be provided only by a driver, you'll want PSA_WANT_ALG_SHA_256 and MBEDTLS_PSA_ACCEL_SHA_256 defined, and MBEDTLS_SHA256_C undefined.

In addition to these compile-time considerations, at runtime you'll need to make sure you call psa_crypto_init() before any function that uses the driver-only mechanisms. Note that this is already a requirement for any use of the PSA Crypto API, as well as for use of the PK, X.509 and TLS modules when MBEDTLS_USE_PSA_CRYPTO is enabled, so in most cases your application will already be doing this.

Mechanisms covered

For now, only the following (families of) mechanisms are supported:

  • hashes: SHA-3, SHA-2, SHA-1, MD5, etc.
  • elliptic-curve cryptography (ECC): ECDH, ECDSA, EC J-PAKE, ECC key types.
  • finite-field Diffie-Hellman: FFDH algorithm, DH key types.
  • RSA: PKCS#1 v1.5 and v2.1 signature and encryption algorithms, RSA key types (for now, only crypto, no X.509 or TLS support).
  • AEADs:
    • GCM and CCM with AES, ARIA and Camellia key types
    • ChachaPoly with ChaCha20 Key type
  • Unauthenticated ciphers:
    • key types: AES, ARIA, Camellia, DES
    • modes: ECB, CBC, CTR, CFB, OFB, XTS

For each family listed above, all the mentioned alorithms/key types are also all the mechanisms that exist in PSA API.

Supported means that when those are provided only by drivers, everything (including PK, X.509 and TLS if MBEDTLS_USE_PSA_CRYPTO is enabled) should work in the same way as if the mechanisms where built-in, except as documented in the "Limitations" sub-sections of the sections dedicated to each family below.

Hashes

It is possible to have all hash operations provided only by a driver.

More precisely:

  • you can enable PSA_WANT_ALG_SHA_256 without MBEDTLS_SHA256_C, provided you have MBEDTLS_PSA_ACCEL_ALG_SHA_256 enabled;
  • and similarly for all supported hash algorithms: MD5, RIPEMD160, SHA_1, SHA_224, SHA_256, SHA_384, SHA_512, SHA3_224, SHA3_256, SHA3_384, SHA3_512.

In such a build, all crypto operations (via the PSA Crypto API, or non-PSA APIs), as well as X.509 and TLS, will work as usual, except that direct calls to low-level hash APIs (mbedtls_sha256() etc.) are not possible for the modules that are disabled.

You need to call psa_crypto_init() before any crypto operation that uses a hash algorithm that is provided only by a driver, as mentioned in General considerations above.

If you want to check at compile-time whether a certain hash algorithm is available in the present build of Mbed TLS, regardless of whether it's provided by a driver or built-in, you should use the following macros:

  • for code that uses only the PSA Crypto API: PSA_WANT_ALG_xxx from psa/crypto.h;
  • for code that uses non-PSA crypto APIs: MBEDTLS_MD_CAN_xxx from mbedtls/config_adjust_legacy_crypto.h.

HMAC

In addition to accelerated hash operations, it is also possible to accelerate HMAC by enabling and accelerating:

  • HMAC algorithm and key type, i.e. [PSA_WANT|MBEDTLS_PSA_ACCEL]_ALG_HMAC and [PSA_WANT|MBEDTLS_PSA_ACCEL]KEY_TYPE_HMAC.
  • Required hash algorithm(s) as explained in Hashes section.

In such a build it is possible to disable legacy HMAC support by disabling MBEDTLS_MD_C and still getting crypto operations, X.509 and TLS to work as usual. Exceptions are:

  • As mentioned in Hashes direct calls to legacy lo-level hash APIs (mbedtls_sha256() etc.) will not be possible for the legacy modules that are disabled.
  • Legacy HMAC support (mbedtls_md_hmac_xxx()) won't be possible.
  • MBEDTLS_PKCS[5|7]_C, MBEDTLS_HMAC_DRBG_C and MBEDTLS_HKDF_C since they depend on the legacy implementation of HMAC.
    • disabling HMAC_DRBG_C cause deterministic ECDSA (i.e. MBEDTLS_DETERMINISTIC_ECDSA on the legacy side and PSA_WANT_ALG_DETERMINISTIC_ECDSA on the PSA one) to be not available.

Elliptic-curve cryptography (ECC)

It is possible to have most ECC operations provided only by a driver:

  • the ECDH, ECDSA and EC J-PAKE algorithms;
  • key import, export, and random generation.

More precisely, if:

  • you have driver support for ECC public and using private keys (that is, MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY and MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_BASIC are enabled), and
  • you have driver support for all ECC curves that are enabled (that is, for each PSA_WANT_ECC_xxx macro enabled, the corresponding MBEDTLS_PSA_ACCEL_ECC_xxx macros is enabled as well);

then you can:

  • enable PSA_WANT_ALG_ECDH without MBEDTLS_ECDH_C, provided MBEDTLS_PSA_ACCEL_ALG_ECDH is enabled
  • enable PSA_WANT_ALG_ECDSA without MBEDTLS_ECDSA_C, provided MBEDTLS_PSA_ACCEL_ALG_ECDSA is enabled;
  • enable PSA_WANT_ALG_JPAKE without MBEDTLS_ECJPAKE_C, provided MBEDTLS_PSA_ACCEL_ALG_JPAKE is enabled.

In addition, if:

  • none of MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_ECJPAKE_C are enabled (see conditions above), and
  • you have driver support for all enabled ECC key pair operations - that is, for each PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_xxx macro enabled, the corresponding MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_xxx macros is also enabled,

then you can also disable MBEDTLS_ECP_C. However, a small subset of it might still be included in the build, see limitations sub-section below.

In addition, if:

  • MBEDTLS_ECP_C is fully removed (see limitation sub-section below),
  • and support for RSA key types and algorithms is either fully disabled or fully provided by a driver,
  • and support for DH key types and the FFDH algorithm is either disabled or fully provided by a driver,

then you can also disable MBEDTLS_BIGNUM_C.

In such builds, all crypto operations via the PSA Crypto API will work as usual, as well as the PK, X.509 and TLS modules if MBEDTLS_USE_PSA_CRYPTO is enabled, with the following exceptions:

  • direct calls to APIs from the disabled modules are not possible;
  • PK, X.509 and TLS will not support restartable ECC operations (see limitation sub-section below).

If you want to check at compile-time whether a certain curve is available in the present build of Mbed TLS, regardless of whether ECC is provided by a driver or built-in, you should use the following macros:

  • for code that uses only the PSA Crypto API: PSA_WANT_ECC_xxx from psa/crypto.h;
  • for code that may also use non-PSA crypto APIs: MBEDTLS_ECP_HAVE_xxx from mbedtls/build_info.h where xxx can take the same values as for MBEDTLS_ECP_DP_xxx macros.

Note that for externally-provided drivers, the integrator is responsible for ensuring the appropriate MBEDTLS_PSA_ACCEL_xxx macros are defined. However, for the p256-m driver that's provided with the library, those macros are automatically defined when enabling MBEDTLS_PSA_P256M_DRIVER_ENABLED.

Limitations regarding fully removing ecp.c

A limited subset of ecp.c will still be automatically re-enabled if any of the following is enabled:

  • MBEDTLS_PK_PARSE_EC_COMPRESSED - support for parsing ECC keys where the public part is in compressed format;
  • MBEDTLS_PK_PARSE_EC_EXTENDED - support for parsing ECC keys where the curve is identified not by name, but by explicit parameters;
  • PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE - support for deterministic derivation of an ECC keypair with psa_key_derivation_output_key().

Note: when any of the above options is enabled, a subset of ecp.c will automatically be included in the build in order to support it. Therefore you can still disable MBEDTLS_ECP_C in mbedtls_config.h and this will result in some code size savings, but not as much as when none of the above features are enabled.

We do have plans to support each of these with ecp.c fully removed in the future, however there is no established timeline. If you're interested, please let us know, so we can take it into consideration in our planning.

Limitations regarding restartable / interruptible ECC operations

At the moment, there is no driver support for interruptible operations (see psa_sign_hash_start() + psa_sign_hash_complete() etc.) so as a consequence these are not supported in builds without MBEDTLS_ECDSA_C.

Similarly, there is no PSA support for interruptible ECDH operations so these are not supported without ECDH_C. See also limitations regarding restartable operations with MBEDTLS_USE_PSA_CRYPTO in its documentation.

Again, we have plans to support this in the future but not with an established timeline, please let us know if you're interested.

Limitations regarding "mixed" builds (driver and built-in)

In order for a build to be driver-only (no built-in implementation), all the requested algorithms, key types (key operations) and curves must be accelerated (plus a few other restrictions, see "Limitations regarding fully removing ecp.c" above). However, what if you have an accelerator that only supports some algorithms, some key types (key operations), or some curves, but want to have more enabled in you build?

It is possible to have acceleration for only a subset of the requested algorithms. In this case, the built-in implementation of the accelerated algorithms will be disabled, provided all the requested curves and key types that can be used with this algorithm are also declared as accelerated.

There is very limited support for having acceleration for only a subset of the requested key type operations. The only configuration that's tested is that of a driver accelerating PUBLIC_KEY, KEY_PAIR_BASIC, KEY_PAIR_IMPORT, KEY_PAIR_EXPORT but not KEY_PAIR_GENERATE. (Note: currently the driver interface does not support KEY_PAIR_DERIVE.)

There is limited support for having acceleration for only a subset of the requested curves. In such builds, only the PSA API is currently tested and working; there are known issues in PK, and X.509 and TLS are untested.

Finite-field Diffie-Hellman

Support is pretty similar to the "Elliptic-curve cryptography (ECC)" section above. Key management and usage can be enabled by means of the usual PSA_WANT + MBEDTLS_PSA_ACCEL pairs:

  • [PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_PUBLIC_KEY;
  • [PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_KEY_PAIR_BASIC;
  • [PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_KEY_PAIR_IMPORT;
  • [PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_KEY_PAIR_EXPORT;
  • [PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_KEY_PAIR_GENERATE;

The same holds for the associated algorithm: [PSA_WANT|MBEDTLS_PSA_ACCEL]_ALG_FFDH allow builds accelerating FFDH and removing builtin support (i.e. MBEDTLS_DHM_C).

Note that the PSA API only supports FFDH with RFC 7919 groups, whereas the Mbed TLS legacy API supports custom groups. As a consequence, the TLS layer of Mbed TLS only supports DHE cipher suites if built-in FFDH (MBEDTLS_DHM_C) is present, even when MBEDTLS_USE_PSA_CRYPTO is enabled.

RSA

It is possible for all RSA operations to be provided only by a driver.

More precisely, if:

  • all the RSA algorithms that are enabled (PSA_WANT_ALG_RSA_*) are also accelerated (MBEDTLS_PSA_ACCEL_ALG_RSA_*),
  • and all the RSA key types that are enabled (PSA_WANT_KEY_TYPE_RSA_*) are also accelerated (MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_*),

then you can disable MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15 and MBEDTLS_PKCS1_V21, and RSA will still work in PSA Crypto.

Limitations on RSA acceleration

Unlike other mechanisms, for now in configurations with driver-only RSA, only PSA Crypto works. In particular, PK, X.509 and TLS will not work with driver-only RSA even if MBEDTLS_USE_PSA_CRYPTO is enabled.

Currently (early 2024) we don't have plans to extend this support. If you're interested in wider driver-only support for RSA, please let us know.

Ciphers (unauthenticated and AEAD)

It is possible to have all ciphers and AEAD operations provided only by a driver. More precisely, for each desired combination of key type and algorithm/mode you can:

  • Enable desired PSA key type(s):
    • PSA_WANT_KEY_TYPE_AES,
    • PSA_WANT_KEY_TYPE_ARIA,
    • PSA_WANT_KEY_TYPE_CAMELLIA,
    • PSA_WANT_KEY_TYPE_CHACHA20,
    • PSA_WANT_KEY_TYPE_DES.
  • Enable desired PSA algorithm(s):
    • Unauthenticated ciphers modes:
      • PSA_WANT_ALG_CBC_NO_PADDING,
      • PSA_WANT_ALG_CBC_PKCS7,
      • PSA_WANT_ALG_CCM_STAR_NO_TAG,
      • PSA_WANT_ALG_CFB,
      • PSA_WANT_ALG_CTR,
      • PSA_WANT_ALG_ECB_NO_PADDING,
      • PSA_WANT_ALG_OFB,
      • PSA_WANT_ALG_STREAM_CIPHER.
    • AEADs:
      • PSA_WANT_ALG_CCM,
      • PSA_WANT_ALG_GCM,
      • PSA_WANT_ALG_CHACHA20_POLY1305.
  • Enable MBEDTLS_PSA_ACCEL_[KEY_TYPE_xxx|ALG_yyy] symbol(s) which correspond to the PSA_WANT_KEY_TYPE_xxx and PSA_WANT_ALG_yyy of the previous steps.
  • Disable builtin support of key types:
    • MBEDTLS_AES_C,
    • MBEDTLS_ARIA_C,
    • MBEDTLS_CAMELLIA_C,
    • MBEDTLS_DES_C,
    • MBEDTLS_CHACHA20_C. and algorithms/modes:
    • MBEDTLS_CBC_C,
    • MBEDTLS_CFB_C,
    • MBEDTLS_CTR_C,
    • MBEDTLS_OFB_C,
    • MBEDTLS_XTS_C,
    • MBEDTLS_CCM_C,
    • MBEDTLS_GCM_C,
    • MBEDTLS_CHACHAPOLY_C,
    • MBEDTLS_NULL_CIPHER.

Once a key type and related algorithm are accelerated, all the PSA Crypto APIs will work, as well as X.509 and TLS (with MBEDTLS_USE_PSA_CRYPTO enabled) but some non-PSA APIs will be absent or have reduced functionality, see Restrictions for details.

Restrictions

  • If an algorithm other than CCM and GCM (see "Partial acceleration for CCM/GCM" below) is enabled but not accelerated, then all key types that can be used with it will need to be built-in.
  • If a key type is enabled but not accelerated, then all algorithms that can be used with it will need to be built-in.

Some legacy modules can't take advantage of PSA drivers yet, and will either need to be disabled, or have reduced features when the built-in implementations of some ciphers are removed:

  • MBEDTLS_NIST_KW_C needs built-in AES: it must be disabled when MBEDTLS_AES_C is disabled.
  • MBEDTLS_CMAC_C needs built-in AES/DES: it must be disabled when MBEDTLS_AES_C and MBEDTLS_DES_C are both disabled. When only one of them is enabled, then only the corresponding cipher will be available at runtime for use with mbedtls_cipher_cmac_xxx. (Note: if there is driver support for CMAC and all compatible key types, then PSA_WANT_ALG_CMAC can be enabled without MBEDTLS_CMAC_C and CMAC will be usable with psa_max_xxx APIs.)
  • MBEDTLS_CIPHER_C: the mbedtls_cipher_xxx() APIs will only work with ciphers that are built-in - that is, both the underlying cipher (eg MBEDTLS_AES_C) and the mode (eg MBEDTLS_CIPHER_MODE_CBC or MBEDTLS_GCM_C).
  • MBEDTLS_PKCS5_C: encryption/decryption (PBES2, PBE) will only work with ciphers that are built-in.
  • PEM decryption will only work with ciphers that are built-in.
  • PK parse will only be able to parse encrypted keys using built-in ciphers.

Note that if you also disable MBEDTLS_CIPHER_C, there will be additional restrictions, see Disabling MBEDTLS_CIPHER_C.

Legacy <-> PSA matching

Note that the relationship between legacy (i.e. MBEDTLS_xxx_C) and PSA (i.e. PSA_WANT_xxx) symbols is not always 1:1. For example:

  • ECB mode is always enabled in the legacy configuration for each key type that allows it (AES, ARIA, Camellia, DES), whereas it must be explicitly enabled in PSA with PSA_WANT_ALG_ECB_NO_PADDING.
  • In the legacy API, MBEDTLS_CHACHA20_C enables the ChaCha20 stream cipher, and enabling MBEDTLS_CHACHAPOLY_C also enables the ChaCha20-Poly1305 AEAD. In the PSA API, you need to enable PSA_KEY_TYPE_CHACHA20 for both, plus PSA_ALG_STREAM_CIPHER or PSA_ALG_CHACHA20_POLY1305 as desired.
  • The legacy symbol MBEDTLS_CCM_C adds support for both cipher and AEAD, whereas in PSA there are 2 different symbols: PSA_WANT_ALG_CCM_STAR_NO_TAG and PSA_WANT_ALG_CCM, respectively.

Partial acceleration for CCM/GCM

[This section depends on #8598 so it might be updated while that PR progresses.]

In case legacy CCM/GCM algorithms are enabled, it is still possible to benefit from PSA acceleration of the underlying block cipher by enabling support for ECB mode (PSA_WANT_ALG_ECB_NO_PADDING + MBEDTLS_PSA_ACCEL_ALG_ECB_NO_PADDING) together with desired key type(s) (PSA_WANT_KEY_TYPE_[AES|ARIA|CAMELLIA] + MBEDTLS_PSA_ACCEL_KEY_TYPE_[AES|ARIA|CAMELLIA]).

In such configurations it is possible to:

  • Use CCM and GCM via the PSA Crypto APIs.
  • Use CCM and GCM via legacy functions mbedtls_[ccm|gcm]_xxx() (but not the legacy functions mbedtls_cipher_xxx()).
  • Disable legacy key types (MBEDTLS_[AES|ARIA|CAMELLIA]_C) if there is no other dependency requiring them.

ChaChaPoly has no such feature, so it requires full acceleration (key type + algorithm) in order to work with a driver.

CTR-DRBG

The legacy CTR-DRBG module (enabled by MBEDTLS_CTR_DRBG_C) can also benefit from PSA acceleration if both of the following conditions are met:

  • The legacy AES module (MBEDTLS_AES_C) is not enabled and
  • AES is supported on the PSA side together with ECB mode, i.e. PSA_WANT_KEY_TYPE_AES + PSA_WANT_ALG_ECB_NO_PADDING.

Disabling MBEDTLS_CIPHER_C

It is possible to save code size by disabling MBEDTLS_CIPHER_C when all of the following conditions are met:

  • The application is not using the mbedtls_cipher_ API.
  • In PSA, all unauthenticated (that is, non-AEAD) ciphers are either disabled or fully accelerated (that is, all compatible key types are accelerated too).
  • Either TLS is disabled, or MBEDTLS_USE_PSA_CRYPTO is enabled.
  • MBEDTLS_NIST_KW is disabled.
  • MBEDTLS_CMAC_C is disabled. (Note: support for CMAC in PSA can be provided by a driver.)

In such a build, everything will work as usual except for the following:

  • Encryption/decryption functions from the PKCS5 and PKCS12 module will not be available (only key derivation functions).
  • Parsing of PKCS5- or PKCS12-encrypted keys in PK parse will fail.

Note: AEAD ciphers (CCM, GCM, ChachaPoly) do not have a dependency on MBEDTLS_CIPHER_C even when using the built-in implementations.

If you also have some ciphers fully accelerated and the built-ins removed, see Restrictions for restrictions related to removing the built-ins.