mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2025-04-01 13:20:30 +00:00
Merge pull request #9818 from yanesca/remove_USE_PSA_from_standalone_doc_9632
Remove discussions of MBEDTLS_USE_PSA_CRYPTO in standalone documentation
This commit is contained in:
commit
3c4c647328
@ -1,9 +1,10 @@
|
||||
Default behavior changes
|
||||
* The PK, X.509, PKCS7 and TLS modules now always use the PSA subsystem
|
||||
to perform cryptographic operations, with a few exceptions documented
|
||||
in docs/use-psa-crypto.md. This corresponds to the behavior of
|
||||
Mbed TLS 3.x when MBEDTLS_USE_PSA_CRYPTO is enabled. In effect,
|
||||
MBEDTLS_USE_PSA_CRYPTO is now always enabled.
|
||||
in docs/architecture/psa-migration/psa-limitations.md. This
|
||||
corresponds to the behavior of Mbed TLS 3.x when
|
||||
MBEDTLS_USE_PSA_CRYPTO is enabled. In effect, MBEDTLS_USE_PSA_CRYPTO
|
||||
is now always enabled.
|
||||
* psa_crypto_init() must be called before performing any cryptographic
|
||||
operation, including indirect requests such as parsing a key or
|
||||
certificate or starting a TLS handshake.
|
||||
|
@ -295,8 +295,6 @@ Arm welcomes feedback on the design of the API. If you think something could be
|
||||
Mbed TLS includes a reference implementation of the PSA Cryptography API.
|
||||
However, it does not aim to implement the whole specification; in particular it does not implement all the algorithms.
|
||||
|
||||
The X.509 and TLS code can use PSA cryptography for most operations. To enable this support, activate the compilation option `MBEDTLS_USE_PSA_CRYPTO` in `mbedtls_config.h`. Note that TLS 1.3 uses PSA cryptography for most operations regardless of this option. See `docs/use-psa-crypto.md` for details.
|
||||
|
||||
### PSA drivers
|
||||
|
||||
Mbed TLS supports drivers for cryptographic accelerators, secure elements and random generators. This is work in progress. Please note that the driver interfaces are not fully stable yet and may change without notice. We intend to preserve backward compatibility for application code (using the PSA Crypto API), but the code of the drivers may have to change in future minor releases of Mbed TLS.
|
||||
|
@ -1,612 +0,0 @@
|
||||
PSA migration strategy for hashes and ciphers
|
||||
=============================================
|
||||
|
||||
## Introduction
|
||||
|
||||
This document discusses a migration strategy for code that is not subject to `MBEDTLS_USE_PSA_CRYPTO`, is currently using legacy cryptography APIs, and should transition to PSA, without a major version change.
|
||||
|
||||
### Relationship with the main strategy document
|
||||
|
||||
This is complementary to the main [strategy document](strategy.html) and is intended as a refinement. However, at this stage, there may be contradictions between the strategy proposed here and some of the earlier strategy.
|
||||
|
||||
A difference between the original strategy and the current one is that in this work, we are not treating PSA as a black box. We can change experimental features, and we can call internal interfaces.
|
||||
|
||||
## Requirements
|
||||
|
||||
### User stories
|
||||
|
||||
#### Backward compatibility user story
|
||||
|
||||
As a developer of an application that uses Mbed TLS's interfaces (including legacy crypto),
|
||||
I want Mbed TLS to preserve backward compatibility,
|
||||
so that my code keeps working in new minor versions of Mbed TLS.
|
||||
|
||||
#### Interface design user story
|
||||
|
||||
As a developer of library code that uses Mbed TLS to perform cryptographic operations,
|
||||
I want to know which functions to call and which feature macros to check,
|
||||
so that my code works in all Mbed TLS configurations.
|
||||
|
||||
Note: this is the same problem we face in X.509 and TLS.
|
||||
|
||||
#### Hardware accelerator vendor user stories
|
||||
|
||||
As a vendor of a platform with hardware acceleration for some crypto,
|
||||
I want to build Mbed TLS in a way that uses my hardware wherever relevant,
|
||||
so that my customers maximally benefit from my hardware.
|
||||
|
||||
As a vendor of a platform with hardware acceleration for some crypto,
|
||||
I want to build Mbed TLS without software that replicates what my hardware does,
|
||||
to minimize the code size.
|
||||
|
||||
#### Maintainer user stories
|
||||
|
||||
As a maintainer of Mbed TLS,
|
||||
I want to have clear rules for when to use which interface,
|
||||
to avoid bugs in “unusual” configurations.
|
||||
|
||||
As a maintainer of Mbed TLS,
|
||||
I want to avoid duplicating code,
|
||||
because this is inefficient and error-prone.
|
||||
|
||||
### Use PSA more
|
||||
|
||||
In the long term, all code using cryptography should use PSA interfaces, to benefit from PSA drivers, allow eliminating legacy interfaces (less code size, less maintenance). However, this can't be done without breaking [backward compatibility](#backward-compatibility).
|
||||
|
||||
The goal of this work is to arrange for more non-PSA interfaces to use PSA interfaces under the hood, without breaking code in the cases where this doesn't work. Using PSA interfaces has two benefits:
|
||||
|
||||
* Where a PSA driver is available, it likely has better performance, and sometimes better security, than the built-in software implementation.
|
||||
* In many scenarios, where a PSA driver is available, this allows removing the software implementation altogether.
|
||||
* We may be able to get rid of some redundancies, for example the duplication between the implementations of HMAC in `md.c` and in `psa_crypto_mac.c`, and HKDF in `hkdf.c` and `psa_crypto.c`.
|
||||
|
||||
### Correct dependencies
|
||||
|
||||
Traditionally, to determine whether a cryptographic mechanism was available, you had to check whether the corresponding Mbed TLS module or submodule was present: `MBEDTLS_SHA256_C` for SHA256, `MBEDTLS_AES_C && MBEDTLS_CIPHER_MODE_CBC` for AES-CBC, etc. In code that uses the PSA interfaces, this needs to change to `PSA_WANT_xxx` symbols.
|
||||
|
||||
### Backward compatibility
|
||||
|
||||
All documented behavior must be preserved, except for interfaces currently described as experimental or unstable. Those interfaces can change, but we should minimize disruption by providing a transition path for reasonable use cases.
|
||||
|
||||
#### Changeable configuration options
|
||||
|
||||
The following configuration options are described as experimental, and are likely to change at least marginally:
|
||||
|
||||
* `MBEDTLS_PSA_CRYPTO_CLIENT`: “This interface is experimental and may change or be removed without notice.” In practice we don't want to remove this, but we may constrain how it's used.
|
||||
* `MBEDTLS_PSA_CRYPTO_DRIVERS`: “This interface is experimental. We intend to maintain backward compatibility with application code that relies on drivers, but the driver interfaces may change without notice.” In practice, this may mean constraints not only on how to write drivers, but also on how to integrate drivers into code that is platform code more than application code.
|
||||
|
||||
### Non-goals
|
||||
|
||||
It is not a goal at this stage to make more code directly call `psa_xxx` functions. Rather, the goal is to make more code call PSA drivers where available. How dispatch is done is secondary.
|
||||
|
||||
## Problem analysis
|
||||
|
||||
### Scope analysis
|
||||
|
||||
#### Limitations of `MBEDTLS_USE_PSA_CRYPTO`
|
||||
|
||||
The option `MBEDTLS_USE_PSA_CRYPTO` causes parts of the library to call the PSA API instead of legacy APIs for cryptographic calculations. `MBEDTLS_USE_PSA_CRYPTO` only applies to `pk.h`, X.509 and TLS. When this option is enabled, applications must call `psa_crypto_init()` before calling any of the functions in these modules.
|
||||
|
||||
In this work, we want two things:
|
||||
|
||||
* Make non-covered modules call PSA, but only [when this will actually work](#why-psa-is-not-always-possible). This effectively brings those modules to a partial use-PSA behavior (benefiting from PSA accelerators when they're usable) regardless of whether the option is enabled.
|
||||
* Call PSA when a covered module calls a non-covered module which calls another module, for example X.509 calling pk for PSS verification which calls RSA which calculates a hash ([see issue \#6497](https://github.com/Mbed-TLS/mbedtls/issues/6497)). This effectively extends the option to modules that aren't directly covered.
|
||||
|
||||
#### Classification of callers
|
||||
|
||||
We can classify code that implements or uses cryptographic mechanisms into several groups:
|
||||
|
||||
* Software implementations of primitive cryptographic mechanisms. These are not expected to change.
|
||||
* Software implementations of constructed cryptographic mechanisms (e.g. HMAC, CTR_DRBG, RSA (calling a hash for PSS/OAEP, and needing to know the hash length in PKCS1v1.5 sign/verify), …). These need to keep working whenever a legacy implementation of the auxiliary mechanism is available, regardless of whether a PSA implementation is also available.
|
||||
* Code implementing the PSA crypto interface. This is not expected to change, except perhaps to expose some internal functionality to overhauled glue code.
|
||||
* Code that's subject to `MBEDTLS_USE_PSA_CRYPTO`: `pk.h`, X.509, TLS (excluding parts specific TLS 1.3).
|
||||
* Code that always uses PSA for crypto: TLS 1.3 (except things common with 1.2), LMS.
|
||||
|
||||
For the purposes of this work, three domains emerge:
|
||||
|
||||
* **Legacy domain**: does not interact with PSA. Implementations of hashes, of cipher primitives, of arithmetic.
|
||||
* **Mixed domain**: does not currently use PSA, but should [when possible](#why-psa-is-not-always-possible). This consists of the constructed cryptographic primitives (except LMS), as well as pk, X.509 and TLS when `MBEDTLS_USE_PSA_CRYPTO` is disabled.
|
||||
* **PSA domain**: includes pk, X.509 and TLS when `MBEDTLS_USE_PSA_CRYPTO` is enabled. Also TLS 1.3, LMS.
|
||||
|
||||
#### Non-use-PSA modules
|
||||
|
||||
The following modules in Mbed TLS call another module to perform cryptographic operations which, in the long term, will be provided through a PSA interface, but cannot make any PSA-related assumption.
|
||||
|
||||
Hashes and HMAC (after the work on driver-only hashes):
|
||||
|
||||
* entropy (hashes via MD-light)
|
||||
* ECDSA (HMAC\_DRBG; `md.h` exposed through API)
|
||||
* ECJPAKE (hashes via MD-light; `md.h` exposed through API)
|
||||
* MD (hashes and HMAC)
|
||||
* HKDF (HMAC via `md.h`; `md.h` exposed through API)
|
||||
* HMAC\_DRBG (hashes and HMAC via `md.h`; `md.h` exposed through API)
|
||||
* PKCS12 (hashes via MD-light)
|
||||
* PKCS5 (HMAC via `md.h`; `md.h` exposed through API)
|
||||
* PKCS7 (hashes via MD)
|
||||
* RSA (hash via MD-light for PSS and OAEP; `md.h` exposed through API)
|
||||
* PEM (MD5 hash via MD-light)
|
||||
|
||||
Symmetric ciphers and AEADs (before work on driver-only cipher):
|
||||
|
||||
* PEM:
|
||||
* AES, DES or 3DES in CBC mode without padding, decrypt only (!).
|
||||
* Currently using low-level non-generic APIs.
|
||||
* No hard dependency, features guarded by `AES_C` resp. `DES_C`.
|
||||
* Functions called: `setkey_dec()` + `crypt_cbc()`.
|
||||
* PKCS12:
|
||||
* In practice: 2DES or 3DES in CBC mode with PKCS7 padding, decrypt only
|
||||
(when called from pkparse).
|
||||
* In principle: any cipher-mode (default padding), passed an
|
||||
`mbedtls_cipher_type_t` as an argument, no documented restriction.
|
||||
* Cipher, generically, selected from ASN.1 or function parameters;
|
||||
no documented restriction but in practice TODO (inc. padding and
|
||||
en/decrypt, look at standards and tests)
|
||||
* Unconditional dependency on `CIPHER_C` in `check_config.h`.
|
||||
* Note: `cipher.h` exposed through API.
|
||||
* Functions called: `setup`, `setkey`, `set_iv`, `reset`, `update`, `finish` (in sequence, once).
|
||||
* PKCS5 (PBES2, `mbedtls_pkcs5_pbes2()`):
|
||||
* 3DES or DES in CBC mode with PKCS7 padding, both encrypt and decrypt.
|
||||
* Note: could also be AES in the future, see #7038.
|
||||
* Unconditional dependency on `CIPHER_C` in `check_config.h`.
|
||||
* Functions called: `setup`, `setkey`, `crypt`.
|
||||
* CTR\_DRBG:
|
||||
* AES in ECB mode, encrypt only.
|
||||
* Currently using low-level non-generic API (`aes.h`).
|
||||
* Unconditional dependency on `AES_C` in `check_config.h`.
|
||||
* Functions called: `setkey_enc`, `crypt_ecb`.
|
||||
* CCM:
|
||||
* AES, Camellia or Aria in ECB mode, encrypt only.
|
||||
* Unconditional dependency on `AES_C || CAMELLIA_C || ARIA_C` in `check_config.h`.
|
||||
* Unconditional dependency on `CIPHER_C` in `check_config.h`.
|
||||
* Note: also called by `cipher.c` if enabled.
|
||||
* Functions called: `info`, `setup`, `setkey`, `update` (several times) - (never finish)
|
||||
* CMAC:
|
||||
* AES or DES in ECB mode, encrypt only.
|
||||
* Unconditional dependency on `AES_C || DES_C` in `check_config.h`.
|
||||
* Unconditional dependency on `CIPHER_C` in `check_config.h`.
|
||||
* Note: also called by `cipher.c` if enabled.
|
||||
* Functions called: `info`, `setup`, `setkey`, `update` (several times) - (never finish)
|
||||
* GCM:
|
||||
* AES, Camellia or Aria in ECB mode, encrypt only.
|
||||
* Unconditional dependency on `AES_C || CAMELLIA_C || ARIA_C` in `check_config.h`.
|
||||
* Unconditional dependency on `CIPHER_C` in `check_config.h`.
|
||||
* Note: also called by `cipher.c` if enabled.
|
||||
* Functions called: `info`, `setup`, `setkey`, `update` (several times) - (never finish)
|
||||
* NIST\_KW:
|
||||
* AES in ECB mode, both encryt and decrypt.
|
||||
* Unconditional dependency on `AES_C || DES_C` in `check_config.h`.
|
||||
* Unconditional dependency on `CIPHER_C` in `check_config.h`.
|
||||
* Note: also called by `cipher.c` if enabled.
|
||||
* Note: `cipher.h` exposed through API.
|
||||
* Functions called: `info`, `setup`, `setkey`, `update` (several times) - (never finish)
|
||||
* Cipher:
|
||||
* potentially any cipher/AEAD in any mode and any direction
|
||||
|
||||
Note: PSA cipher is built on Cipher, but PSA AEAD directly calls the underlying AEAD modules (GCM, CCM, ChachaPoly).
|
||||
|
||||
### Difficulties
|
||||
|
||||
#### Why PSA is not always possible
|
||||
|
||||
Here are some reasons why calling `psa_xxx()` to perform a hash or cipher calculation might not be desirable in some circumstances, explaining why the application would arrange to call the legacy software implementation instead.
|
||||
|
||||
* `MBEDTLS_PSA_CRYPTO_C` is disabled.
|
||||
* There is a PSA driver which has not been initialized (this happens in `psa_crypto_init()`).
|
||||
* For ciphers, the keystore is not initialized yet, and Mbed TLS uses a custom implementation of PSA ITS where the file system is not accessible yet (because something else needs to happen first, and the application takes care that it happens before it calls `psa_crypto_init()`). A possible workaround may be to dispatch to the internal functions that are called after the keystore lookup, rather than to the PSA API functions (but this is incompatible with `MBEDTLS_PSA_CRYPTO_CLIENT`).
|
||||
* The requested mechanism is enabled in the legacy interface but not in the PSA interface. This was not really intended, but is possible, for example, if you enable `MBEDTLS_MD5_C` for PEM decoding with PBKDF1 but don't want `PSA_ALG_WANT_MD5` because it isn't supported for `PSA_ALG_RSA_PSS` and `PSA_ALG_DETERMINISTIC_ECDSA`.
|
||||
* `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled, and the client has not yet activated the connection to the server (this happens in `psa_crypto_init()`).
|
||||
* `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled, but the operation is part of the implementation of an encrypted communication with the crypto service, or the local implementation is faster because it avoids a costly remote procedure call.
|
||||
|
||||
#### Indirect knowledge
|
||||
|
||||
Consider for example the code in `rsa.c` to perform an RSA-PSS signature. It needs to calculate a hash. If `mbedtls_rsa_rsassa_pss_sign()` is called directly by application code, it is supposed to call the built-in implementation: calling a PSA accelerator would be a behavior change, acceptable only if this does not add a risk of failure or performance degradation ([PSA is impossible or undesirable in some circumstances](#why-psa-is-not-always-possible)). Note that this holds regardless of the state of `MBEDTLS_USE_PSA_CRYPTO`, since `rsa.h` is outside the scope of `MBEDTLS_USE_PSA_CRYPTO`. On the other hand, if `mbedtls_rsa_rsassa_pss_sign()` is called from X.509 code, it should use PSA to calculate hashes. It doesn't, currently, which is [bug \#6497](https://github.com/Mbed-TLS/mbedtls/issues/6497).
|
||||
|
||||
Generally speaking, modules in the mixed domain:
|
||||
|
||||
* must call PSA if called by a module in the PSA domain;
|
||||
* must not call PSA (or must have a fallback) if their caller is not in the PSA domain and the PSA call is not guaranteed to work.
|
||||
|
||||
#### Non-support guarantees: requirements
|
||||
|
||||
Generally speaking, just because some feature is not enabled in `mbedtls_config.h` or `psa_config.h` doesn't guarantee that it won't be enabled in the build. We can enable additional features through `build_info.h`.
|
||||
|
||||
If `PSA_WANT_xxx` is disabled, this should guarantee that attempting xxx through the PSA API will fail. This is generally guaranteed by the test suite `test_suite_psa_crypto_not_supported` with automatically enumerated test cases, so it would be inconvenient to carve out an exception.
|
||||
|
||||
### Technical requirements
|
||||
|
||||
Based on the preceding analysis, the core of the problem is: for code in the mixed domain (see [“Classification of callers”](#classification-of-callers)), how do we handle a cryptographic mechanism? This has several related subproblems:
|
||||
|
||||
* How the mechanism is encoded (e.g. `mbedtls_md_type_t` vs `const *mbedtls_md_info_t` vs `psa_algorithm_t` for hashes).
|
||||
* How to decide whether a specific algorithm or key type is supported (eventually based on `MBEDTLS_xxx_C` vs `PSA_WANT_xxx`).
|
||||
* How to obtain metadata about algorithms (e.g. hash/MAC/tag size, key size).
|
||||
* How to perform the operation (context type, which functions to call).
|
||||
|
||||
We need a way to decide this based on the available information:
|
||||
|
||||
* Who's the ultimate caller — see [indirect knowledge](#indirect-knowledge) — which is not actually available.
|
||||
* Some parameter indicating which algorithm to use.
|
||||
* The available cryptographic implementations, based on preprocessor symbols (`MBEDTLS_xxx_C`, `PSA_WANT_xxx`, `MBEDTLS_PSA_ACCEL_xxx`, etc.).
|
||||
* Possibly additional runtime state (for example, we might check whether `psa_crypto_init` has been called).
|
||||
|
||||
And we need to take care of the [the cases where PSA is not possible](#why-psa-is-not-always-possible): either make sure the current behavior is preserved, or (where allowed by backward compatibility) document a behavior change and, preferably, a workaround.
|
||||
|
||||
### Working through an example: RSA-PSS
|
||||
|
||||
Let us work through the example of RSA-PSS which calculates a hash, as in [see issue \#6497](https://github.com/Mbed-TLS/mbedtls/issues/6497).
|
||||
|
||||
RSA is in the [mixed domain](#classification-of-callers). So:
|
||||
|
||||
* When called from `psa_sign_hash` and other PSA functions, it must call the PSA hash accelerator if there is one.
|
||||
* When called from user code, it must call the built-in hash implementation if PSA is not available (regardless of whether this is because `MBEDTLS_PSA_CRYPTO_C` is disabled, or because `PSA_WANT_ALG_xxx` is disabled for this hash, or because there is an accelerator driver which has not been initialized yet).
|
||||
|
||||
RSA knows which hash algorithm to use based on a parameter of type `mbedtls_md_type_t`. (More generally, all mixed-domain modules that take an algorithm specification as a parameter take it via a numerical type, except HMAC\_DRBG and HKDF which take a `const mbedtls_md_info_t*` instead, and CMAC which takes a `const mbedtls_cipher_info_t *`.)
|
||||
|
||||
#### Double encoding solution
|
||||
|
||||
A natural solution is to double up the encoding of hashes in `mbedtls_md_type_t`. Pass `MBEDTLS_MD_SHA256` and `md` will dispatch to the legacy code, pass a new constant `MBEDTLS_MD_SHA256_USE_PSA` and `md` will dispatch through PSA.
|
||||
|
||||
This maximally preserves backward compatibility, but then no non-PSA code benefits from PSA accelerators, and there's little potential for removing the software implementation.
|
||||
|
||||
#### Availability of hashes in RSA-PSS
|
||||
|
||||
Here we try to answer the question: As a caller of RSA-PSS via `rsa.h`, how do I know whether it can use a certain hash?
|
||||
|
||||
* For a caller in the legacy domain: if e.g. `MBEDTLS_SHA256_C` is enabled, then I want RSA-PSS to support SHA-256. I don't care about negative support. So `MBEDTLS_SHA256_C` must imply support for RSA-PSS-SHA-256. It must work at all times, regardless of the state of PSA (e.g. drivers not initialized).
|
||||
* For a caller in the PSA domain: if e.g. `PSA_WANT_ALG_SHA_256` is enabled, then I want RSA-PSS to support SHA-256, provided that `psa_crypto_init()` has been called. In some limited cases, such as `test_suite_psa_crypto_not_supported` when PSA implements RSA-PSS in software, we care about negative support: if `PSA_WANT_ALG_SHA_256` is disabled then `psa_verify_hash` must reject `PSA_WANT_ALG_SHA_256`. This can be done at the level of PSA before it calls the RSA module, though, so it doesn't have any implication on the RSA module. As far as `rsa.c` is concerned, what matters is that `PSA_WANT_ALG_SHA_256` implies that SHA-256 is supported after `psa_crypto_init()` has been called.
|
||||
* For a caller in the mixed domain: requirements depend on the caller. Whatever solution RSA has to determine the availability of algorithms will apply to its caller as well.
|
||||
|
||||
Conclusion so far: RSA must be able to do SHA-256 if either `MBEDTLS_SHA256_C` or `PSA_WANT_ALG_SHA_256` is enabled. If only `PSA_WANT_ALG_SHA_256` and not `MBEDTLS_SHA256_C` is enabled (which implies that PSA's SHA-256 comes from an accelerator driver), then SHA-256 only needs to work if `psa_crypto_init()` has been called.
|
||||
|
||||
#### More in-depth discussion of compile-time availability determination
|
||||
|
||||
The following combinations of compile-time support are possible:
|
||||
|
||||
* `MBEDTLS_PSA_CRYPTO_CLIENT`. Then calling PSA may or may not be desirable for performance. There are plausible use cases where only the server has access to an accelerator so it's best to call the server, and plausible use cases where calling the server has overhead that negates the savings from using acceleration, if there are savings at all. In any case, calling PSA only works if the connection to the server has been established, meaning `psa_crypto_init` has been called successfully. In the rest of this case enumeration, assume `MBEDTLS_PSA_CRYPTO_CLIENT` is disabled.
|
||||
* No PSA accelerator. Then just call `mbedtls_sha256`, it's all there is, and it doesn't matter (from an API perspective) exactly what call chain leads to it.
|
||||
* PSA accelerator, no software implementation. Then we might as well call the accelerator, unless it's important that the call fails. At the time of writing, I can't think of a case where we would want to guarantee that if `MBEDTLS_xxx_C` is not enabled, but xxx is enabled through PSA, then a request to use algorithm xxx through some legacy interface must fail.
|
||||
* Both PSA acceleration and the built-in implementation. In this case, we would prefer PSA for the acceleration, but we can only do this if the accelerator driver is working. For hashes, it's enough to assume the driver is initialized; we've [considered requiring hash drivers to work without initialization](https://github.com/Mbed-TLS/mbedtls/pull/6470). For ciphers, this is more complicated because the cipher functions require the keystore, and plausibly a cipher accelerator might want entropy (for side channel countermeasures) which might not be available at boot time.
|
||||
|
||||
Note that it's a bit tricky to determine which algorithms are available. In the case where there is a PSA accelerator but no software implementation, we don't want the preprocessor symbols to indicate that the algorithm is available through the legacy domain, only through the PSA domain. What does this mean for the interfaces in the mixed domain? They can't guarantee the availability of the algorithm, but they must try if requested.
|
||||
|
||||
### Designing an interface for hashes
|
||||
|
||||
In this section, we specify a hash metadata and calculation for the [mixed domain](#classification-of-callers), i.e. code that can be called both from legacy code and from PSA code.
|
||||
|
||||
#### Availability of hashes
|
||||
|
||||
Generalizing the analysis in [“Availability of hashes in RSA-PSS”](#availability-of-hashes-in-RSA-PSS):
|
||||
|
||||
A hash is available through the mixed-domain interface iff either of the following conditions is true:
|
||||
|
||||
* A legacy hash interface is available and the hash algorithm is implemented in software.
|
||||
* PSA crypto is enabled and the hash algorithm is implemented via PSA.
|
||||
|
||||
We could go further and make PSA accelerators available to legacy callers that call any legacy hash interface, e.g. `md.h` or `shaX.h`. There is little point in doing this, however: callers should just use the mixed-domain interface.
|
||||
|
||||
#### Implications between legacy availability and PSA availability
|
||||
|
||||
There is no mandatory relationship between PSA support and legacy support for a mechanism. Users can configure legacy support and PSA support independently. Legacy support is automatically enabled if PSA support is requested, but only if there is no accelerator.
|
||||
|
||||
It is strongly desirable to allow mechanisms available through PSA but not legacy: this allows saving code size when an accelerator is present.
|
||||
|
||||
There is no strong reason to allow mechanisms available through legacy but not PSA when `MBEDTLS_PSA_CRYPTO_C` is enabled. This would only save at best a very small amount of code size in the PSA dispatch code. This may be more desirable when `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled (having a mechanism available only locally and not in the crypto service), but we do not have an explicit request for this and it would be entirely reasonable to forbid it.
|
||||
|
||||
In this analysis, we have not found a compelling reason to require all legacy mechanisms to also be available through PSA. However, this can simplify both the implementation and the use of dispatch code thanks to some simplifying properties:
|
||||
|
||||
* Mixed-domain code can call PSA code if it knows that `psa_crypto_init()` has been called, without having to inspect the specifics of algorithm support.
|
||||
* Mixed-domain code can assume that PSA buffer calculations work correctly for all algorithms that it supports.
|
||||
|
||||
#### Shape of the mixed-domain hash interface
|
||||
|
||||
We now need to create an abstraction for mixed-domain hash calculation. (We could not create an abstraction, but that would require every piece of mixed-domain code to replicate the logic here. We went that route in Mbed TLS 3.3, but it made it effectively impossible to get something that works correctly.)
|
||||
|
||||
Requirements: given a hash algorithm,
|
||||
|
||||
* Obtain some metadata about it (size, block size).
|
||||
* Calculate the hash.
|
||||
* Set up a multipart operation to calculate the hash. The operation must support update, finish, reset, abort, clone.
|
||||
|
||||
The existing interface in `md.h` is close to what we want, but not perfect. What's wrong with it?
|
||||
|
||||
* It has an extra step of converting from `mbedtls_md_type_t` to `const mbedtls_md_info_t *`.
|
||||
* It includes extra fluff such as names and HMAC. This costs code size.
|
||||
* The md module has some legacy baggage dating from when it was more open, which we don't care about anymore. This may cost code size.
|
||||
|
||||
These problems are easily solvable.
|
||||
|
||||
* `mbedtls_md_info_t` can become a very thin type. We can't remove the extra function call from the source code of callers, but we can make it a very thin abstraction that compilers can often optimize.
|
||||
* We can make names and HMAC optional. The mixed-domain hash interface won't be the full `MBEDTLS_MD_C` but a subset.
|
||||
* We can optimize `md.c` without making API changes to `md.h`.
|
||||
|
||||
### Scope reductions and priorities for 3.x
|
||||
|
||||
This section documents things that we chose to temporarily exclude from the scope in the 3.x branch (which will eventually be in scope again after 4.0) as well as things we chose to prioritize if we don't have time to support everything.
|
||||
|
||||
#### Don't support PK, X.509 and TLS without `MBEDTLS_USE_PSA_CRYPTO`
|
||||
|
||||
We do not need to support driver-only hashes and ciphers in PK. X.509 and TLS without `MBEDTLS_USE_PSA_CRYPTO`. Users who want to take full advantage of drivers will need to enabled this macro.
|
||||
|
||||
Note that this applies to TLS 1.3 as well, as some uses of hashes and all uses of ciphers there are common with TLS 1.2, hence governed by `MBEDTLS_USE_PSA_CRYPTO`, see [this macro's extended documentation](../../docs/use-psa-crypto.html).
|
||||
|
||||
This will go away naturally in 4.0 when this macros is not longer an option (because it's always on).
|
||||
|
||||
#### Don't support for `MBEDTLS_PSA_CRYPTO_CLIENT` without `MBEDTLS_PSA_CRYPTO_C`
|
||||
|
||||
We generally don't really support builds with `MBEDTLS_PSA_CRYPTO_CLIENT` without `MBEDTLS_PSA_CRYPTO_C`. For example, both `MBEDTLS_USE_PSA_CRYPTO` and `MBEDTLS_SSL_PROTO_TLS1_3` require `MBEDTLS_PSA_CRYPTO_C`, while in principle they should only require `MBEDTLS_PSA_CRYPTO_CLIENT`.
|
||||
|
||||
Considering this existing restriction which we do not plan to lift before 4.0, it is acceptable driver-only hashes and cipher support to have the same restriction in 3.x.
|
||||
|
||||
It is however desirable for the design to keep support for `MBEDTLS_PSA_CRYPTO_CLIENT` in mind, in order to avoid making it more difficult to add in the future.
|
||||
|
||||
#### For cipher: prioritize constrained devices and modern TLS
|
||||
|
||||
The primary target is a configuration like TF-M's medium profile, plus TLS with only AEAD ciphersuites.
|
||||
|
||||
This excludes things like:
|
||||
- Support for encrypted PEM, PKCS5 and PKCS12 encryption, and PKCS8 encrypted keys in PK parse. (Not widely used on highly constrained devices.)
|
||||
- Support for NIST-KW. (Same justification.)
|
||||
- Support for CMAC. (Same justification, plus can be directly accelerated.)
|
||||
- Support for CBC ciphersuites in TLS. (They've been recommended against for a while now.)
|
||||
|
||||
### Dual-dispatch for block cipher primitives
|
||||
|
||||
Considering the priorities stated above, initially we want to support GCM, CCM and CTR-DRBG. All three of them use the block cipher primitive only in the encrypt direction. Currently, GCM and CCM use the Cipher layer in order to work with AES, Aria and Camellia (DES is excluded by the standards due to its smaller block size) and CTR-DRBG directly uses the low-level API from `aes.h`. In all cases, access to the "block cipher primitive" is done by using "ECB mode" (which for both Cipher and `aes.h` only allows a single block, contrary to PSA which implements actual ECB mode).
|
||||
|
||||
The two AEAD modes, GCM and CCM, have very similar needs and positions in the stack, strongly suggesting using the same design for both. On the other hand, there are a number of differences between CTR-DRBG and them.
|
||||
- CTR-DRBG only uses AES (and there is no plan to extend it to other block ciphers at the moment), while GCM and CCM need to work with 3 block ciphers already.
|
||||
- CTR-DRBG holds a special position in the stack: most users don't care about it per se, they only care about getting random numbers - in fact PSA users don't even need to know what DRBG is used. In particular, no part of the stack is asking questions like "is CTR-DRBG-AES available?" - an RNG needs to be available and that's it - contrary to similar questions about AES-GCM etc. which are asked for example by TLS.
|
||||
|
||||
So, it makes sense to use different designs for CTR-DRBG on one hand, and GCM/CCM on the other hand:
|
||||
- CTR-DRBG can just check if `AES_C` is present and "fall back" to PSA if not.
|
||||
- GCM and CCM need an common abstraction layer that allows:
|
||||
- Using AES, Aria or Camellia in a uniform way.
|
||||
- Dispatching to built-in or driver.
|
||||
|
||||
The abstraction layer used by GCM and CCM may either be a new internal module, or a subset of the existing Cipher API, extended with the ability to dispatch to a PSA driver.
|
||||
|
||||
Reasons for making this layer's API a subset of the existing Cipher API:
|
||||
- No need to design, implement and test a new module. (Will need to test the new subset though, as well as the extended behaviour.)
|
||||
- No code change in GCM and CCM - only need to update dependencies.
|
||||
- No risk for code duplication between a potential new module and Cipher: source-level, and in in particular in builds that still have `CIPHER_C` enabled. (Compiled-code duplication could be avoided by excluding the new module in such builds, though.)
|
||||
- If want to support other users of Cipher later (such as NIST-KW, CMAC, PKCS5 and PKCS12), we can just extend dual-dispatch support to other modes/operations in Cipher and keep those extra modules unchanged as well.
|
||||
|
||||
Possible costs of re-using (a subset of) the existing Cipher API instead of defining a new one:
|
||||
- We carry over costs associated with `cipher_info_t` structures. (Currently the info structure is used for 3 things: (1) to check if the cipher is supported, (2) to check its block size, (3) because `setup()` requires it).
|
||||
- We carry over questionable implementation decisions, like dynamic allocation of context.
|
||||
|
||||
Those costs could be avoided by refactoring (parts of) Cipher, but that would probably mean either:
|
||||
- significant differences in how the `cipher.h` API is implemented between builds with the full Cipher or only a subset;
|
||||
- or more work to apply the simplifications to all of Cipher.
|
||||
|
||||
Prototyping both approaches showed better code size savings and cleaner code with a new internal module (see section "Internal "block cipher" abstraction (Cipher light)" below).
|
||||
|
||||
## Specification
|
||||
|
||||
### MD light
|
||||
|
||||
#### Definition of MD light
|
||||
|
||||
MD light is a subset of `md.h` that implements the hash calculation interface described in ”[Designing an interface for hashes](#designing-an-interface-for-hashes)”. It is activated by `MBEDTLS_MD_LIGHT` in `mbedtls_config.h`.
|
||||
|
||||
The following things enable MD light automatically in `build_info.h`:
|
||||
|
||||
* A [mixed-domain](#classification-of-callers) module that needs to calculate hashes is enabled.
|
||||
* `MBEDTLS_MD_C` is enabled.
|
||||
|
||||
MD light includes the following types:
|
||||
|
||||
* `mbedtls_md_type_t`
|
||||
* `mbedtls_md_info_t`
|
||||
* `mbedtls_md_context_t`
|
||||
|
||||
MD light includes the following functions:
|
||||
|
||||
* `mbedtls_md_info_from_type`
|
||||
* `mbedtls_md_init`
|
||||
* `mbedtls_md_free`
|
||||
* `mbedtls_md_setup` — but `hmac` must be 0 if `MBEDTLS_MD_C` is disabled.
|
||||
* `mbedtls_md_clone`
|
||||
* `mbedtls_md_get_size`
|
||||
* `mbedtls_md_get_type`
|
||||
* `mbedtls_md_starts`
|
||||
* `mbedtls_md_update`
|
||||
* `mbedtls_md_finish`
|
||||
* `mbedtls_md`
|
||||
|
||||
Unlike the full MD, MD light does not support null pointers as `mbedtls_md_context_t *`. At least some functions still need to support null pointers as `const mbedtls_md_info_t *` because this arises when you try to use an unsupported algorithm (`mbedtls_md_info_from_type` returns `NULL`).
|
||||
|
||||
#### MD algorithm support macros
|
||||
|
||||
For each hash algorithm, `md.h` defines a macro `MBEDTLS_MD_CAN_xxx` whenever the corresponding hash is available through MD light. These macros are only defined when `MBEDTLS_MD_LIGHT` is enabled. Per “[Availability of hashes](#availability-of-hashes)”, `MBEDTLS_MD_CAN_xxx` is enabled if:
|
||||
|
||||
* the corresponding `MBEDTLS_xxx_C` is defined; or
|
||||
* one of `MBEDTLS_PSA_CRYPTO_C` or `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled, and the corresponding `PSA_WANT_ALG_xxx` is enabled.
|
||||
|
||||
Note that some algorithms have different spellings in legacy and PSA. Since MD is a legacy interface, we'll use the legacy names. Thus, for example:
|
||||
|
||||
```
|
||||
#if defined(MBEDTLS_MD_LIGHT)
|
||||
#if defined(MBEDTLS_SHA256_C) || \
|
||||
(defined(MBEDTLS_PSA_CRYPTO_C) && PSA_WANT_ALG_SHA_256)
|
||||
#define MBEDTLS_MD_CAN_SHA256
|
||||
#endif
|
||||
#endif
|
||||
```
|
||||
|
||||
Note: in the future, we may want to replace `defined(MBEDTLS_PSA_CRYPTO_C)`
|
||||
with `defined(MBEDTLS_PSA_CRYTO_C) || defined(MBEDTLS_PSA_CRYPTO_CLIENT)` but
|
||||
for now this is out of scope.
|
||||
|
||||
#### MD light internal support macros
|
||||
|
||||
* If at least one hash has a PSA driver, define `MBEDTLS_MD_SOME_PSA`.
|
||||
* If at least one hash has a legacy implementation, defined `MBEDTLS_MD_SOME_LEGACY`.
|
||||
|
||||
#### Support for PSA in the MD context
|
||||
|
||||
An MD context needs to contain either a legacy module's context (or a pointer to one, as is the case now), or a PSA context (or a pointer to one).
|
||||
|
||||
I am inclined to remove the pointer indirection, but this means that an MD context would always be as large as the largest supported hash context. So for the time being, this specification keeps a pointer. For uniformity, PSA will also have a pointer (we may simplify this later).
|
||||
|
||||
```
|
||||
enum {
|
||||
MBEDTLS_MD_ENGINE_LEGACY,
|
||||
MBEDTLS_MD_ENGINE_PSA,
|
||||
} mbedtls_md_engine_t; // private type
|
||||
|
||||
typedef struct mbedtls_md_context_t {
|
||||
mbedtls_md_type_t type;
|
||||
#if defined(MBEDTLS_MD_SOME_PSA)
|
||||
mbedtls_md_engine_t engine;
|
||||
#endif
|
||||
void *md_ctx; // mbedtls_xxx_context or psa_hash_operation
|
||||
#if defined(MBEDTLS_MD_C)
|
||||
void *hmac_ctx;
|
||||
#endif
|
||||
} mbedtls_md_context_t;
|
||||
```
|
||||
|
||||
All fields are private.
|
||||
|
||||
The `engine` field is almost redundant with knowledge about `type`. However, when an algorithm is available both via a legacy module and a PSA accelerator, we will choose based on the runtime availability of the accelerator when the context is set up. This choice needs to be recorded in the context structure.
|
||||
|
||||
#### Inclusion of MD info structures
|
||||
|
||||
MD light needs to support hashes that are only enabled through PSA. Therefore the `mbedtls_md_info_t` structures must be included based on `MBEDTLS_MD_CAN_xxx` instead of just the legacy module.
|
||||
|
||||
The same criterion applies in `mbedtls_md_info_from_type`.
|
||||
|
||||
#### Conversion to PSA encoding
|
||||
|
||||
The implementation needs to convert from a legacy type encoding to a PSA encoding.
|
||||
|
||||
```
|
||||
static inline psa_algorithm_t psa_alg_of_md_info(
|
||||
const mbedtls_md_info_t *md_info );
|
||||
```
|
||||
|
||||
#### Determination of PSA support at runtime
|
||||
|
||||
```
|
||||
int psa_can_do_hash(psa_algorithm_t hash_alg);
|
||||
```
|
||||
|
||||
The job of this private function is to return 1 if `hash_alg` can be performed through PSA now, and 0 otherwise. It is only defined on algorithms that are enabled via PSA.
|
||||
|
||||
As a starting point, return 1 if PSA crypto's driver subsystem has been initialized.
|
||||
|
||||
Usage note: for algorithms that are not enabled via PSA, calling `psa_can_do_hash` is generally safe: whether it returns 0 or 1, you can call a PSA hash function on the algorithm and it will return `PSA_ERROR_NOT_SUPPORTED`.
|
||||
|
||||
#### Support for PSA dispatch in hash operations
|
||||
|
||||
Each function that performs some hash operation or context management needs to know whether to dispatch via PSA or legacy.
|
||||
|
||||
If given an established context, use its `engine` field.
|
||||
|
||||
If given an algorithm as an `mbedtls_md_type_t type` (possibly being the `type` field of a `const mbedtls_md_info_t *`):
|
||||
|
||||
* If there is a PSA accelerator for this hash and `psa_can_do_hash(alg)`, call the corresponding PSA function, and if applicable set the engine to `MBEDTLS_MD_ENGINE_PSA`. (Skip this is `MBEDTLS_MD_SOME_PSA` is not defined.)
|
||||
* Otherwise dispatch to the legacy module based on the type as currently done. (Skip this is `MBEDTLS_MD_SOME_LEGACY` is not defined.)
|
||||
* If no dispatch is possible, return `MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE`.
|
||||
|
||||
Note that this assumes that an operation that has been started via PSA can be completed. This implies that `mbedtls_psa_crypto_free` must not be called while an operation using PSA is in progress. Document this.
|
||||
|
||||
#### Error code conversion
|
||||
|
||||
After calling a PSA function, MD light calls `mbedtls_md_error_from_psa` to convert its status code.
|
||||
|
||||
### Support all legacy algorithms in PSA
|
||||
|
||||
As discussed in [“Implications between legacy availability and PSA availability”](#implications-between-legacy-availability-and-psa-availability), we require the following property:
|
||||
|
||||
> If an algorithm has a legacy implementation, it is also available through PSA.
|
||||
|
||||
### MD light optimizations
|
||||
|
||||
This section is not necessary to implement MD light, but will cut down its code size.
|
||||
|
||||
#### Split names out of MD light
|
||||
|
||||
Remove hash names from `mbedtls_md_info_t`. Use a simple switch-case or a separate list to implement `mbedtls_md_info_from_string` and `mbedtls_md_get_name`.
|
||||
|
||||
#### Remove metadata from the info structure
|
||||
|
||||
In `mbedtls_md_get_size` and in modules that want a hash's block size, instead of looking up hash metadata in the info structure, call the PSA macros.
|
||||
|
||||
#### Optimize type conversions
|
||||
|
||||
To allow optimizing conversions between `mbedtls_md_type_t` and `psa_algorithm_t`, renumber the `mbedtls_md_type_t` enum so that the values are the 8 lower bits of the PSA encoding.
|
||||
|
||||
With this optimization,
|
||||
```
|
||||
static inline psa_algorithm_t psa_alg_of_md_info(
|
||||
const mbedtls_md_info_t *md_info )
|
||||
{
|
||||
if( md_info == NULL )
|
||||
return( PSA_ALG_NONE );
|
||||
return( PSA_ALG_CATEGORY_HASH | md_info->type );
|
||||
}
|
||||
```
|
||||
|
||||
Work in progress on this conversion is at https://github.com/gilles-peskine-arm/mbedtls/tree/hash-unify-ids-wip-1
|
||||
|
||||
#### Unify HMAC with PSA
|
||||
|
||||
PSA has its own HMAC implementation. In builds with both `MBEDTLS_MD_C` and `PSA_WANT_ALG_HMAC` not fully provided by drivers, we should have a single implementation. Replace the one in `md.h` by calls to the PSA driver interface. This will also give mixed-domain modules access to HMAC accelerated directly by a PSA driver (eliminating the need to a HMAC interface in software if all supported hashes have an accelerator that includes HMAC support).
|
||||
|
||||
### Improving support for `MBEDTLS_PSA_CRYPTO_CLIENT`
|
||||
|
||||
So far, MD light only dispatches to PSA if an algorithm is available via `MBEDTLS_PSA_CRYPTO_C`, not if it's available via `MBEDTLS_PSA_CRYPTO_CLIENT`. This is acceptable because `MBEDTLS_USE_PSA_CRYPTO` requires `MBEDTLS_PSA_CRYPTO_C`, hence mixed-domain code never invokes PSA.
|
||||
|
||||
The architecture can be extended to support `MBEDTLS_PSA_CRYPTO_CLIENT` with a little extra work. Here is an overview of the task breakdown, which should be fleshed up after we've done the first [migration](#migration-to-md-light):
|
||||
|
||||
* Compile-time dependencies: instead of checking `defined(MBEDTLS_PSA_CRYPTO_C)`, check `defined(MBEDTLS_PSA_CRYPTO_C) || defined(MBEDTLS_PSA_CRYPTO_CLIENT)`.
|
||||
* Implementers of `MBEDTLS_PSA_CRYPTO_CLIENT` will need to provide `psa_can_do_hash()` (or a more general function `psa_can_do`) alongside `psa_crypto_init()`. Note that at this point, it will become a public interface, hence we won't be able to change it at a whim.
|
||||
|
||||
### Internal "block cipher" abstraction (previously known as "Cipher light")
|
||||
|
||||
#### Definition
|
||||
|
||||
The new module is automatically enabled in `config_adjust_legacy_crypto.h` by modules that need
|
||||
it (namely: CCM, GCM) only when `CIPHER_C` is not available, or the new module
|
||||
is needed for PSA dispatch (see next section). Note: CCM and GCM currently
|
||||
depend on the full `CIPHER_C` (enforced by `check_config.h`); this hard
|
||||
dependency would be replaced by the above auto-enablement.
|
||||
|
||||
The following API functions are offered:
|
||||
```
|
||||
void mbedtls_block_cipher_init(mbedtls_block_cipher_context_t *ctx);
|
||||
void mbedtls_block_cipher_free(mbedtls_block_cipher_context_t *ctx);
|
||||
int mbedtls_block_cipher_setup(mbedtls_block_cipher_context_t *ctx,
|
||||
mbedtls_cipher_id_t cipher_id);
|
||||
int mbedtls_block_cipher_setkey(mbedtls_block_cipher_context_t *ctx,
|
||||
const unsigned char *key,
|
||||
unsigned key_bitlen);
|
||||
int mbedtls_block_cipher_encrypt(mbedtls_block_cipher_context_t *ctx,
|
||||
const unsigned char input[16],
|
||||
unsigned char output[16]);
|
||||
```
|
||||
|
||||
The only supported ciphers are AES, ARIA and Camellia. They are identified by
|
||||
an `mbedtls_cipher_id_t` in the `setup()` function, because that's how they're
|
||||
identifed by callers (GCM/CCM).
|
||||
|
||||
#### Block cipher dual dispatch
|
||||
|
||||
Support for dual dispatch in the new internal module `block_cipher` is extremely similar to that in MD light.
|
||||
|
||||
A block cipher context contains either a legacy module's context (AES, ARIA, Camellia) or a PSA key identifier; it has a field indicating which one is in use. All fields are private.
|
||||
|
||||
The `engine` field is almost redundant with knowledge about `type`. However, when an algorithm is available both via a legacy module and a PSA accelerator, we will choose based on the runtime availability of the accelerator when the context is set up. This choice needs to be recorded in the context structure.
|
||||
|
||||
Support is determined at runtime using the new internal function
|
||||
```
|
||||
int psa_can_do_cipher(psa_key_type_t key_type, psa_algorithm_t cipher_alg);
|
||||
```
|
||||
|
||||
The job of this private function is to return 1 if `hash_alg` can be performed through PSA now, and 0 otherwise. It is only defined on algorithms that are enabled via PSA. As a starting point, return 1 if PSA crypto's driver subsystem has been initialized.
|
||||
|
||||
Each function in the module needs to know whether to dispatch via PSA or legacy. All functions consult the context's `engine` field, except `setup()` which will set it according to the key type and the return value of `psa_can_do_cipher()` as discussed above.
|
||||
|
||||
Note that this assumes that an operation that has been started via PSA can be completed. This implies that `mbedtls_psa_crypto_free` must not be called while an operation using PSA is in progress.
|
||||
|
||||
After calling a PSA function, `block_cipher` functions call `mbedtls_cipher_error_from_psa` to convert its status code.
|
@ -3,10 +3,9 @@
|
||||
# This script runs tests before and after a PR and analyzes the results in
|
||||
# order to highlight any difference in the set of tests skipped.
|
||||
#
|
||||
# It can be used to check the first testing criterion mentioned in strategy.md,
|
||||
# end of section "Supporting builds with drivers without the software
|
||||
# implementation", namely: the sets of tests skipped in the default config and
|
||||
# the full config must be the same before and after the PR.
|
||||
# It can be used to check for unintended consequences when making non-trivial
|
||||
# changes to compile time guards: the sets of tests skipped in the default
|
||||
# config and the full config must be the same before and after the PR.
|
||||
#
|
||||
# USAGE:
|
||||
# - First, commit any uncommited changes. (Also, see warning below.)
|
||||
|
@ -1,344 +0,0 @@
|
||||
Bridges between legacy and PSA crypto APIs
|
||||
==========================================
|
||||
|
||||
## Introduction
|
||||
|
||||
### Goal of this document
|
||||
|
||||
This document explores the needs of applications that use both Mbed TLS legacy crypto interfaces and PSA crypto interfaces. Based on [requirements](#requirements), we [analyze gaps](#gap-analysis) and [API design](#api-design).
|
||||
|
||||
This is a design document. The target audience is library maintainers. See the companion document [“Transitioning to the PSA API”](../../psa-transition.md) for a user focus on the same topic.
|
||||
|
||||
### Keywords
|
||||
|
||||
* [TODO] A part of the analysis that isn't finished.
|
||||
* [OPEN] Open question: a specific aspect of the design where there are several plausible decisions.
|
||||
* [ACTION] A finalized part of the design that will need to be carried out.
|
||||
|
||||
### Context
|
||||
|
||||
Mbed TLS 3.x supports two cryptographic APIs:
|
||||
|
||||
* The legacy API `mbedtls_xxx` is inherited from PolarSSL.
|
||||
* The PSA API `psa_xxx` was introduced in Mbed TLS 2.17.
|
||||
|
||||
Mbed TLS is gradually shifting from the legacy API to the PSA API. Mbed TLS 4.0 will be the first version where the PSA API is considered the main API, and large parts of the legacy API will be removed.
|
||||
|
||||
In Mbed TLS 4.0, the cryptography will be provided by a separate project [TF-PSA-Crypto](https://github.com/Mbed-TLS/TF-PSA-Crypto). For simplicity, in this document, we just refer to the whole as “Mbed TLS”.
|
||||
|
||||
### Document history
|
||||
|
||||
This document was originally written when preparing Mbed TLS 3.6. Mbed TLS 3.6 includes both PSA and legacy APIs covering largely overlapping ground. Many legacy APIs will be removed in Mbed TLS 4.0.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Why mix APIs?
|
||||
|
||||
There is functionality that is tied to one API and is not directly available in the other API:
|
||||
|
||||
* Only PSA fully supports PSA accelerators and secure element integration.
|
||||
* Only PSA supports isolating cryptographic material in a secure service.
|
||||
* The legacy API has features that are not present (yet) in PSA, notably parsing and formatting asymmetric keys.
|
||||
|
||||
The legacy API can partially leverage PSA features via `MBEDTLS_USE_PSA_CRYPTO`, but this has limited scope.
|
||||
|
||||
In addition, many applications cannot be migrated in a single go. For large projects, it is impractical to rewrite a significant part of the code all at once. (For example, Mbed TLS itself will have taken more than 6 years to transition.) Projects that use one or more library in addition to Mbed TLS must follow the evolution of these libraries, each of which might have its own pace.
|
||||
|
||||
### Where mixing happens
|
||||
|
||||
Mbed TLS can be, and normally is, built with support for both APIs. Therefore no special effort is necessary to allow an application to use both APIs.
|
||||
|
||||
Special effort is necessary to use both APIs as part of the implementation of the same feature. From an informal analysis of typical application requirements, we identify four parts of the use of cryptography which can be provided by different APIs:
|
||||
|
||||
* Metadata manipulation: parsing and producing encrypted or signed files, finding mutually supported algorithms in a network protocol negotiation, etc.
|
||||
* Key management: parsing, generating, deriving and formatting cryptographic keys.
|
||||
* Data manipulation other than keys. In practice, most data formats within the scope of the legacy crypto APIs are trivial (ciphertexts, hashes, MACs, shared secrets). The one exception is ECDSA signatures.
|
||||
* Cryptographic operations: hash, sign, encrypt, etc.
|
||||
|
||||
From this, we deduce the following requirements:
|
||||
|
||||
* Convert between PSA and legacy metadata.
|
||||
* Creating a key with the legacy API and consuming it in the PSA API.
|
||||
* Creating a key with the PSA API and consuming it in the legacy API.
|
||||
* Manipulating data formats, other than keys, where the PSA API is lacking.
|
||||
|
||||
### Scope limitations
|
||||
|
||||
The goal of this document is to bridge the legacy API and the PSA API. The goal is not to provide a PSA way to do everything that is currently possible with the legacy API. The PSA API is less flexible in some regards, and extending it is out of scope in the present study.
|
||||
|
||||
With respect to the legacy API, we do not consider functionality of low-level modules for individual algorithms. Our focus is on applications that use high-level legacy crypto modules (md, cipher, pk) and need to combine that with uses of the PSA APIs.
|
||||
|
||||
## Gap analysis
|
||||
|
||||
The document [“Transitioning to the PSA API”](../../psa-transition.md) enumerates the public header files in Mbed TLS 3.4 and the API elements (especially enums and functions) that they provide, listing PSA equivalents where they exist. There are gaps in two cases:
|
||||
|
||||
* Where the PSA equivalents do not provide the same functionality. A typical example is parsing and formatting asymmetric keys.
|
||||
* To convert between data representations used by legacy APIs and data representations used by PSA APIs.
|
||||
|
||||
Based on “[Where mixing happens](#where-mixing-happens)”, we focus the gap analysis on two topics: metadata and keys. This chapter explores the gaps in each family of cryptographic mechanisms.
|
||||
|
||||
### Generic metadata gaps
|
||||
|
||||
#### Need for error code conversion
|
||||
|
||||
Do we need public functions to convert between `MBEDTLS_ERR_xxx` error codes and `PSA_ERROR_xxx` error codes? We have such functions for internal use.
|
||||
|
||||
Mbed TLS needs these conversions because it has many functions that expose one API (legacy/API) but are implemented on top of the other API. Most applications would convert legacy and PSA error code to their own error codes, and converting between `MBEDTLS_ERR_xxx` error codes and `PSA_ERROR_xxx` is not particularly helpful for that. Application code might need such conversion functions when implementing an X.509 or TLS callback (returning `MBEDTLS_ERR_xxx`) on top of PSA functions, but this is a very limited use case.
|
||||
|
||||
Conclusion: no need for public error code conversion functions.
|
||||
|
||||
### Hash gap analysis
|
||||
|
||||
Hashes do not involve keys, and involves no nontrivial data format. Therefore the only gap is with metadata, namely specifying a hash algorithm.
|
||||
|
||||
Hashes are often used as building blocks for other mechanisms (HMAC, signatures, key derivation, etc.). Therefore metadata about hashes is relevant not only when calculating hashes, but also when performing many other cryptographic operations.
|
||||
|
||||
Gap: functions to convert between `psa_algorithm_t` hash algorithms and `mbedtls_md_type_t`. Such functions exist in Mbed TLS 3.5 (`mbedtls_md_psa_alg_from_type`, `mbedtls_md_type_from_psa_alg`) but they are declared only in private headers.
|
||||
|
||||
### MAC gap analysis
|
||||
|
||||
[TODO]
|
||||
|
||||
### Cipher and AEAD gap analysis
|
||||
|
||||
[TODO]
|
||||
|
||||
### Key derivation gap analysis
|
||||
|
||||
[TODO]
|
||||
|
||||
### Random generation gap analysis
|
||||
|
||||
[TODO]
|
||||
|
||||
### Asymmetric cryptography gap analysis
|
||||
|
||||
#### Asymmetric cryptography metadata
|
||||
|
||||
The legacy API only has generic support for two key types: RSA and ECC, via the pk module. ECC keys can also be further classified according to their curve. The legacy API also supports DHM (Diffie-Hellman-Merkle = FFDH: finite-field Diffie-Hellman) keys, but those are not integrated in the pk module.
|
||||
|
||||
An RSA or ECC key can potentially be used for different algorithms in the scope of the pk module:
|
||||
|
||||
* RSA: PKCS#1v1.5 signature, PSS signature, PKCS#1v1.5 encryption, OAEP encryption.
|
||||
* ECC: ECDSA signature (randomized or deterministic), ECDH key agreement (via `mbedtls_pk_ec`).
|
||||
|
||||
ECC keys are also involved in EC-JPAKE, but this happens internally: the EC-JPAKE interface only needs one piece of metadata, namely, to identify a curve.
|
||||
|
||||
Since there is no algorithm that can be used with multiple types, and PSA keys have a policy that (for the most part) limits them to one algorithm, there does not seem to be a need to convert between legacy and PSA asymmetric key types on their own. The useful metadata conversions are:
|
||||
|
||||
* Selecting an **elliptic curve**.
|
||||
|
||||
This means converting between an `mbedtls_ecp_group_id` and a pair of `{psa_ecc_family_t; size_t}`.
|
||||
|
||||
This is fulfilled by `mbedtls_ecc_group_to_psa` and `mbedtls_ecc_group_from_psa`, which were introduced into the public API between Mbed TLS 3.5 and 3.6 ([#8664](https://github.com/Mbed-TLS/mbedtls/pull/8664)).
|
||||
|
||||
* Selecting A **DHM group**.
|
||||
|
||||
PSA only supports predefined groups, whereas legacy only supports ad hoc groups. An existing application referring to `MBEDTLS_DHM_RFC7919_FFDHExxx` values would need to refer to `PSA_DH_FAMILY_RFC7919`; an existing application using arbitrary groups cannot migrate to PSA.
|
||||
|
||||
* Simultaneously supporting **a key type and an algorithm**.
|
||||
|
||||
On the legacy side, this is an `mbedtls_pk_type_t` value and more. For ECDSA, the choice between randomized and deterministic is made at compile time. For RSA, the choice of encryption or signature algorithm is made either by configuring the underlying `mbedtls_rsa_context` or when calling the operation function.
|
||||
|
||||
On the PSA side, this is a `psa_key_type_t` value and an algorithm which is normally encoded as policy information in a `psa_key_attributes_t`. The algorithm is also needed in its own right when calling operation functions.
|
||||
|
||||
#### Using a legacy key pair or public key with PSA
|
||||
|
||||
There are several scenarios where an application has a legacy key pair or public key (`mbedtls_pk_context`) and needs to create a PSA key object (`psa_key_id_t`).
|
||||
|
||||
Reasons for first creating a legacy key object, where it's impossible or impractical to directly create a PSA key:
|
||||
|
||||
* A very common case where the input is a legacy key object is parsing. PSA does not (yet) have an equivalent of the `mbedtls_pk_parse_xxx` functions.
|
||||
* The PSA key creation interface is less flexible in some cases. In particular, PSA RSA key generation does not (yet) allow choosing the public exponent.
|
||||
* The pk object may be created by a part of the application (or a third-party library) that hasn't been migrated to the PSA API yet.
|
||||
|
||||
Reasons for needing a PSA key object:
|
||||
|
||||
* Using the key with third-party interface that takes a PSA key identifier as input. (Mbed TLS itself has a few TLS functions that take PSA key identifiers, but as of Mbed TLS 3.5, it is always possible to use a legacy key instead.)
|
||||
* Benefiting from a PSA accelerator, or from PSA's world separation, even without `MBEDTLS_USE_PSA_CRYPTO`. (Not a priority scenario: we generally expect people to activate `MBEDTLS_USE_PSA_CRYPTO` at an early stage of their migration to PSA.)
|
||||
|
||||
Gap: a way to create a PSA key object from an `mbedtls_pk_context`. This partially exists in the form of `mbedtls_pk_wrap_as_opaque`, but it is not fully satisfactory, for reasons that are detailed in “[API to create a PSA key from a PK context](#api-to-create-a-psa-key-from-a-pk-context)” below.
|
||||
|
||||
#### Using a PSA key as a PK context
|
||||
|
||||
There are several scenarios where an application has a PSA key and needs to use it through an interface that wants an `mbedtls_pk_context` object. Typically, there is an existing key in the PSA key store (possibly in a secure element and non-exportable), and the key needs to be used in an interface that requires a `mbedtls_pk_context *` input, such as Mbed TLS's X.509 and TLS APIs or a similar third-party interface, or the `mbedtls_pk_write_xxx` interfaces which do not (yet) have PSA equivalents.
|
||||
|
||||
There is a function `mbedtls_pk_setup_opaque` that mostly does this. However, it has several limitations:
|
||||
|
||||
* It creates a PK key of type `MBEDTLS_PK_OPAQUE` that wraps the PSA key. This is good enough in some scenarios, but not others. For example, it's ok for pkwrite, because we've upgraded the pkwrite code to handle `MBEDTLS_PK_OPAQUE`. That doesn't help users of third-party libraries that haven't yet been upgraded.
|
||||
* It ties the lifetime of the PK object to the PSA key, which is error-prone: if the PSA key is destroyed but the PK object isn't, there is no way to reliably detect any subsequent misuse of the PK object.
|
||||
* It is only available under `MBEDTLS_USE_PSA_CRYPTO`. This is not a priority concern, since we generally expect people to activate `MBEDTLS_USE_PSA_CRYPTO` at an early stage of their migration to PSA. However, this function is useful to use specific PSA keys in X.509/TLS regardless of whether X.509/TLS use the PSA API for all cryptographic operations, so this is a wart in the current API.
|
||||
|
||||
It therefore appears that we need two ways to “convert” a PSA key to PK:
|
||||
|
||||
* Wrapping, which is what `mbedtls_pk_setup_opaque` does. This works for any PSA key but is limited by the key's lifetime and creates a PK object with limited functionality.
|
||||
* Copying, which requires a new function. This requires an exportable key but creates a fully independent, fully functional PK object.
|
||||
|
||||
Gap: a way to copy a PSA key into a PK context. This can only be expected to work if the PSA key is exportable.
|
||||
|
||||
After some discussion, have not identified anything we want to change in the behavior of `mbedtls_pk_setup_opaque`. We only want to generalize it to non-`MBEDTLS_USE_PSA_CRYPTO` and to document it better.
|
||||
|
||||
#### Signature formats
|
||||
|
||||
The pk module uses signature formats intended for X.509. The PSA module uses the simplest sensible signature format.
|
||||
|
||||
* For RSA, the formats are the same.
|
||||
* For ECDSA, PSA uses a fixed-size concatenation of (r,s), whereas X.509 and pk use an ASN.1 DER encoding of the sequence (r,s).
|
||||
|
||||
Gap: We need APIs to convert between these two formats. The conversion code already exists under the hood, but it's in pieces that can't be called directly.
|
||||
|
||||
There is a design choice here: do we provide conversions functions for ECDSA specifically, or do we provide conversion functions that take an algorithm as argument and just happen to be a no-op with RSA? One factor is plausible extensions. These conversions functions will remain useful in Mbed TLS 4.x and perhaps beyond. We will at least add EdDSA support, and its signature encoding is the fixed-size concatenation (r,s) even in X.509. We may well also add support for some post-quantum signatures, and their concrete format is still uncertain.
|
||||
|
||||
Given the uncertainty, it would be nice to provide a sufficiently generic interface to convert between the PSA and the pk signature format, parametrized by the algorithm. However, it is difficult to predict exactly what parameters are needed. For example, converting from an ASN.1 ECDSA signature to (r,s) requires the knowledge of the curve, or at least the curve's size. Therefore we are not going to add a generic function at this stage.
|
||||
|
||||
For ECDSA, there are two plausible APIs: follow the ASN.1/X.509 write/parse APIs, or present an ordinary input/output API. The ASN.1 APIs are the way they are to accommodate nested TLV structures. But ECDSA signatures do not appear nested in TLV structures in either TLS (there's just a signature field) or X.509 (the signature is inside a BITSTRING, not directly in a SEQUENCE). So there does not seem to be a need for an ASN.1-like API for the ASN.1 format, just the format conversion itself in a buffer that just contains the signature.
|
||||
|
||||
#### Asymmetric cryptography TODO
|
||||
|
||||
[TODO] Other gaps?
|
||||
|
||||
## New APIs
|
||||
|
||||
This section presents new APIs to implement based on the [gap analysis](#gap-analysis).
|
||||
|
||||
### General notes
|
||||
|
||||
Each action to implement a function entails:
|
||||
|
||||
* Implement the library function.
|
||||
* Document it precisely, including error conditions.
|
||||
* Unit-test it.
|
||||
* Mention it where relevant in the PSA transition guide.
|
||||
|
||||
### Hash APIs
|
||||
|
||||
Based on the [gap analysis](#hash-gap-analysis):
|
||||
|
||||
[ACTION] [#8340](https://github.com/Mbed-TLS/mbedtls/issues/8340) Move `mbedtls_md_psa_alg_from_type` and `mbedtls_md_type_from_psa_alg` from `library/md_psa.h` to `include/mbedtls/md.h`.
|
||||
|
||||
### MAC APIs
|
||||
|
||||
[TODO]
|
||||
|
||||
### Cipher and AEAD APIs
|
||||
|
||||
[TODO]
|
||||
|
||||
### Key derivation APIs
|
||||
|
||||
[TODO]
|
||||
|
||||
### Random generation APIs
|
||||
|
||||
[TODO]
|
||||
|
||||
### Asymmetric cryptography APIs
|
||||
|
||||
#### Asymmetric cryptography metadata APIs
|
||||
|
||||
Based on the [gap analysis](#asymmetric-cryptography-metadata):
|
||||
|
||||
* No further work is needed about RSA specifically. The amount of metadata other than hashes is sufficiently small to be handled in ad hoc ways in applications, and hashes have [their own conversions](#hash-apis).
|
||||
* No further work is needed about ECC specifically. We have just added adequate functions.
|
||||
* No further work is needed about DHM specifically. There is no good way to translate the relevant information.
|
||||
* [OPEN] Is there a decent way to convert between `mbedtls_pk_type_t` plus extra information, and `psa_key_type_t` plus policy information? The two APIs are different in crucial ways, with different splits between key type, policy information and operation algorithm.
|
||||
Thinking so far: there isn't really a nice way to present this conversion. For a specific key, `mbedtls_pk_get_psa_attributes` and `mbedtls_pk_copy_from_psa` do the job.
|
||||
|
||||
#### API to create a PSA key from a PK context
|
||||
|
||||
Based on the [gap analysis](#using-a-legacy-key-pair-or-public-key-with-psa):
|
||||
|
||||
Given an `mbedtls_pk_context`, we want a function that creates a PSA key with the same key material and algorithm. “Same key material” is straightforward, but “same algorithm” is not, because a PK context has incomplete algorithm information. For example, there is no way to distinguish between an RSA key that is intended for signature or for encryption. Between algorithms of the same nature, there is no way to distinguish a key intended for PKCS#1v1.5 and one intended for PKCS#1v2.1 (OAEP/PSS): this is indicated in the underlying RSA context, but the indication there is only a default that can be overridden by calling `mbedtls_pk_{sign,verify}_ext`. Also there is no way to distinguish between `PSA_ALG_RSA_PKCS1V15_SIGN(hash_alg)` and `PSA_ALG_RSA_PKCS1V15_SIGN_RAW`: in the legacy interface, this is only determined when actually doing a signature/verification operation. Therefore the function that creates the PSA key needs extra information to indicate which algorithm to put in the key's policy.
|
||||
|
||||
When creating a PSA key, apart from the key material, the key is determined by attributes, which fall under three categories:
|
||||
|
||||
* Type and size. These are directly related to the key material and can be deduced from it if the key material is in a structured format, which is the case with an `mbedtls_pk_context` input.
|
||||
* Policy. This includes the chosen algorithm, which as discussed above cannot be fully deduced from the `mbedtls_pk_context` object. Just choosing one algorithm is problematic because it doesn't allow implementation-specific extensions, such as Mbed TLS's enrollment algorithm. The intended usage flags cannot be deduced from the PK context either, but the conversion function could sensibly just enable all the relevant usage flags. Users who want a more restrictive usage can call `psa_copy_key` and `psa_destroy_key` to obtain a PSA key object with a more restrictive usage.
|
||||
* Persistence and location. This is completely orthogonal to the information from the `mbedtls_pk_context` object. It is convenient, but not necessary, for the conversion function to allow customizing these aspects. If it doesn't, users can call the conversion function and then call `psa_copy_key` and `psa_destroy_key` to move the key to its desired location.
|
||||
|
||||
To allow the full flexibility around policies, and make the creation of a persistent key more convenient, the conversion function shall take a `const psa_key_attributes_t *` input, like all other functions that create a PSA key. In addition, there shall be a helper function to populate a `psa_key_attributes_t` with a sensible default. This lets the caller choose a more flexible, or just different usage policy, unlike the default-then-copy approach which only allows restricting the policy.
|
||||
|
||||
This is close to the existing function `mbedtls_pk_wrap_as_opaque`, but does not bake in the implementation-specific consideration that a PSA key has exactly two algorithms, and also allows the caller to benefit from default for the policy in more cases.
|
||||
|
||||
[ACTION] [#8708](https://github.com/Mbed-TLS/mbedtls/issues/8708) Implement `mbedtls_pk_get_psa_attributes` and `mbedtls_pk_import_into_psa` as described below. These functions are available whenever `MBEDTLS_PK_C` and `MBEDTLS_PSA_CRYPTO_CLIENT` are both defined. Deprecate `mbedtls_pk_wrap_as_opaque`.
|
||||
|
||||
```
|
||||
int mbedtls_pk_get_psa_attributes(const mbedtls_pk_context *pk,
|
||||
psa_key_usage_flags_t usage,
|
||||
psa_key_attributes_t *attributes);
|
||||
int mbedtls_pk_import_into_psa(const mbedtls_pk_context *pk,
|
||||
const psa_key_attributes_t *attributes,
|
||||
mbedtls_svc_key_id_t *key_id);
|
||||
```
|
||||
|
||||
* `mbedtls_pk_get_psa_attributes` does not change the id/lifetime fields of the attributes (which indicate a volatile key by default).
|
||||
* [OPEN] Or should it reset them to 0? Resetting is more convenient for the case where the pk key is a `MBEDTLS_PK_OPAQUE`. But that's an uncommon use case. It's probably less surprising if this function leaves the lifetime-related alone, since its job is to set the type-related and policy-related attributes.
|
||||
* `mbedtls_pk_get_psa_attributes` sets the type and size based on what's in the pk context.
|
||||
* The key type is a key pair if the context contains a private key and the indicated usage is a private-key usage. The key type is a public key if the context only contains a public key, in which case a private-key usage is an error.
|
||||
* `mbedtls_pk_get_psa_attributes` sets the usage flags based on the `usage` parameter. It extends the usage to other usage that is possible:
|
||||
* `EXPORT` and `COPY` are always set.
|
||||
* If `SIGN_{HASH,MESSAGE}` is set then so is `VERIFY_{HASH,MESSAGE}`.
|
||||
* If `DECRYPT` is set then so is `ENCRYPT`.
|
||||
* It is an error if `usage` has more than one flag set, or has a usage that is incompatible with the key type.
|
||||
* `mbedtls_pk_get_psa_attributes` sets the algorithm usage policy based on information in the key object and on `usage`.
|
||||
* For an RSA key with the `MBEDTLS_RSA_PKCS_V15` padding mode, the algorithm policy is `PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)` for a sign/verify usage, and `PSA_ALG_RSA_PKCS1V15_CRYPT` for an encrypt/decrypt usage.
|
||||
* For an RSA key with the `MBEDTLS_RSA_PKCS_V21` padding mode, the algorithm policy is `PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)` for a sign/verify usage, and `PSA_ALG_RSA_OAEP(hash)` for an encrypt/decrypt usage where `hash` is from the RSA key's parameters. (Note that `PSA_ALG_ANY_HASH` is only allowed in signature algorithms.)
|
||||
* For an `MBEDTLS_PK_ECKEY` or `MBEDTLS_PK_ECDSA` with a sign/verify usage, the algorithm policy is `PSA_ALG_DETERMINISTIC_ECDSA` if `MBEDTLS_ECDSA_DETERMINISTIC` is enabled and `PSA_ALG_ECDSA` otherwise. In either case, the hash policy is `PSA_ALG_ANY_HASH`.
|
||||
* For an `MBEDTLS_PK_ECKEY` or `MBEDTLS_PK_ECDKEY_DH` with the usage `PSA_KEY_USAGE_DERIVE`, the algorithm is `PSA_ALG_ECDH`.
|
||||
* For a `MBEDTLS_PK_OPAQUE`, this function reads the attributes of the existing PK key and copies them (without overriding the lifetime and key identifier in `attributes`), then applies a public-key restriction if needed.
|
||||
* Public-key restriction: if `usage` is a public-key usage, change the type to the corresponding public-key type, and remove private-key usage flags from the usage flags read from the existing key.
|
||||
* `mbedtls_pk_import_into_psa` checks that the type field in the attributes is consistent with the content of the `mbedtls_pk_context` object (RSA/ECC, and availability of the private key).
|
||||
* The key type can be a public key even if the private key is available.
|
||||
* `mbedtls_pk_import_into_psa` does not need to check the bit-size in the attributes: `psa_import_key` will do enough checks.
|
||||
* `mbedtls_pk_import_into_psa` does not check that the policy in the attributes is sensible. That's on the user.
|
||||
|
||||
#### API to copy a PSA key to a PK context
|
||||
|
||||
Based on the [gap analysis](#using-a-psa-key-as-a-pk-context):
|
||||
|
||||
[ACTION] [#8709](https://github.com/Mbed-TLS/mbedtls/issues/8709) Implement `mbedtls_pk_copy_from_psa` as described below.
|
||||
|
||||
```
|
||||
int mbedtls_pk_copy_from_psa(mbedtls_svc_key_id_t key_id,
|
||||
mbedtls_pk_context *pk);
|
||||
```
|
||||
|
||||
* `pk` must be initialized, but not set up.
|
||||
* It is an error if the key is neither a key pair nor a public key.
|
||||
* It is an error if the key is not exportable.
|
||||
* The resulting pk object has a transparent type, not `MBEDTLS_PK_OPAQUE`. That's `MBEDTLS_PK_RSA` for RSA keys (since pk objects don't use `MBEDTLS_PK_RSASSA_PSS` as a type), and `MBEDTLS_PK_ECKEY` for ECC keys (following the example of pkparse).
|
||||
* Once this function returns, the pk object is completely independent of the PSA key.
|
||||
* Calling `mbedtls_pk_sign`, `mbedtls_pk_verify`, `mbedtls_pk_encrypt`, `mbedtls_pk_decrypt` on the resulting pk context will perform an algorithm that is compatible with the PSA key's primary algorithm policy (`psa_get_key_algorithm`) if that is a matching operation type (sign/verify, encrypt/decrypt), but with no restriction on the hash (as if the policy had `PSA_ALG_ANY_HASH` instead of a specific hash, and with `PSA_ALG_RSA_PKCS1V15_SIGN_RAW` merged with `PSA_ALG_RSA_PKCS1V15_SIGN(hash_alg)`).
|
||||
* For ECDSA, the choice of deterministic vs randomized will be based on the compile-time setting `MBEDTLS_ECDSA_DETERMINISTIC`, like `mbedtls_pk_sign` today.
|
||||
* For an RSA key, the output key will allow both encrypt/decrypt and sign/verify regardless of the original key's policy. The original key's policy determines the output key's padding mode.
|
||||
* The primary intent of this requirement is to allow an application to switch to PSA for creating the key material (for example to benefit from a PSA accelerator driver, or to start using a secure element), without modifying the code that consumes the key. For RSA keys, the PSA primary algorithm policy is how one conveys the same information as RSA key padding information in the legacy API. Convey this in the documentation.
|
||||
|
||||
#### API to create a PK object that wraps a PSA key
|
||||
|
||||
Based on the [gap analysis](#using-a-psa-key-as-a-pk-context):
|
||||
|
||||
[ACTION] [#8712](https://github.com/Mbed-TLS/mbedtls/issues/8712) Clarify the documentation of `mbedtls_pk_setup_opaque` regarding which algorithms the resulting key will perform with `mbedtls_pk_sign`, `mbedtls_pk_verify`, `mbedtls_pk_encrypt`, `mbedtls_pk_decrypt`.
|
||||
|
||||
[ACTION] [#8710](https://github.com/Mbed-TLS/mbedtls/issues/8710) Provide `mbedtls_pk_setup_opaque` whenever `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled, not just when `MBEDTLS_USE_PSA_CRYPTO` is enabled. This is nice-to-have, not critical. Update `use-psa-crypto.md` accordingly.
|
||||
|
||||
[OPEN] What about `mbedtls_pk_sign_ext` and `mbedtls_pk_verify_ext`?
|
||||
|
||||
#### API to convert between signature formats
|
||||
|
||||
Based on the [gap analysis](#signature-formats):
|
||||
|
||||
[ACTION] [#7765](https://github.com/Mbed-TLS/mbedtls/issues/7765) Implement `mbedtls_ecdsa_raw_to_der` and `mbedtls_ecdsa_der_to_raw` as described below.
|
||||
|
||||
```
|
||||
int mbedtls_ecdsa_raw_to_der(size_t bits,
|
||||
const unsigned char *raw, size_t raw_len,
|
||||
unsigned char *der, size_t der_size, size_t *der_len);
|
||||
int mbedtls_ecdsa_der_to_raw(size_t bits,
|
||||
const unsigned char *der, size_t der_len,
|
||||
unsigned char *raw, size_t raw_size, size_t *raw_len);
|
||||
```
|
||||
|
||||
* These functions convert between the signature format used by `mbedtls_pk_{sign,verify}{,_ext}` and the signature format used by `psa_{sign,verify}_{hash,message}`.
|
||||
* The input and output buffers can overlap.
|
||||
* The `bits` parameter is necessary in the DER-to-raw direction because the DER format lacks leading zeros, so something else needs to convey the size of (r,s). The `bits` parameter is redundant in the raw-to-DER direction, but we have it anyway because [it helps catch errors](https://github.com/Mbed-TLS/mbedtls/pull/8681#discussion_r1445980971), and it isn't a burden on the caller because the information is readily available in practice.
|
||||
* Should these functions rely on the ASN.1 module? We experimented [calling ASN.1 functions](https://github.com/Mbed-TLS/mbedtls/pull/8681), [reimplementing simpler ASN.1 functions](https://github.com/Mbed-TLS/mbedtls/pull/8696), and [providing the functions from the ASN.1 module](https://github.com/Mbed-TLS/mbedtls/pull/8703). Providing the functions from the ASN.1 module [won on a compromise of code size and simplicity](https://github.com/Mbed-TLS/mbedtls/issues/7765#issuecomment-1893670015).
|
@ -1,7 +1,8 @@
|
||||
This document lists current limitations of the PSA Crypto API (as of version
|
||||
1.1) that may impact our ability to (1) use it for all crypto operations in
|
||||
TLS and X.509 and (2) support isolation of all long-term secrets in TLS (that
|
||||
is, goals G1 and G2 in [strategy.md](strategy.md) in the same directory).
|
||||
is, goals G1 and G2 in
|
||||
[strategy.md](https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.6/docs/architecture/psa-migration/strategy.md)).
|
||||
|
||||
This is supposed to be a complete list, based on a exhaustive review of crypto
|
||||
operations done in TLS and X.509 code, but of course it's still possible that
|
||||
@ -21,11 +22,11 @@ TLS have not yet been adapted to take advantage of the new PSA APIs. See:
|
||||
- <https://github.com/Mbed-TLS/mbedtls/issues/7293>;
|
||||
- <https://github.com/Mbed-TLS/mbedtls/issues/7294>.
|
||||
|
||||
Currently, when `MBEDTLS_USE_PSA_CRYPTO` and `MBEDTLS_ECP_RESTARTABLE` are
|
||||
both enabled, some operations that should be restartable are not (ECDH in TLS
|
||||
1.2 clients using ECDHE-ECDSA), as they are using PSA instead, and some
|
||||
operations that should use PSA do not (signature generation & verification) as
|
||||
they use the legacy API instead, in order to get restartable behaviour.
|
||||
Currently, when `MBEDTLS_ECP_RESTARTABLE` is enabled, some operations that
|
||||
should be restartable are not (ECDH in TLS 1.2 clients using ECDHE-ECDSA), as
|
||||
they are using PSA instead, and some operations that should use PSA do not
|
||||
(signature generation & verification) as they use the legacy API instead, in
|
||||
order to get restartable behaviour.
|
||||
|
||||
Things that are in the API but not implemented yet
|
||||
--------------------------------------------------
|
||||
|
@ -1,486 +0,0 @@
|
||||
This document explains the strategy that was used so far in starting the
|
||||
migration to PSA Crypto and mentions future perspectives and open questions.
|
||||
|
||||
Goals
|
||||
=====
|
||||
|
||||
Several benefits are expected from migrating to PSA Crypto:
|
||||
|
||||
G1. Use PSA Crypto drivers when available.
|
||||
G2. Allow isolation of long-term secrets (for example, private keys).
|
||||
G3. Allow isolation of short-term secrets (for example, TLS session keys).
|
||||
G4. Have a clean, unified API for Crypto (retire the legacy API).
|
||||
G5. Code size: compile out our implementation when a driver is available.
|
||||
|
||||
As of Mbed TLS 3.2, most of (G1) and all of (G2) is implemented when
|
||||
`MBEDTLS_USE_PSA_CRYPTO` is enabled. For (G2) to take effect, the application
|
||||
needs to be changed to use new APIs. For a more detailed account of what's
|
||||
implemented, see `docs/use-psa-crypto.md`, where new APIs are about (G2), and
|
||||
internal changes implement (G1).
|
||||
|
||||
As of early 2023, work towards G5 is in progress: Mbed TLS 3.3 and 3.4 saw
|
||||
some improvements in this area, and more will be coming in future releases.
|
||||
|
||||
Generally speaking, the numbering above doesn't mean that each goal requires
|
||||
the preceding ones to be completed.
|
||||
|
||||
|
||||
Compile-time options
|
||||
====================
|
||||
|
||||
We currently have a few compile-time options that are relevant to the migration:
|
||||
|
||||
- `MBEDTLS_PSA_CRYPTO_C` - enabled by default, controls the presence of the PSA
|
||||
Crypto APIs.
|
||||
- `MBEDTLS_USE_PSA_CRYPTO` - disabled by default (enabled in "full" config),
|
||||
controls usage of PSA Crypto APIs to perform operations in X.509 and TLS
|
||||
(G1 above), as well as the availability of some new APIs (G2 above).
|
||||
- `PSA_CRYPTO_CONFIG` - disabled by default, supports builds with drivers and
|
||||
without the corresponding software implementation (G5 above).
|
||||
|
||||
The reasons why `MBEDTLS_USE_PSA_CRYPTO` is optional and disabled by default
|
||||
are:
|
||||
- it's not fully compatible with `MBEDTLS_ECP_RESTARTABLE`: you can enable
|
||||
both, but then you won't get the full effect of RESTARTBLE (see the
|
||||
documentation of this option in `mbedtls_config.h`);
|
||||
- to avoid a hard/default dependency of TLS, X.509 and PK on
|
||||
`MBEDTLS_PSA_CRYPTO_C`, for backward compatibility reasons:
|
||||
- When `MBEDTLS_PSA_CRYPTO_C` is enabled and used, applications need to call
|
||||
`psa_crypto_init()` before TLS/X.509 uses PSA functions. (This prevents us
|
||||
from even enabling the option by default.)
|
||||
- `MBEDTLS_PSA_CRYPTO_C` has a hard dependency on `MBEDTLS_ENTROPY_C ||
|
||||
MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` but it's
|
||||
currently possible to compile TLS and X.509 without any of the options.
|
||||
Also, we can't just auto-enable `MBEDTLS_ENTROPY_C` as it doesn't build
|
||||
out of the box on all platforms, and even less
|
||||
`MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` as it requires a user-provided RNG
|
||||
function.
|
||||
|
||||
The downside of this approach is that until we are able to make
|
||||
`MBDEDTLS_USE_PSA_CRYPTO` non-optional (always enabled), we have to maintain
|
||||
two versions of some parts of the code: one using PSA, the other using the
|
||||
legacy APIs. However, see next section for strategies that can lower that
|
||||
cost. The rest of this section explains the reasons for the
|
||||
incompatibilities mentioned above.
|
||||
|
||||
At the time of writing (early 2022) it is unclear what could be done about the
|
||||
backward compatibility issues, and in particular if the cost of implementing
|
||||
solutions to these problems would be higher or lower than the cost of
|
||||
maintaining dual code paths until the next major version. (Note: these
|
||||
solutions would probably also solve other problems at the same time.)
|
||||
|
||||
### `MBEDTLS_ECP_RESTARTABLE`
|
||||
|
||||
Currently this option controls not only the presence of restartable APIs in
|
||||
the crypto library, but also their use in the TLS and X.509 layers. Since PSA
|
||||
Crypto does not support restartable operations, there's a clear conflict: the
|
||||
TLS and X.509 layers can't both use only PSA APIs and get restartable
|
||||
behaviour.
|
||||
|
||||
Support for restartable (aka interruptible) ECDSA sign/verify operation was
|
||||
added to PSA in Mbed TLS 3.4, but support for ECDH is not present yet.
|
||||
|
||||
It will then require follow-up work to make use of the new PSA APIs in
|
||||
PK/X.509/TLS in all places where we currently allow restartable operations.
|
||||
|
||||
### Backward compatibility issues with making `MBEDTLS_USE_PSA_CRYPTO` always on
|
||||
|
||||
1. Existing applications may not be calling `psa_crypto_init()` before using
|
||||
TLS, X.509 or PK. We can try to work around that by calling (the relevant
|
||||
part of) it ourselves under the hood as needed, but that would likely require
|
||||
splitting init between the parts that can fail and the parts that can't (see
|
||||
<https://github.com/ARM-software/psa-crypto-api/pull/536> for that).
|
||||
2. It's currently not possible to enable `MBEDTLS_PSA_CRYPTO_C` in
|
||||
configurations that don't have `MBEDTLS_ENTROPY_C`, and we can't just
|
||||
auto-enable the latter, as it won't build or work out of the box on all
|
||||
platforms. There are two kinds of things we'd need to do if we want to work
|
||||
around that:
|
||||
1. Make it possible to enable the parts of PSA Crypto that don't require an
|
||||
RNG (typically, public key operations, symmetric crypto, some key
|
||||
management functions (destroy etc)) in configurations that don't have
|
||||
`ENTROPY_C`. This requires going through the PSA code base to adjust
|
||||
dependencies. Risk: there may be annoying dependencies, some of which may be
|
||||
surprising.
|
||||
2. For operations that require an RNG, provide an alternative function
|
||||
accepting an explicit `f_rng` parameter (see #5238), that would be
|
||||
available in entropy-less builds. (Then code using those functions still needs
|
||||
to have one version using it, for entropy-less builds, and one version using
|
||||
the standard function, for driver support in build with entropy.)
|
||||
|
||||
See <https://github.com/Mbed-TLS/mbedtls/issues/5156>.
|
||||
|
||||
Taking advantage of the existing abstractions layers - or not
|
||||
=============================================================
|
||||
|
||||
The Crypto library in Mbed TLS currently has 3 abstraction layers that offer
|
||||
algorithm-agnostic APIs for a class of algorithms:
|
||||
|
||||
- MD for messages digests aka hashes (including HMAC)
|
||||
- Cipher for symmetric ciphers (included AEAD)
|
||||
- PK for asymmetric (aka public-key) cryptography (excluding key exchange)
|
||||
|
||||
Note: key exchange (FFDH, ECDH) is not covered by an abstraction layer.
|
||||
|
||||
These abstraction layers typically provide, in addition to the API for crypto
|
||||
operations, types and numerical identifiers for algorithms (for
|
||||
example `mbedtls_cipher_mode_t` and its values). The
|
||||
current strategy is to keep using those identifiers in most of the code, in
|
||||
particular in existing structures and public APIs, even when
|
||||
`MBEDTLS_USE_PSA_CRYPTO` is enabled. (This is not an issue for G1, G2, G3
|
||||
above, and is only potentially relevant for G4.)
|
||||
|
||||
The are multiple strategies that can be used regarding the place of those
|
||||
layers in the migration to PSA.
|
||||
|
||||
Silently call to PSA from the abstraction layer
|
||||
-----------------------------------------------
|
||||
|
||||
- Provide a new definition (conditionally on `USE_PSA_CRYPTO`) of wrapper
|
||||
functions in the abstraction layer, that calls PSA instead of the legacy
|
||||
crypto API.
|
||||
- Upside: changes contained to a single place, no need to change TLS or X.509
|
||||
code anywhere.
|
||||
- Downside: tricky to implement if the PSA implementation is currently done on
|
||||
top of that layer (dependency loop).
|
||||
|
||||
This strategy is currently (early 2023) used for all operations in the PK
|
||||
layer; the MD layer uses a variant where it dispatches to PSA if a driver is
|
||||
available and the driver subsystem has been initialized, regardless of whether
|
||||
`USE_PSA_CRYPTO` is enabled; see `md-cipher-dispatch.md` in the same directory
|
||||
for details.
|
||||
|
||||
This strategy is not very well suited to the Cipher layer, as the PSA
|
||||
implementation is currently done on top of that layer.
|
||||
|
||||
This strategy will probably be used for some time for the PK layer, while we
|
||||
figure out what the future of that layer is: parts of it (parse/write, ECDSA
|
||||
signatures in the format that X.509 & TLS want) are not covered by PSA, so
|
||||
they will need to keep existing in some way. (Also, the PK layer is a good
|
||||
place for dispatching to either PSA or `mbedtls_xxx_restartable` while that
|
||||
part is not covered by PSA yet, if we decide to do that.)
|
||||
|
||||
Replace calls for each operation
|
||||
--------------------------------
|
||||
|
||||
- For every operation that's done through this layer in TLS or X.509, just
|
||||
replace function call with calls to PSA (conditionally on `USE_PSA_CRYPTO`)
|
||||
- Upside: conceptually simple, and if the PSA implementation is currently done
|
||||
on top of that layer, avoids concerns about dependency loops.
|
||||
- Upside: opens the door to building TLS/X.509 without that layer, saving some
|
||||
code size.
|
||||
- Downside: TLS/X.509 code has to be done for each operation.
|
||||
|
||||
This strategy is currently (early 2023) used for the MD layer and the Cipher
|
||||
layer in X.509 and TLS. Crypto modules however always call to MD which may
|
||||
then dispatch to PSA, see `md-cipher-dispatch.md`.
|
||||
|
||||
Opt-in use of PSA from the abstraction layer
|
||||
--------------------------------------------
|
||||
|
||||
- Provide a new way to set up a context that causes operations on that context
|
||||
to be done via PSA.
|
||||
- Upside: changes mostly contained in one place, TLS/X.509 code only needs to
|
||||
be changed when setting up the context, but not when using it. In
|
||||
particular, no changes to/duplication of existing public APIs that expect a
|
||||
key to be passed as a context of this layer (eg, `mbedtls_pk_context`).
|
||||
- Upside: avoids dependency loop when PSA implemented on top of that layer.
|
||||
- Downside: when the context is typically set up by the application, requires
|
||||
changes in application code.
|
||||
|
||||
This strategy is not useful when no context is used, for example with the
|
||||
one-shot function `mbedtls_md()`.
|
||||
|
||||
There are two variants of this strategy: one where using the new setup
|
||||
function also allows for key isolation (the key is only held by PSA,
|
||||
supporting both G1 and G2 in that area), and one without isolation (the key is
|
||||
still stored outside of PSA most of the time, supporting only G1).
|
||||
|
||||
This strategy, with support for key isolation, is currently (early 2022) used for
|
||||
private-key operations in the PK layer - see `mbedtls_pk_setup_opaque()`. This
|
||||
allows use of PSA-held private ECDSA keys in TLS and X.509 with no change to
|
||||
the TLS/X.509 code, but a contained change in the application.
|
||||
|
||||
This strategy, without key isolation, was also previously used (until 3.1
|
||||
included) in the Cipher layer - see `mbedtls_cipher_setup_psa()`. This allowed
|
||||
use of PSA for cipher operations in TLS with no change to the application
|
||||
code, and a contained change in TLS code. (It only supported a subset of
|
||||
ciphers.)
|
||||
|
||||
Note: for private key operations in the PK layer, both the "silent" and the
|
||||
"opt-in" strategy can apply, and can complement each other, as one provides
|
||||
support for key isolation, but at the (unavoidable) code of change in
|
||||
application code, while the other requires no application change to get
|
||||
support for drivers, but fails to provide isolation support.
|
||||
|
||||
Summary
|
||||
-------
|
||||
|
||||
Strategies currently (early 2022) used with each abstraction layer:
|
||||
|
||||
- PK (for G1): silently call PSA
|
||||
- PK (for G2): opt-in use of PSA (new key type)
|
||||
- Cipher (G1): replace calls at each call site
|
||||
- MD (G1, X.509 and TLS): replace calls at each call site (depending on
|
||||
`USE_PSA_CRYPTO`)
|
||||
- MD (G5): silently call PSA when a driver is available, see
|
||||
`md-cipher-dispatch.md`.
|
||||
|
||||
|
||||
Supporting builds with drivers without the software implementation
|
||||
==================================================================
|
||||
|
||||
This section presents a plan towards G5: save code size by compiling out our
|
||||
software implementation when a driver is available.
|
||||
|
||||
Let's expand a bit on the definition of the goal: in such a configuration
|
||||
(driver used, software implementation and abstraction layer compiled out),
|
||||
we want:
|
||||
|
||||
a. the library to build in a reasonably-complete configuration,
|
||||
b. with all tests passing,
|
||||
c. and no more tests skipped than the same configuration with software
|
||||
implementation.
|
||||
|
||||
Criterion (c) ensures not only test coverage, but that driver-based builds are
|
||||
at feature parity with software-based builds.
|
||||
|
||||
We can roughly divide the work needed to get there in the following steps:
|
||||
|
||||
0. Have a working driver interface for the algorithms we want to replace.
|
||||
1. Have users of these algorithms call to PSA or an abstraction layer than can
|
||||
dispatch to PSA, but not the low-level legacy API, for all operations.
|
||||
(This is G1, and for PK, X.509 and TLS this is controlled by
|
||||
`MBEDTLS_USE_PSA_CRYPTO`.) This needs to be done in the library and tests.
|
||||
2. Have users of these algorithms not depend on the legacy API for information
|
||||
management (getting a size for a given algorithm, etc.)
|
||||
3. Adapt compile-time guards used to query availability of a given algorithm;
|
||||
this needs to be done in the library (for crypto operations and data) and
|
||||
tests.
|
||||
|
||||
Note: the first two steps enable use of drivers, but not by themselves removal
|
||||
of the software implementation.
|
||||
|
||||
Note: the fact that step 1 is not achieved for all of libmbedcrypto (see
|
||||
below) is the reason why criterion (a) has "a reasonably-complete
|
||||
configuration", to allow working around internal crypto dependencies when
|
||||
working on other parts such as X.509 and TLS - for example, a configuration
|
||||
without RSA PKCS#1 v2.1 still allows reasonable use of X.509 and TLS.
|
||||
|
||||
Note: this is a conceptual division that will sometimes translate to how the
|
||||
work is divided into PRs, sometimes not. For example, in situations where it's
|
||||
not possible to achieve good test coverage at the end of step 1 or step 2, it
|
||||
is preferable to group with the next step(s) in the same PR until good test
|
||||
coverage can be reached.
|
||||
|
||||
**Status as of end of March 2023 (shortly after 3.4):**
|
||||
|
||||
- Step 0 is achieved for most algorithms, with only a few gaps remaining.
|
||||
- Step 1 is achieved for most of PK, X.509, and TLS when
|
||||
`MBEDTLS_USE_PSA_CRYPTO` is enabled with only a few gaps remaining (see
|
||||
docs/use-psa-crypto.md).
|
||||
- Step 1 is achieved for the crypto library regarding hashes: everything uses
|
||||
MD (not low-level hash APIs), which then dispatches to PSA if applicable.
|
||||
- Step 1 is not achieved for all of the crypto library when it come to
|
||||
ciphers. For example,`ctr_drbg.c` calls the legacy API `mbedtls_aes`.
|
||||
- Step 2 is achieved for most of X.509 and TLS (same gaps as step 1) when
|
||||
`MBEDTLS_USE_PSA_CRYPTO` is enabled.
|
||||
- Step 3 is done for hashes and top-level ECC modules (ECDSA, ECDH, ECJPAKE).
|
||||
|
||||
**Strategy for step 1:**
|
||||
|
||||
Regarding PK, X.509, and TLS, this is mostly achieved with only a few gaps.
|
||||
(The strategy was outlined in the previous section.)
|
||||
|
||||
Regarding libmbedcrypto:
|
||||
- for hashes and ciphers, see `md-cipher-dispatch.md` in the same directory;
|
||||
- for ECC, we have no internal uses of the top-level algorithms (ECDSA, ECDH,
|
||||
ECJPAKE), however they all depend on `ECP_C` which in turn depends on
|
||||
`BIGNUM_C`. So, direct calls from TLS, X.509 and PK to ECP and Bignum will
|
||||
need to be replaced; see <https://github.com/Mbed-TLS/mbedtls/issues/6839> and
|
||||
linked issues for a summary of intermediate steps and open points.
|
||||
|
||||
**Strategy for step 2:**
|
||||
|
||||
The most satisfying situation here is when we can just use the PSA Crypto API
|
||||
for information management as well. However sometimes it may not be
|
||||
convenient, for example in parts of the code that accept old-style identifiers
|
||||
(such as `mbedtls_md_type_t`) in their API and can't assume PSA to be
|
||||
compiled in (such as `rsa.c`).
|
||||
|
||||
When using an existing abstraction layer such as MD, it can provide
|
||||
information management functions. In other cases, information that was in a
|
||||
low-level module but logically belongs in a higher-level module can be moved
|
||||
to that module (for example, TLS identifiers of curves and there conversion
|
||||
to/from PSA or legacy identifiers belongs in TLS, not `ecp.c`).
|
||||
|
||||
**Strategy for step 3:**
|
||||
|
||||
There are currently two (complementary) ways for crypto-using code to check if a
|
||||
particular algorithm is supported: using `MBEDTLS_xxx` macros, and using
|
||||
`PSA_WANT_xxx` macros. For example, PSA-based code that want to use SHA-256
|
||||
will check for `PSA_WANT_ALG_SHA_256`, while legacy-based code that wants to
|
||||
use SHA-256 will check for `MBEDTLS_SHA256_C` if using the `mbedtls_sha256`
|
||||
API, or for `MBEDTLS_MD_C && MBEDTLS_SHA256_C` if using the `mbedtls_md` API.
|
||||
|
||||
Code that obeys `MBEDTLS_USE_PSA_CRYPTO` will want to use one of the two
|
||||
dependencies above depending on whether `MBEDTLS_USE_PSA_CRYPTO` is defined:
|
||||
if it is, the code want the algorithm available in PSA, otherwise, it wants it
|
||||
available via the legacy API(s) is it using (MD and/or low-level).
|
||||
|
||||
As much as possible, we're trying to create for each algorithm a single new
|
||||
macro that can be used to express dependencies everywhere (except pure PSA
|
||||
code that should always use `PSA_WANT`). For example, for hashes this is the
|
||||
`MBEDTLS_MD_CAN_xxx` family. For ECC algorithms, we have similar
|
||||
`MBEDTLS_PK_CAN_xxx` macros.
|
||||
|
||||
Note that in order to achieve that goal, even for code that obeys
|
||||
`USE_PSA_CRYPTO`, it is useful to impose that all algorithms that are
|
||||
available via the legacy APIs are also available via PSA.
|
||||
|
||||
Executing step 3 will mostly consist of using the right dependency macros in
|
||||
the right places (once the previous steps are done).
|
||||
|
||||
**Note on testing**
|
||||
|
||||
Since supporting driver-only builds is not about adding features, but about
|
||||
supporting existing features in new types of builds, testing will not involve
|
||||
adding cases to the test suites, but instead adding new components in `all.sh`
|
||||
that build and run tests in newly-supported configurations. For example, if
|
||||
we're making some part of the library work with hashes provided only by
|
||||
drivers when `MBEDTLS_USE_PSA_CRYPTO` is defined, there should be a place in
|
||||
`all.sh` that builds and run tests in such a configuration.
|
||||
|
||||
There is however a risk, especially in step 3 where we change how dependencies
|
||||
are expressed (sometimes in bulk), to get things wrong in a way that would
|
||||
result in more tests being skipped, which is easy to miss. Care must be
|
||||
taken to ensure this does not happen. The following criteria can be used:
|
||||
|
||||
1. The sets of tests skipped in the default config and the full config must be
|
||||
the same before and after the PR that implements step 3. This is tested
|
||||
manually for each PR that changes dependency declarations by using the script
|
||||
`outcome-analysis.sh` in the present directory.
|
||||
2. The set of tests skipped in the driver-only build is the same as in an
|
||||
equivalent software-based configuration. This is tested automatically by the
|
||||
CI in the "Results analysis" stage, by running
|
||||
`tests/scripts/analyze_outcomes.py`. See the
|
||||
`analyze_driver_vs_reference_xxx` actions in the script and the comments above
|
||||
their declaration for how to do that locally.
|
||||
|
||||
|
||||
Migrating away from the legacy API
|
||||
==================================
|
||||
|
||||
This section briefly introduces questions and possible plans towards G4,
|
||||
mainly as they relate to choices in previous stages.
|
||||
|
||||
The role of the PK/Cipher/MD APIs in user migration
|
||||
---------------------------------------------------
|
||||
|
||||
We're currently taking advantage of the existing PK layer in order
|
||||
to reduce the number of places where library code needs to be changed. It's
|
||||
only natural to consider using the same strategy (with the PK, MD and Cipher
|
||||
layers) for facilitating migration of application code.
|
||||
|
||||
Note: a necessary first step for that would be to make sure PSA is no longer
|
||||
implemented of top of the concerned layers
|
||||
|
||||
### Zero-cost compatibility layer?
|
||||
|
||||
The most favourable case is if we can have a zero-cost abstraction (no
|
||||
runtime, RAM usage or code size penalty), for example just a bunch of
|
||||
`#define`s, essentially mapping `mbedtls_` APIs to their `psa_` equivalent.
|
||||
|
||||
Unfortunately that's unlikely to fully work. For example, the MD layer uses the
|
||||
same context type for hashes and HMACs, while the PSA API (rightfully) has
|
||||
distinct operation types. Similarly, the Cipher layer uses the same context
|
||||
type for unauthenticated and AEAD ciphers, which again the PSA API
|
||||
distinguishes.
|
||||
|
||||
It is unclear how much value, if any, a zero-cost compatibility layer that's
|
||||
incomplete (for example, for MD covering only hashes, or for Cipher covering
|
||||
only AEAD) or differs significantly from the existing API (for example,
|
||||
introducing new context types) would provide to users.
|
||||
|
||||
### Low-cost compatibility layers?
|
||||
|
||||
Another possibility is to keep most or all of the existing API for the PK, MD
|
||||
and Cipher layers, implemented on top of PSA, aiming for the lowest possible
|
||||
cost. For example, `mbedtls_md_context_t` would be defined as a (tagged) union
|
||||
of `psa_hash_operation_t` and `psa_mac_operation_t`, then `mbedtls_md_setup()`
|
||||
would initialize the correct part, and the rest of the functions be simple
|
||||
wrappers around PSA functions. This would vastly reduce the complexity of the
|
||||
layers compared to the existing (no need to dispatch through function
|
||||
pointers, just call the corresponding PSA API).
|
||||
|
||||
Since this would still represent a non-zero cost, not only in terms of code
|
||||
size, but also in terms of maintenance (testing, etc.) this would probably
|
||||
be a temporary solution: for example keep the compatibility layers in 4.0 (and
|
||||
make them optional), but remove them in 5.0.
|
||||
|
||||
Again, this provides the most value to users if we can manage to keep the
|
||||
existing API unchanged. Their might be conflicts between this goal and that of
|
||||
reducing the cost, and judgment calls may need to be made.
|
||||
|
||||
Note: when it comes to holding public keys in the PK layer, depending on how
|
||||
the rest of the code is structured, it may be worth holding the key data in
|
||||
memory controlled by the PK layer as opposed to a PSA key slot, moving it to a
|
||||
slot only when needed (see current `ecdsa_verify_wrap` when
|
||||
`MBEDTLS_USE_PSA_CRYPTO` is defined) For example, when parsing a large
|
||||
number, N, of X.509 certificates (for example the list of trusted roots), it
|
||||
might be undesirable to use N PSA key slots for their public keys as long as
|
||||
the certs are loaded. OTOH, this could also be addressed by merging the "X.509
|
||||
parsing on-demand" (#2478), and then the public key data would be held as
|
||||
bytes in the X.509 CRT structure, and only moved to a PK context / PSA slot
|
||||
when it's actually used.
|
||||
|
||||
Note: the PK layer actually consists of two relatively distinct parts: crypto
|
||||
operations, which will be covered by PSA, and parsing/writing (exporting)
|
||||
from/to various formats, which is currently not fully covered by the PSA
|
||||
Crypto API.
|
||||
|
||||
### Algorithm identifiers and other identifiers
|
||||
|
||||
It should be easy to provide the user with a bunch of `#define`s for algorithm
|
||||
identifiers, for example `#define MBEDTLS_MD_SHA256 PSA_ALG_SHA_256`; most of
|
||||
those would be in the MD, Cipher and PK compatibility layers mentioned above,
|
||||
but there might be some in other modules that may be worth considering, for
|
||||
example identifiers for elliptic curves.
|
||||
|
||||
### Lower layers
|
||||
|
||||
Generally speaking, we would retire all of the low-level, non-generic modules,
|
||||
such as AES, SHA-256, RSA, DHM, ECDH, ECP, bignum, etc, without providing
|
||||
compatibility APIs for them. People would be encouraged to switch to the PSA
|
||||
API. (The compatibility implementation of the existing PK, MD, Cipher APIs
|
||||
would mostly benefit people who already used those generic APis rather than
|
||||
the low-level, alg-specific ones.)
|
||||
|
||||
### APIs in TLS and X.509
|
||||
|
||||
Public APIs in TLS and X.509 may be affected by the migration in at least two
|
||||
ways:
|
||||
|
||||
1. APIs that rely on a legacy `mbedtls_` crypto type: for example
|
||||
`mbedtls_ssl_conf_own_cert()` to configure a (certificate and the
|
||||
associated) private key. Currently the private key is passed as a
|
||||
`mbedtls_pk_context` object, which would probably change to a `psa_key_id_t`.
|
||||
Since some users would probably still be using the compatibility PK layer, it
|
||||
would need a way to easily extract the PSA key ID from the PK context.
|
||||
|
||||
2. APIs the accept list of identifiers: for example
|
||||
`mbedtls_ssl_conf_curves()` taking a list of `mbedtls_ecp_group_id`s. This
|
||||
could be changed to accept a list of pairs (`psa_ecc_family_t`, size) but we
|
||||
should probably take this opportunity to move to a identifier independent from
|
||||
the underlying crypto implementation and use TLS-specific identifiers instead
|
||||
(based on IANA values or custom enums), as is currently done in the new
|
||||
`mbedtls_ssl_conf_groups()` API, see #4859).
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
An question that needs careful consideration when we come around to removing
|
||||
the low-level crypto APIs and making PK, MD and Cipher optional compatibility
|
||||
layers is to be sure to preserve testing quality. A lot of the existing test
|
||||
cases use the low level crypto APIs; we would need to either keep using that
|
||||
API for tests, or manually migrate tests to the PSA Crypto API. Perhaps a
|
||||
combination of both, perhaps evolving gradually over time.
|
@ -11,7 +11,7 @@
|
||||
#
|
||||
# Usage:
|
||||
# - build the library with debug symbols and the config you're interested in
|
||||
# (default, full minus MBEDTLS_USE_PSA_CRYPTO, full, etc.)
|
||||
# (default, full, etc.)
|
||||
# - launch this script with 1 or more arguments depending on the analysis' goal:
|
||||
# - if only 1 argument is used (which is the name of the used config,
|
||||
# ex: full), then the analysis is done on libmbedx509 and libmbedtls
|
||||
|
@ -1,99 +0,0 @@
|
||||
Testing strategy for `MBEDTLS_USE_PSA_CRYPTO`
|
||||
=============================================
|
||||
|
||||
This document records the testing strategy used so far in implementing
|
||||
`MBEDTLS_USE_PSA_CRYPTO`.
|
||||
|
||||
|
||||
General considerations
|
||||
----------------------
|
||||
|
||||
There needs to be at least one build in `all.sh` that enables
|
||||
`MBEDTLS_USE_PSA_CRYPTO` and runs the full battery of tests; currently that's
|
||||
ensured by the fact that `scripts/config.py full` enables
|
||||
`MBEDTLS_USE_PSA_CRYPTO`. There needs to be at least one build with
|
||||
`MBEDTLS_USE_PSA_CRYPTO` disabled (as long as it's optional); currently that's
|
||||
ensured by the fact that it's disabled in the default config.
|
||||
|
||||
Generally, code review is enough to ensure that PSA APIs are indeed used where
|
||||
they should be when `MBEDTLS_USE_PSA_CRYPTO` is enabled.
|
||||
|
||||
However, when it comes to TLS, we also have the option of using debug messages
|
||||
to confirm which code path is taken. This is generally unnecessary, except when
|
||||
a decision is made at run-time about whether to use the PSA or legacy code
|
||||
path. (For example, for record protection, previously (until 3.1), some ciphers were supported
|
||||
via PSA while some others weren't, with a run-time fallback. In this case, it's
|
||||
good to have a debug message checked by the test case to confirm that the
|
||||
right decision was made at run-time, i. e. that we didn't use the fallback for
|
||||
ciphers that are supposed to be supported.)
|
||||
|
||||
|
||||
New APIs meant for application use
|
||||
----------------------------------
|
||||
|
||||
For example, `mbedtls_pk_setup_opaque()` is meant to be used by applications
|
||||
in order to create PK contexts that can then be passed to existing TLS and
|
||||
X.509 APIs (which remain unchanged).
|
||||
|
||||
In that case, we want:
|
||||
|
||||
- unit testing of the new API and directly-related APIs - for example:
|
||||
- in `test_suite_pk` we have a new test function `pk_psa_utils` that exercises
|
||||
`mbedtls_pk_setup_opaque()` and checks that various utility functions
|
||||
(`mbedtls_pk_get_type()` etc.) work and the functions that are expected to
|
||||
fail (`mbedtls_pk_verify()` etc) return the expected error.
|
||||
- in `test_suite_pk` we modified the existing `pk_psa_sign` test function to
|
||||
check that signature generation works as expected
|
||||
- in `test_suite_pkwrite` we should have a new test function checking that
|
||||
exporting (writing out) the public part of the key works as expected and
|
||||
that exporting the private key fails as expected.
|
||||
- integration testing of the new API with each existing API which should
|
||||
accepts a context created this way - for example:
|
||||
- in `programs/ssl/ssl_client2` a new option `key_opaque` that causes the
|
||||
new API to be used, and one or more tests in `ssl-opt.sh` using that.
|
||||
(We should have the same server-side.)
|
||||
- in `test_suite_x509write` we have a new test function
|
||||
`x509_csr_check_opaque()` checking integration of the new API with the
|
||||
existing `mbedtls_x509write_csr_set_key()`. (And also
|
||||
`mbedtls_x509write_crt_set_issuer_key()` since #5710.)
|
||||
|
||||
For some APIs, for example with `mbedtls_ssl_conf_psk_opaque()`, testing in
|
||||
`test_suite_ssl` was historically not possible, so we only have testing in
|
||||
`ssl-opt.sh`.
|
||||
|
||||
New APIs meant for internal use
|
||||
-------------------------------
|
||||
|
||||
For example, `mbedtls_cipher_setup_psa()` (no longer used, soon to be
|
||||
deprecated - #5261) was meant to be used by the TLS layer, but probably not
|
||||
directly by applications.
|
||||
|
||||
In that case, we want:
|
||||
|
||||
- unit testing of the new API and directly-related APIs - for example:
|
||||
- in `test_suite_cipher`, the existing test functions `auth_crypt_tv` and
|
||||
`test_vec_crypt` gained a new parameter `use_psa` and corresponding test
|
||||
cases
|
||||
- integration testing:
|
||||
- usually already covered by existing tests for higher-level modules:
|
||||
- for example simple use of `mbedtls_cipher_setup_psa()` in TLS is already
|
||||
covered by running the existing TLS tests in a build with
|
||||
`MBEDTLS_USA_PSA_CRYPTO` enabled
|
||||
- however if use of the new API in higher layers involves more logic that
|
||||
use of the old API, specific integrations test may be required
|
||||
- for example, the logic to fall back from `mbedtls_cipher_setup_psa()` to
|
||||
`mbedtls_cipher_setup()` in TLS is tested by `run_test_psa` in
|
||||
`ssl-opt.sh`.
|
||||
|
||||
Internal changes
|
||||
----------------
|
||||
|
||||
For example, use of PSA to compute the TLS 1.2 PRF.
|
||||
|
||||
Changes in this category rarely require specific testing, as everything should
|
||||
be already be covered by running the existing tests in a build with
|
||||
`MBEDTLS_USE_PSA_CRYPTO` enabled; however we need to make sure the existing
|
||||
test have sufficient coverage, and improve them if necessary.
|
||||
|
||||
However, if additional logic is involved, or there are run-time decisions about
|
||||
whether to use the PSA or legacy code paths, specific tests might be in order.
|
@ -126,7 +126,6 @@ Support description
|
||||
| MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED | n/a |
|
||||
| | |
|
||||
| MBEDTLS_PSA_CRYPTO_C | no (1) |
|
||||
| MBEDTLS_USE_PSA_CRYPTO | yes |
|
||||
|
||||
(1) These options must remain in their default state of enabled.
|
||||
(2) See the TLS 1.3 specific build options section below.
|
||||
|
@ -4,10 +4,6 @@ default: all
|
||||
|
||||
all_markdown = \
|
||||
config-split.md \
|
||||
psa-conditional-inclusion-c.md \
|
||||
psa-driver-developer-guide.md \
|
||||
psa-driver-integration-guide.md \
|
||||
psa-driver-interface.md \
|
||||
# This line is intentionally left blank
|
||||
|
||||
html: $(all_markdown:.md=.html)
|
||||
|
@ -290,7 +290,6 @@ PSA_WANT_\* macros as in current `crypto_config.h`.
|
||||
//#define MBEDTLS_SHA512_SMALLER
|
||||
//#define MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT
|
||||
//#define MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY
|
||||
//#define MBEDTLS_USE_PSA_CRYPTO
|
||||
|
||||
//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1
|
||||
//#define MBEDTLS_ECP_WINDOW_SIZE 4
|
||||
|
@ -50,8 +50,6 @@ Then use the [summary of API modules](#summary-of-api-modules), the table of con
|
||||
|
||||
To make the PSA API available, make sure that the configuration option [`MBEDTLS_PSA_CRYPTO_C`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/mbedtls__config_8h/#c.MBEDTLS_PSA_CRYPTO_C) is enabled. (It is enabled in the default configuration.)
|
||||
|
||||
You should probably enable [`MBEDTLS_USE_PSA_CRYPTO`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/mbedtls__config_8h/#mbedtls__config_8h_1a70fd7b97d5f11170546583f2095942a6) as well (it is disabled by default). This option causes the PK, X.509 and TLS modules to use PSA crypto under the hood.
|
||||
|
||||
By default, the PSA crypto API offers a similar set of cryptographic mechanisms as those offered by the legacy API (configured by `MBEDTLS_XXX` macros). The PSA crypto API also has its own configuration mechanism; see “[Cryptographic mechanism availability](#cryptographic-mechanism-availability)”.
|
||||
|
||||
### Header files
|
||||
@ -228,7 +226,7 @@ The PSA Crypto API may use accelerator drivers. In this case any options control
|
||||
|
||||
In the Mbed TLS legacy interface, you can replace some cryptographic primitives and modes by an alternative implementation, by enabling configuration options of the form `MBEDTLS_xxx_ALT` and linking with your own implementation of the affected function or module. Alternative implementations remain supported in Mbed TLS 3.x even if the application code uses the PSA API. However, they will be removed from the next version of the library.
|
||||
|
||||
The corresponding PSA feature is accelerator drivers. To implement an accelerator driver, see the [PSA cryptoprocessor driver example and guide](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/psa-driver-example-and-guide.md). In an application that uses both the legacy interface and the PSA interface for the same mechanism, only some algorithms support calling a PSA driver from the legacy interface. See the [Guide to driver-only builds](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/driver-only-builds.md) for more information.
|
||||
The corresponding PSA feature is accelerator drivers. To implement an accelerator driver, see the [PSA cryptoprocessor driver example and guide](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/psa-driver-example-and-guide.md). In an application that uses both the legacy interface and the PSA interface for the same mechanism, only some algorithms support calling a PSA driver from the legacy interface. See the [Guide to driver-only builds](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/driver-only-builds.md) for more information.
|
||||
|
||||
### Self-tests
|
||||
|
||||
@ -908,7 +906,7 @@ This section discusses how to use a PSA key in a context that requires a PK obje
|
||||
|
||||
* [`mbedtls_pk_copy_from_psa`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/pk_8h/#pk_8h_1ab8e88836fd9ee344ffe630c40447bd08) copies a PSA key into a PK object. The PSA key must be exportable. The PK object remains valid even if the PSA key is destroyed.
|
||||
* [`mbedtls_pk_copy_public_from_psa`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/pk_8h/#pk_8h_1a2a50247a528889c12ea0ddddb8b15a4e) copies the public part of a PSA key into a PK object. The PK object remains valid even if the PSA key is destroyed.
|
||||
* [`mbedtls_pk_setup_opaque`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/pk_8h/#pk_8h_1a4c04ac22ab9c1ae09cc29438c308bf05) sets up a PK object that wraps the PSA key. This functionality is only available when `MBEDTLS_USE_PSA_CRYPTO` is enabled. The PK object has the type `MBEDTLS_PK_OPAQUE` regardless of whether the key is an RSA or ECC key. The PK object can only be used as permitted by the PSA key's policy. The PK object contains a reference to the PSA key identifier, therefore PSA key must not be destroyed as long as the PK object remains alive.
|
||||
* [`mbedtls_pk_setup_opaque`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/pk_8h/#pk_8h_1a4c04ac22ab9c1ae09cc29438c308bf05) sets up a PK object that wraps the PSA key. The PK object has the type `MBEDTLS_PK_OPAQUE` regardless of whether the key is an RSA or ECC key. The PK object can only be used as permitted by the PSA key's policy. The PK object contains a reference to the PSA key identifier, therefore PSA key must not be destroyed as long as the PK object remains alive.
|
||||
|
||||
Here is some sample code illustrating how to use the PK module to format a PSA public key or the public key of a PSA key pair.
|
||||
```
|
||||
@ -1278,7 +1276,7 @@ The PSA API is a cryptography API, not an arithmetic API. As a consequence, ther
|
||||
|
||||
#### RSA-ALT interface
|
||||
|
||||
Implementers of the RSA-ALT interface (`MBEDTLS_PK_RSA_ALT` pk type, `mbedtls_pk_setup_rsa_alt` setup function) should migrate to the [PSA cryptoprocessor driver interface](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/psa-driver-example-and-guide.md).
|
||||
Implementers of the RSA-ALT interface (`MBEDTLS_PK_RSA_ALT` pk type, `mbedtls_pk_setup_rsa_alt` setup function) should migrate to the [PSA cryptoprocessor driver interface](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/psa-driver-example-and-guide.md).
|
||||
|
||||
* If the purpose of the ALT interface is acceleration only: use the accelerator driver interface. This is fully transparent to application code.
|
||||
* If the purpose of the ALT interface is to isolate the private key in a high-security environment: use the opaque driver interface. This is mostly transparent to user code. Code that uses a key via its key identifier does not need to know whether the key is transparent (equivalent of `MBEDTLS_PK_RSA`) or opaque (equivalent of `MBEDTLS_PK_RSA_ALT`). When creating a key, it will be transparent by default; to create an opaque key, call [`psa_set_key_lifetime`](https://mbed-tls.readthedocs.io/projects/api/en/development/api/group/group__attributes/#group__attributes_1gac03ccf09ca6d36cc3d5b43f8303db6f7) to set the key's location to the chosen location value for the driver, e.g.
|
||||
|
@ -1,169 +0,0 @@
|
||||
This document describes the compile-time configuration option
|
||||
`MBEDTLS_USE_PSA_CRYPTO` from a user's perspective.
|
||||
|
||||
This option:
|
||||
- makes the X.509 and TLS libraries use PSA for cryptographic operations as
|
||||
much as possible, see "Internal changes" below;
|
||||
- enables new APIs for using keys handled by PSA Crypto, such as
|
||||
`mbedtls_pk_setup_opaque()` and `mbedtls_ssl_conf_psk_opaque()`, see
|
||||
"New APIs / API extensions" below.
|
||||
|
||||
General considerations
|
||||
----------------------
|
||||
|
||||
**Application code:** when this option is enabled, you need to call
|
||||
`psa_crypto_init()` before calling any function from the SSL/TLS, X.509 or PK
|
||||
modules, except for the various mbedtls_xxx_init() functions which can be called
|
||||
at any time.
|
||||
|
||||
**Why enable this option:** to fully take advantage of PSA drivers in PK,
|
||||
X.509 and TLS. For example, enabling this option is what allows use of drivers
|
||||
for ECDSA, ECDH and EC J-PAKE in those modules. However, note that even with
|
||||
this option disabled, some code in PK, X.509, TLS or the crypto library might
|
||||
still use PSA drivers, if it can determine it's safe to do so; currently
|
||||
that's the case for hashes.
|
||||
|
||||
**Relationship with other options:** This option depends on
|
||||
`MBEDTLS_PSA_CRYPTO_C`. These two options differ in the following way:
|
||||
- `MBEDTLS_PSA_CRYPTO_C` enables the implementation of the PSA Crypto API.
|
||||
When it is enabled, `psa_xxx()` APIs are available and you must call
|
||||
`psa_crypto_init()` before you call any other `psa_xxx()` function. Other
|
||||
modules in the library (non-PSA crypto APIs, X.509, TLS) may or may not use
|
||||
PSA Crypto but you're not required to call `psa_crypto_init()` before calling
|
||||
non-PSA functions, unless explicitly documented (TLS 1.3).
|
||||
- `MBEDTLS_USE_PSA_CRYPTO` means that X.509 and TLS will use PSA Crypto as
|
||||
much as possible (that is, everywhere except for features that are not
|
||||
supported by PSA Crypto, see "Internal Changes" below for a complete list of
|
||||
exceptions). When it is enabled, you need to call `psa_crypto_init()` before
|
||||
calling any function from PK, X.509 or TLS; however it doesn't change anything
|
||||
for the rest of the library.
|
||||
|
||||
**Scope:** `MBEDTLS_USE_PSA_CRYPTO` has no effect on modules other than PK,
|
||||
X.509 and TLS. It also has no effect on most of the TLS 1.3 code, which always
|
||||
uses PSA crypto. The parts of the TLS 1.3 code that will use PSA Crypto or not
|
||||
depending on this option being set or not are:
|
||||
- record protection;
|
||||
- running handshake hash;
|
||||
- asymmetric signature verification & generation;
|
||||
- X.509 certificate chain verification.
|
||||
You need to enable `MBEDTLS_USE_PSA_CRYPTO` if you want TLS 1.3 to use PSA
|
||||
everywhere.
|
||||
|
||||
**Historical note:** This option was introduced at a time when PSA Crypto was
|
||||
still beta and not ready for production, so we made its use in X.509 and TLS
|
||||
opt-in: by default, these modules would keep using the stable,
|
||||
production-ready legacy (pre-PSA) crypto APIs. So, the scope of was X.509 and
|
||||
TLS, as well as some of PK for technical reasons. Nowadays PSA Crypto is no
|
||||
longer beta, and production quality, so there's no longer any reason to make
|
||||
its use in other modules opt-in. However, PSA Crypto functions require that
|
||||
`psa_crypto_init()` has been called before their use, and for backwards
|
||||
compatibility reasons we can't impose this requirement on non-PSA functions
|
||||
that didn't have such a requirement before. So, nowadays the main meaning of
|
||||
`MBEDTLS_USE_PSA_CRYPTO` is that the user promises to call `psa_crypto_init()`
|
||||
before calling any PK, X.509 or TLS functions. For the same compatibility
|
||||
reasons, we can't extend its scope. However, new modules in the library, such
|
||||
as TLS 1.3, can be introduced with a requirement to call `psa_crypto_init()`.
|
||||
|
||||
New APIs / API extensions
|
||||
-------------------------
|
||||
|
||||
### PSA-held (opaque) keys in the PK layer
|
||||
|
||||
**New API function:** `mbedtls_pk_setup_opaque()` - can be used to
|
||||
wrap a PSA key pair into a PK context. The key can be used for private-key
|
||||
operations and its public part can be exported.
|
||||
|
||||
**Benefits:** isolation of long-term secrets, use of PSA Crypto drivers.
|
||||
|
||||
**Limitations:** please refer to the documentation of `mbedtls_pk_setup_opaque()`
|
||||
for a full list of supported operations and limitations.
|
||||
|
||||
**Use in X.509 and TLS:** opt-in. The application needs to construct the PK context
|
||||
using the new API in order to get the benefits; it can then pass the
|
||||
resulting context to the following existing APIs:
|
||||
|
||||
- `mbedtls_ssl_conf_own_cert()` or `mbedtls_ssl_set_hs_own_cert()` to use the
|
||||
key together with a certificate for certificate-based key exchanges;
|
||||
- `mbedtls_x509write_csr_set_key()` to generate a CSR (certificate signature
|
||||
request);
|
||||
- `mbedtls_x509write_crt_set_issuer_key()` to generate a certificate.
|
||||
|
||||
### PSA-held (opaque) keys for TLS pre-shared keys (PSK)
|
||||
|
||||
**New API functions:** `mbedtls_ssl_conf_psk_opaque()` and
|
||||
`mbedtls_ssl_set_hs_psk_opaque()`. Call one of these from an application to
|
||||
register a PSA key for use with a PSK key exchange.
|
||||
|
||||
**Benefits:** isolation of long-term secrets.
|
||||
|
||||
**Limitations:** none.
|
||||
|
||||
**Use in TLS:** opt-in. The application needs to register the key using one of
|
||||
the new APIs to get the benefits.
|
||||
|
||||
### PSA-held (opaque) keys for TLS 1.2 EC J-PAKE key exchange
|
||||
|
||||
**New API function:** `mbedtls_ssl_set_hs_ecjpake_password_opaque()`.
|
||||
Call this function from an application to register a PSA key for use with the
|
||||
TLS 1.2 EC J-PAKE key exchange.
|
||||
|
||||
**Benefits:** isolation of long-term secrets.
|
||||
|
||||
**Limitations:** none.
|
||||
|
||||
**Use in TLS:** opt-in. The application needs to register the key using one of
|
||||
the new APIs to get the benefits.
|
||||
|
||||
### PSA-based operations in the Cipher layer
|
||||
|
||||
There is a new API function `mbedtls_cipher_setup_psa()` to set up a context
|
||||
that will call PSA to store the key and perform the operations.
|
||||
|
||||
This function only worked for a small number of ciphers. It is now deprecated
|
||||
and it is recommended to use `psa_cipher_xxx()` or `psa_aead_xxx()` functions
|
||||
directly instead.
|
||||
|
||||
**Warning:** This function will be removed in a future version of Mbed TLS. If
|
||||
you are using it and would like us to keep it, please let us know about your
|
||||
use case.
|
||||
|
||||
Internal changes
|
||||
----------------
|
||||
|
||||
All of these internal changes are active as soon as `MBEDTLS_USE_PSA_CRYPTO`
|
||||
is enabled, no change required on the application side.
|
||||
|
||||
### TLS: most crypto operations based on PSA
|
||||
|
||||
Current exceptions:
|
||||
|
||||
- Finite-field (non-EC) Diffie-Hellman (used in key exchanges: DHE-RSA,
|
||||
DHE-PSK).
|
||||
- Restartable operations when `MBEDTLS_ECP_RESTARTABLE` is also enabled (see
|
||||
the documentation of that option).
|
||||
|
||||
Other than the above exceptions, all crypto operations are based on PSA when
|
||||
`MBEDTLS_USE_PSA_CRYPTO` is enabled.
|
||||
|
||||
### X.509: most crypto operations based on PSA
|
||||
|
||||
Current exceptions:
|
||||
|
||||
- Restartable operations when `MBEDTLS_ECP_RESTARTABLE` is also enabled (see
|
||||
the documentation of that option).
|
||||
|
||||
Other than the above exception, all crypto operations are based on PSA when
|
||||
`MBEDTLS_USE_PSA_CRYPTO` is enabled.
|
||||
|
||||
### PK layer: most crypto operations based on PSA
|
||||
|
||||
Current exceptions:
|
||||
|
||||
- Verification of RSA-PSS signatures with an MGF hash that's different from
|
||||
the message hash.
|
||||
- Restartable operations when `MBEDTLS_ECP_RESTARTABLE` is also enabled (see
|
||||
the documentation of that option).
|
||||
|
||||
Other than the above exceptions, all crypto operations are based on PSA when
|
||||
`MBEDTLS_USE_PSA_CRYPTO` is enabled.
|
||||
|
Loading…
x
Reference in New Issue
Block a user