quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

md-cipher-dispatch.md (43030B)


      1 PSA migration strategy for hashes and ciphers
      2 =============================================
      3 
      4 ## Introduction
      5 
      6 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.
      7 
      8 ### Relationship with the main strategy document
      9 
     10 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.
     11 
     12 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.
     13 
     14 ## Requirements
     15 
     16 ### User stories
     17 
     18 #### Backward compatibility user story
     19 
     20 As a developer of an application that uses Mbed TLS's interfaces (including legacy crypto),
     21 I want Mbed TLS to preserve backward compatibility,
     22 so that my code keeps working in new minor versions of Mbed TLS.
     23 
     24 #### Interface design user story
     25 
     26 As a developer of library code that uses Mbed TLS to perform cryptographic operations,
     27 I want to know which functions to call and which feature macros to check,
     28 so that my code works in all Mbed TLS configurations.
     29 
     30 Note: this is the same problem we face in X.509 and TLS.
     31 
     32 #### Hardware accelerator vendor user stories
     33 
     34 As a vendor of a platform with hardware acceleration for some crypto,
     35 I want to build Mbed TLS in a way that uses my hardware wherever relevant,
     36 so that my customers maximally benefit from my hardware.
     37 
     38 As a vendor of a platform with hardware acceleration for some crypto,
     39 I want to build Mbed TLS without software that replicates what my hardware does,
     40 to minimize the code size.
     41 
     42 #### Integrators of Mbed TLS alongside a PSA Crypto provider
     43 
     44 I have a platform where the PSA Crypto is already provided "externally" from
     45 Mbed TLS (ex: through TF-M in Zephyr) and I would like Mbed TLS to make use
     46 of it whenever possible in order to benefit from higher performances (if some
     47 hardware acceleration is supported in the provider) and/or higher isolation/security
     48 (if the PSA provider is running in a completetly separated/inaccessible context).
     49 
     50 #### Maintainer user stories
     51 
     52 As a maintainer of Mbed TLS,
     53 I want to have clear rules for when to use which interface,
     54 to avoid bugs in “unusual” configurations.
     55 
     56 As a maintainer of Mbed TLS,
     57 I want to avoid duplicating code,
     58 because this is inefficient and error-prone.
     59 
     60 ### Use PSA more
     61 
     62 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).
     63 
     64 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:
     65 
     66 * Where a PSA driver/provider is available, it likely has better performance, and sometimes better security, than the built-in software implementation.
     67 * In many scenarios, where a PSA driver/provider is available, this allows removing the software implementation altogether.
     68 * 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`.
     69 
     70 ### Correct dependencies
     71 
     72 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.
     73 
     74 ### Backward compatibility
     75 
     76 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.
     77 
     78 #### Changeable configuration options
     79 
     80 The following configuration options are described as experimental, and are likely to change at least marginally:
     81 
     82 * `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.
     83 * `MBEDTLS_PSA_CRYPTO_CONFIG`: “This feature is still experimental and is not ready for production since it is not completed.” We may want to change this, for example, to automatically enable more mechanisms (although this wouldn't be considered a backward compatibility break anyway, since we don't promise that you will not get a feature if you don't enable its `PSA_WANT_xxx`).
     84 
     85 ### Non-goals
     86 
     87 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.
     88 
     89 ## Problem analysis
     90 
     91 ### Scope analysis
     92 
     93 #### Limitations of `MBEDTLS_USE_PSA_CRYPTO`
     94 
     95 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.
     96 
     97 In this work, we want two things:
     98 
     99 * 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.
    100 * 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.
    101 
    102 #### Classification of callers
    103 
    104 We can classify code that implements or uses cryptographic mechanisms into several groups:
    105 
    106 * Software implementations of primitive cryptographic mechanisms. These are not expected to change.
    107 * 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.
    108 * Code implementing the PSA crypto interface. This is not expected to change, except perhaps to expose some internal functionality to overhauled glue code.
    109 * Code that's subject to `MBEDTLS_USE_PSA_CRYPTO`: `pk.h`, X.509, TLS (excluding parts specific TLS 1.3).
    110 * Code that always uses PSA for crypto: TLS 1.3 (except things common with 1.2), LMS.
    111 
    112 For the purposes of this work, three domains emerge:
    113 
    114 * **Legacy domain**: does not interact with PSA. Implementations of hashes, of cipher primitives, of arithmetic.
    115 * **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.
    116 * **PSA domain**: includes pk, X.509 and TLS when `MBEDTLS_USE_PSA_CRYPTO` is enabled. Also TLS 1.3, LMS.
    117 
    118 #### Non-use-PSA modules
    119 
    120 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.
    121 
    122 Hashes and HMAC (after the work on driver-only hashes):
    123 
    124 * entropy (hashes via MD-light)
    125 * ECDSA (HMAC\_DRBG; `md.h` exposed through API)
    126 * ECJPAKE (hashes via MD-light; `md.h` exposed through API)
    127 * MD (hashes and HMAC)
    128 * HKDF (HMAC via `md.h`; `md.h` exposed through API)
    129 * HMAC\_DRBG (hashes and HMAC via `md.h`; `md.h` exposed through API)
    130 * PKCS12 (hashes via MD-light)
    131 * PKCS5 (HMAC via `md.h`; `md.h` exposed through API)
    132 * PKCS7 (hashes via MD)
    133 * RSA (hash via MD-light for PSS and OAEP; `md.h` exposed through API)
    134 * PEM (MD5 hash via MD-light)
    135 
    136 Symmetric ciphers and AEADs (before work on driver-only cipher):
    137 
    138 * PEM:
    139   * AES, DES or 3DES in CBC mode without padding, decrypt only (!).
    140   * Currently using low-level non-generic APIs.
    141   * No hard dependency, features guarded by `AES_C` resp. `DES_C`.
    142   * Functions called: `setkey_dec()` + `crypt_cbc()`.
    143 * PKCS12:
    144   * In practice: 2DES or 3DES in CBC mode with PKCS7 padding, decrypt only
    145     (when called from pkparse).
    146   * In principle: any cipher-mode (default padding), passed an
    147     `mbedtls_cipher_type_t` as an argument, no documented restriction.
    148   * Cipher, generically, selected from ASN.1 or function parameters;
    149     no documented restriction but in practice TODO (inc. padding and
    150     en/decrypt, look at standards and tests)
    151   * Unconditional dependency on `CIPHER_C` in `check_config.h`.
    152   * Note: `cipher.h` exposed through API.
    153   * Functions called: `setup`, `setkey`, `set_iv`, `reset`, `update`, `finish` (in sequence, once).
    154 * PKCS5 (PBES2, `mbedtls_pkcs5_pbes2()`):
    155   * 3DES or DES in CBC mode with PKCS7 padding, both encrypt and decrypt.
    156   * Note: could also be AES in the future, see #7038.
    157   * Unconditional dependency on `CIPHER_C` in `check_config.h`.
    158   * Functions called: `setup`, `setkey`, `crypt`.
    159 * CTR\_DRBG:
    160   * AES in ECB mode, encrypt only.
    161   * Currently using low-level non-generic API (`aes.h`).
    162   * Unconditional dependency on `AES_C` in `check_config.h`.
    163   * Functions called: `setkey_enc`, `crypt_ecb`.
    164 * CCM:
    165   * AES, Camellia or Aria in ECB mode, encrypt only.
    166   * Unconditional dependency on `AES_C || CAMELLIA_C || ARIA_C` in `check_config.h`.
    167   * Unconditional dependency on `CIPHER_C` in `check_config.h`.
    168   * Note: also called by `cipher.c` if enabled.
    169   * Functions called: `info`, `setup`, `setkey`, `update` (several times) - (never finish)
    170 * CMAC:
    171   * AES or DES in ECB mode, encrypt only.
    172   * Unconditional dependency on `AES_C || DES_C` in `check_config.h`.
    173   * Unconditional dependency on `CIPHER_C` in `check_config.h`.
    174   * Note: also called by `cipher.c` if enabled.
    175   * Functions called: `info`, `setup`, `setkey`, `update` (several times) - (never finish)
    176 * GCM:
    177   * AES, Camellia or Aria in ECB mode, encrypt only.
    178   * Unconditional dependency on `AES_C || CAMELLIA_C || ARIA_C` in `check_config.h`.
    179   * Unconditional dependency on `CIPHER_C` in `check_config.h`.
    180   * Note: also called by `cipher.c` if enabled.
    181   * Functions called: `info`, `setup`, `setkey`, `update` (several times) - (never finish)
    182 * NIST\_KW:
    183   * AES in ECB mode, both encryt and decrypt.
    184   * Unconditional dependency on `AES_C || DES_C` in `check_config.h`.
    185   * Unconditional dependency on `CIPHER_C` in `check_config.h`.
    186   * Note: also called by `cipher.c` if enabled.
    187   * Note: `cipher.h` exposed through API.
    188   * Functions called: `info`, `setup`, `setkey`, `update` (several times) - (never finish)
    189 * Cipher:
    190   * potentially any cipher/AEAD in any mode and any direction
    191 
    192 Note: PSA cipher is built on Cipher, but PSA AEAD directly calls the underlying AEAD modules (GCM, CCM, ChachaPoly).
    193 
    194 ### Difficulties
    195 
    196 #### Why PSA is not always possible
    197 
    198 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.
    199 
    200 * `MBEDTLS_PSA_CRYPTO_CLIENT` is disabled.
    201 * There is a PSA driver which has not been initialized (this happens in `psa_crypto_init()`).
    202 * 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`).
    203 * 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`.
    204 * `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled, and the client has not yet activated the connection to the server (this happens in `psa_crypto_init()`).
    205 * `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.
    206 
    207 #### Indirect knowledge
    208 
    209 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).
    210 
    211 Generally speaking, modules in the mixed domain:
    212 
    213 * must call PSA if called by a module in the PSA domain;
    214 * 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.
    215 
    216 #### Non-support guarantees: requirements
    217 
    218 Generally speaking, just because some feature is not enabled in `mbedtls_config.h` or `crypto_config.h` doesn't guarantee that it won't be enabled in the build. We can enable additional features through `build_info.h` and other header files included there (`*adjust*.h`).
    219 
    220 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.
    221 
    222 ### Technical requirements
    223 
    224 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:
    225 
    226 * How the mechanism is encoded (e.g. `mbedtls_md_type_t` vs `const *mbedtls_md_info_t` vs `psa_algorithm_t` for hashes).
    227 * How to decide whether a specific algorithm or key type is supported (eventually based on `MBEDTLS_xxx_C` vs `PSA_WANT_xxx`).
    228 * How to obtain metadata about algorithms (e.g. hash/MAC/tag size, key size).
    229 * How to perform the operation (context type, which functions to call).
    230 
    231 We need a way to decide this based on the available information:
    232 
    233 * Who's the ultimate caller — see [indirect knowledge](#indirect-knowledge) — which is not actually available.
    234 * Some parameter indicating which algorithm to use.
    235 * The available cryptographic implementations, based on preprocessor symbols (`MBEDTLS_xxx_C`, `PSA_WANT_xxx`, `MBEDTLS_PSA_ACCEL_xxx`, etc.).
    236 * Possibly additional runtime state (for example, we might check whether `psa_crypto_init` has been called).
    237 
    238 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.
    239 
    240 ### Working through an example: RSA-PSS
    241 
    242 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).
    243 
    244 RSA is in the [mixed domain](#classification-of-callers). So:
    245 
    246 * When called from `psa_sign_hash` and other PSA functions, it must call the PSA hash accelerator if there is one.
    247 * 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).
    248 
    249 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 *`.)
    250 
    251 #### Double encoding solution
    252 
    253 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.
    254 
    255 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.
    256 
    257 #### Availability of hashes in RSA-PSS
    258 
    259 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?
    260 
    261 * 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).
    262 * 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.
    263 * 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.
    264 
    265 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.
    266 
    267 #### More in-depth discussion of compile-time availability determination
    268 
    269 The following combinations of compile-time support are possible:
    270 
    271 * `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.
    272 * 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.
    273 * 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.
    274 * 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.
    275 
    276 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.
    277 
    278 ### Designing an interface for hashes
    279 
    280 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.
    281 
    282 #### Availability of hashes
    283 
    284 Generalizing the analysis in [“Availability of hashes in RSA-PSS”](#availability-of-hashes-in-RSA-PSS):
    285 
    286 A hash is available through the mixed-domain interface iff either of the following conditions is true:
    287 
    288 * A legacy hash interface is available and the hash algorithm is implemented in software.
    289 * PSA crypto is enabled and the hash algorithm is implemented via PSA.
    290 
    291 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.
    292 
    293 #### Implications between legacy availability and PSA availability
    294 
    295 * When `MBEDTLS_PSA_CRYPTO_CONFIG` is disabled, all legacy mechanisms are automatically enabled through PSA. Users can manually enable PSA mechanisms that are available through accelerators but not through legacy, but this is not officially supported (users are not supposed to manually define PSA configuration symbols when `MBEDTLS_PSA_CRYPTO_CONFIG` is disabled).
    296 * When `MBEDTLS_PSA_CRYPTO_CONFIG` is enabled, 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.
    297 
    298 It is strongly desirable to allow mechanisms available through PSA but not legacy: this allows saving code size when an accelerator is present.
    299 
    300 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.
    301 
    302 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:
    303 
    304 * 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.
    305 * Mixed-domain code can assume that PSA buffer calculations work correctly for all algorithms that it supports.
    306 
    307 #### Shape of the mixed-domain hash interface
    308 
    309 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.)
    310 
    311 Requirements: given a hash algorithm,
    312 
    313 * Obtain some metadata about it (size, block size).
    314 * Calculate the hash.
    315 * Set up a multipart operation to calculate the hash. The operation must support update, finish, reset, abort, clone.
    316 
    317 The existing interface in `md.h` is close to what we want, but not perfect. What's wrong with it?
    318 
    319 * It has an extra step of converting from `mbedtls_md_type_t` to `const mbedtls_md_info_t *`.
    320 * It includes extra fluff such as names and HMAC. This costs code size.
    321 * 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.
    322 
    323 These problems are easily solvable.
    324 
    325 * `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.
    326 * We can make names and HMAC optional. The mixed-domain hash interface won't be the full `MBEDTLS_MD_C` but a subset.
    327 * We can optimize `md.c` without making API changes to `md.h`.
    328 
    329 ### Scope reductions and priorities for 3.x
    330 
    331 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.
    332 
    333 #### Don't support PK, X.509 and TLS without `MBEDTLS_USE_PSA_CRYPTO`
    334 
    335 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.
    336 
    337 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).
    338 
    339 This will go away naturally in 4.0 when this macros is not longer an option (because it's always on).
    340 
    341 #### Support for `MBEDTLS_PSA_CRYPTO_CLIENT` without `MBEDTLS_PSA_CRYPTO_C`
    342 
    343 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`.
    344 
    345 #### For cipher: prioritize constrained devices and modern TLS
    346 
    347 The primary target is a configuration like TF-M's medium profile, plus TLS with only AEAD ciphersuites.
    348 
    349 This excludes things like:
    350 - Support for encrypted PEM, PKCS5 and PKCS12 encryption, and PKCS8 encrypted keys in PK parse. (Not widely used on highly constrained devices.)
    351 - Support for NIST-KW. (Same justification.)
    352 - Support for CMAC. (Same justification, plus can be directly accelerated.)
    353 - Support for CBC ciphersuites in TLS. (They've been recommended against for a while now.)
    354 
    355 ### Dual-dispatch for block cipher primitives
    356 
    357 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).
    358 
    359 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.
    360 - 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.
    361 - 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.
    362 
    363 So, it makes sense to use different designs for CTR-DRBG on one hand, and GCM/CCM on the other hand:
    364 - CTR-DRBG can just check if `AES_C` is present and "fall back" to PSA if not.
    365 - GCM and CCM need an common abstraction layer that allows:
    366   - Using AES, Aria or Camellia in a uniform way.
    367   - Dispatching to built-in or driver.
    368 
    369 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.
    370 
    371 Reasons for making this layer's API a subset of the existing Cipher API:
    372 - No need to design, implement and test a new module. (Will need to test the new subset though, as well as the extended behaviour.)
    373 - No code change in GCM and CCM - only need to update dependencies.
    374 - 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.)
    375 - 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.
    376 
    377 Possible costs of re-using (a subset of) the existing Cipher API instead of defining a new one:
    378 - 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).
    379 - We carry over questionable implementation decisions, like dynamic allocation of context.
    380 
    381 Those costs could be avoided by refactoring (parts of) Cipher, but that would probably mean either:
    382 - significant differences in how the `cipher.h` API is implemented between builds with the full Cipher or only a subset;
    383 - or more work to apply the simplifications to all of Cipher.
    384 
    385 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).
    386 
    387 ## Specification
    388 
    389 ### MD light
    390 
    391 #### Definition of MD light
    392 
    393 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`.
    394 
    395 The following things enable MD light automatically in `build_info.h`:
    396 
    397 * A [mixed-domain](#classification-of-callers) module that needs to calculate hashes is enabled.
    398 * `MBEDTLS_MD_C` is enabled.
    399 
    400 MD light includes the following types:
    401 
    402 * `mbedtls_md_type_t`
    403 * `mbedtls_md_info_t`
    404 * `mbedtls_md_context_t`
    405 
    406 MD light includes the following functions:
    407 
    408 * `mbedtls_md_info_from_type`
    409 * `mbedtls_md_init`
    410 * `mbedtls_md_free`
    411 * `mbedtls_md_setup` — but `hmac` must be 0 if `MBEDTLS_MD_C` is disabled.
    412 * `mbedtls_md_clone`
    413 * `mbedtls_md_get_size`
    414 * `mbedtls_md_get_type`
    415 * `mbedtls_md_starts`
    416 * `mbedtls_md_update`
    417 * `mbedtls_md_finish`
    418 * `mbedtls_md`
    419 
    420 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`).
    421 
    422 #### MD algorithm support macros
    423 
    424 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:
    425 
    426 * the corresponding `MBEDTLS_xxx_C` is defined.
    427 * `MBEDTLS_PSA_CRYPTO_C` is enabled and the corresponding `PSA_WANT_ALG_xxx` and `MBEDTLS_PSA_ACCEL_ALG_xxx` are enabled. This enables driver acceleration support.
    428 * `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled the corresponding `PSA_WANT_ALG_xxx` is enabled. Then the Mbed TLS library must be linked against the PSA Crypto provider one which will eventually handle all PSA calls.
    429 
    430 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:
    431 
    432 ```
    433 #if defined(MBEDTLS_MD_LIGHT)
    434 #if defined(MBEDTLS_SHA256_C) || \
    435     (defined(MBEDTLS_PSA_CRYPTO_C) && PSA_WANT_ALG_SHA_256)
    436 #define MBEDTLS_MD_CAN_SHA256
    437 #endif
    438 #endif
    439 ```
    440 
    441 Note: in the future, we may want to replace `defined(MBEDTLS_PSA_CRYPTO_C)`
    442 with `defined(MBEDTLS_PSA_CRYTO_C) || defined(MBEDTLS_PSA_CRYPTO_CLIENT)` but
    443 for now this is out of scope.
    444 
    445 #### MD light internal support macros
    446 
    447 * If at least one hash has a PSA driver or support in PSA Crypto provider, define `MBEDTLS_MD_SOME_PSA`.
    448 * If at least one hash has a legacy implementation, defined `MBEDTLS_MD_SOME_LEGACY`.
    449 
    450 #### Support for PSA in the MD context
    451 
    452 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).
    453 
    454 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).
    455 
    456 ```
    457 enum {
    458     MBEDTLS_MD_ENGINE_LEGACY,
    459     MBEDTLS_MD_ENGINE_PSA,
    460 } mbedtls_md_engine_t; // private type
    461 
    462 typedef struct mbedtls_md_context_t {
    463     mbedtls_md_type_t type;
    464 #if defined(MBEDTLS_MD_SOME_PSA)
    465     mbedtls_md_engine_t engine;
    466 #endif
    467     void *md_ctx; // mbedtls_xxx_context or psa_hash_operation
    468 #if defined(MBEDTLS_MD_C)
    469     void *hmac_ctx;
    470 #endif
    471 } mbedtls_md_context_t;
    472 ```
    473 
    474 All fields are private.
    475 
    476 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.
    477 
    478 #### Inclusion of MD info structures
    479 
    480 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.
    481 
    482 The same criterion applies in `mbedtls_md_info_from_type`.
    483 
    484 #### Conversion to PSA encoding
    485 
    486 The implementation needs to convert from a legacy type encoding to a PSA encoding.
    487 
    488 ```
    489 static inline psa_algorithm_t psa_alg_of_md_info(
    490     const mbedtls_md_info_t *md_info );
    491 ```
    492 
    493 #### Determination of PSA support at runtime
    494 
    495 Mbed TLS defines internal symbols `MBEDTLS_MD_xxx_VIA_PSA` which are used to check if the `xxx` hash algorithm is supported in PSA. They are enabled when:
    496 
    497 * `MBEDTLS_PSA_CRYPTO_C && MBEDTLS_PSA_ACCEL_ALG_xxx`, i.e. when the PSA Crypto core is built with Mbed TLS and the `xxx` is accelerated through a driver.
    498 * `MBEDTLS_PSA_CRYPTO_CLIENT && PSA_WANT_ALG_xxx`, i.e. there is a PSA Crypto provider/server which supports `xxx` hash algorithm.
    499 
    500 MD internally uses the following private function to determine if PSA can be used at runtime or not:
    501 
    502 ```
    503 static int md_can_use_psa(const mbedtls_md_info_t *info)
    504 ```
    505 
    506 Internally this function does the following:
    507 
    508 * First of all it converts the `mbedtls_md_info_t` to `psa_algorithm_t`. The result of this conversion is based on the `MBEDTLS_MD_xxx_VIA_PSA` symbols: if an algorithm does not have the corresponding `MBEDTLS_MD_xxx_VIA_PSA` enabled, then `md_can_use_psa` will return false.
    509 
    510 * `int psa_can_do_hash(psa_algorithm_t hash_alg)` is then used to further checking if the PSA Crypto core has been initialized or not. If so then `md_can_use_psa` will finally succeed, otherwise it will fail.
    511 
    512 To be noted that in client/server builds (i.e. `MBEDTLS_PSA_CRYPTO_CLIENT && !MBEDTLS_PSA_CRYPTO_C`) the implementer of the client interface is expected to provide psa_can_do_hash().
    513 
    514 #### Support for PSA dispatch in hash operations
    515 
    516 Each function that performs some hash operation or context management needs to know whether to dispatch via PSA or legacy.
    517 
    518 If given an established context, use its `engine` field.
    519 
    520 If given an algorithm as an `mbedtls_md_type_t type` (possibly being the `type` field of a `const mbedtls_md_info_t *`):
    521 
    522 * If there is a PSA accelerator/provider for this hash and `md_can_use_psa` succeeds, 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.)
    523 * Otherwise dispatch to the legacy module based on the type as currently done. (Skip this is `MBEDTLS_MD_SOME_LEGACY` is not defined.)
    524 * If no dispatch is possible, return `MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE`.
    525 
    526 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.
    527 
    528 #### Error code conversion
    529 
    530 After calling a PSA function, MD light calls `mbedtls_md_error_from_psa` to convert its status code.
    531 
    532 ### Support all legacy algorithms in PSA
    533 
    534 As discussed in [“Implications between legacy availability and PSA availability”](#implications-between-legacy-availability-and-psa-availability), we require the following property:
    535 
    536 > If an algorithm has a legacy implementation, it is also available through PSA.
    537 
    538 When `MBEDTLS_PSA_CRYPTO_CONFIG` is disabled, this is already the case. When is enabled, `include/config_adjust_psa_superset_legacy.h` will ensure that PSA configuration is always a superset of what's enabled in legacy.
    539 
    540 ### MD light optimizations
    541 
    542 This section is not necessary to implement MD light, but will cut down its code size.
    543 
    544 #### Split names out of MD light
    545 
    546 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`.
    547 
    548 #### Remove metadata from the info structure
    549 
    550 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.
    551 
    552 #### Optimize type conversions
    553 
    554 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.
    555 
    556 With this optimization,
    557 ```
    558 static inline psa_algorithm_t psa_alg_of_md_info(
    559     const mbedtls_md_info_t *md_info )
    560 {
    561     if( md_info == NULL )
    562         return( PSA_ALG_NONE );
    563     return( PSA_ALG_CATEGORY_HASH | md_info->type );
    564 }
    565 ```
    566 
    567 Work in progress on this conversion is at https://github.com/gilles-peskine-arm/mbedtls/tree/hash-unify-ids-wip-1
    568 
    569 #### Unify HMAC with PSA
    570 
    571 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).
    572 
    573 ### Internal "block cipher" abstraction (previously known as "Cipher light")
    574 
    575 #### Definition
    576 
    577 The new module is automatically enabled in `config_adjust_legacy_crypto.h` by modules that need
    578 it (namely: CCM, GCM) only when `CIPHER_C` is not available, or the new module
    579 is needed for PSA dispatch (see next section). Note: CCM and GCM currently
    580 depend on the full `CIPHER_C` (enforced by `check_config.h`); this hard
    581 dependency would be replaced by the above auto-enablement.
    582 
    583 The following API functions are offered:
    584 ```
    585 void mbedtls_block_cipher_init(mbedtls_block_cipher_context_t *ctx);
    586 void mbedtls_block_cipher_free(mbedtls_block_cipher_context_t *ctx);
    587 int mbedtls_block_cipher_setup(mbedtls_block_cipher_context_t *ctx,
    588                                mbedtls_cipher_id_t cipher_id);
    589 int mbedtls_block_cipher_setkey(mbedtls_block_cipher_context_t *ctx,
    590                                 const unsigned char *key,
    591                                 unsigned key_bitlen);
    592 int mbedtls_block_cipher_encrypt(mbedtls_block_cipher_context_t *ctx,
    593                                  const unsigned char input[16],
    594                                  unsigned char output[16]);
    595 ```
    596 
    597 The only supported ciphers are AES, ARIA and Camellia. They are identified by
    598 an `mbedtls_cipher_id_t` in the `setup()` function, because that's how they're
    599 identifed by callers (GCM/CCM).
    600 
    601 #### Block cipher dual dispatch
    602 
    603 Support for dual dispatch in the new internal module `block_cipher` is extremely similar to that in MD light.
    604 
    605 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.
    606 
    607 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.
    608 
    609 Support is determined at runtime using the new internal function
    610 ```
    611 int psa_can_do_cipher(psa_key_type_t key_type, psa_algorithm_t cipher_alg);
    612 ```
    613 
    614 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.
    615 
    616 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.
    617 
    618 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.
    619 
    620 After calling a PSA function, `block_cipher` functions call `mbedtls_cipher_error_from_psa` to convert its status code.