Skip to content

Evolution of pk.h in 4.0 #8452

@mpg

Description

@mpg

This issue is meant as a place to discuss what we want to do with PK in 4.0.

There are two main options:

  1. Keep it as part of the public API until 5.0, but aim to make it a thin wrapper around PSA Crypto (in 4.0 or 4.x).
  2. Remove it from the public API in 4.0, and eventually remove it entirely (in 4.0 or 4.x).

Scope of PK

  • Crypto operations similar to two PSA Crypto families: asymmetric signature (RSA, ECDSA) and asymmetric encryption (RSA).
    • Note: that's not all asymmetric crypto: key agreement (ECDH) and PAKE (EC J-PAKE) are not covered.
  • Writing and parsing of public and private keys (ECC, RSA) in a variety of formats currently not supported by PSA.
  • The pk_context structure serves as a container for public/private keys, which tend to be longer-lived and more often user-provided.

Note: for low-level modules related to asymmetric crypto (rsa.h, ecdsa.h covered by PK, but also ecdh.h and ecjpake.h, and underneath them ecp.h and bignum.h) I think the plan is to remove them from the public API, regardless of what we do with PK.

The problem of X.509 vs the PSA key store

With option 1 and pk_context structures being thin wrappers around psa_key_id_t, or with option 2 and blindly replacing all uses of pk_context with psa_key_id_t and no other code change, we'd have the following problem:

  • It is not unusual with X.509 to have a more than a hundred trust roots (currently 147 on my Ubuntu laptop).
  • When parsing these (for example with mbedtls_x509_crt_parse_path()) a psa_key_id_t would be created to hold each certificate's public key, resulting in 100+ PSA key slots being used simultaneously.
  • But currently the default size of the PSA key store (MBEDTLS_PSA_KEY_SLOT_COUNT) is 32.
  • Hence this use case would break in the default config.

There are a number of ways to avoid that problem; we can act at any step in the chain leading to that potential issue:

  • The easiest and most obvious would be to up the default value of MBEDTLS_PSA_KEY_SLOT_COUNT to something like 256.
  • We could also change X.509 so that it doesn't load the key into a pk_context/psa_key_id_t when parsing a certificate, but only when actually doing an operation with the key. This might be desirable for other reasons and have even been done in the baremetal branch as part of "on-demand parsing" which significantly improved RAM usage. But it requires designing new APIs for users to access the public key embedded in a certificate.
  • If we keep PK but make it a thin wrapper around PSA, we could go with a hybrid approach where it stores private keys into PSA key slots, but public keys serialized in a way that psa_import() accepts - and then only load them into a temporary PSA key slot when used. (Note: that's the approach currently used by MBEDTLS_PK_USE_PSA_EC_DATA.)

Rationale for option 1 (keep)

This gives users more time to move to PSA. People who were using low-level modules (including those not covered by PK) need to migrate immediately, but those who were only using the generic PK API can migrate at a convenient time between now and 5.0.

Work needed for option 1 (keep)

In 4.0:

  • We may still want to remove some parts:
  • We might want to remove mbedtls_pk_info_t from the API in order to make it slicker but that would require users to change their code, so it runs against the stated goal. (Alternatively, we can keep the structure but later make it trivial as it has no public field.)
  • We need some investigation (probably including a prototype) to make sure the current API can be implemented efficiently as a thin wrapper around PSA. Note: for crypto operations, this is already mostly the case with USE_PSA_CRYPTO; when using mbedtls_pk_setup_opaque() (or when MBEDTLS_PK_USE_PSA_EC_DATA is defined) that's also the case for (ECC) key storage.

In 4.0 or 4.x:

  • Actually make it a thin wrapper around PSA crypto.
  • Migrate all internal users (library and tests) to use PSA Crypto directly (note: common with option 2).

Rationale for option 2 (remove)

This leaves us with only one PK API to maintain, document and test. For new users, this also gives more clarity.

Note the current pk.h API has a few shortcomings, the most prominent being it doesn't manage key permissions like PSA does. So, pushing users to the PSA API is also pushing them to a better API.

Work needed for option 2 (remove)

In 4.0:

  • Design and implement a PSA replacement for PK parse. Note: that's probably an EPIC on its own, but also something we want to do anyway.
  • Update all TLS and X.509 APIs that handle a pk_context:
    • X.509: mbedtls_x509write_crt_set_subject_key(), mbedtls_x509write_crt_set_issuer_key() and mbedtls_x509write_csr_set_key() + public fields in mbedtls_x509_crt and mbedtls_x509_csr structure, and some private fields too.
    • TLS: mbedtls_ssl_conf_own_cert() and mbedtls_ssl_set_hs_own_cert().
  • Move pk.h to an internal location and adapt all files that #include it.
  • Change or remove all example programs that used it.
  • Provide a migration guide.

In 4.0 or 4.x:

  • Refactor psa_crypto_cipher.c so that it no longer
  • Migrate all remaining internal users (library and tests) to use PSA Crypto directly (note: common with option 2).
  • Then remove Cipher from the code base entirely.

Other options

  • We could go for a mix: keep some parts but remove others. For example, we could keep PK parse or pk_context but remove the part about doing operations?
  • Other?

Metadata

Metadata

Labels

api-breakThis issue/PR breaks the API and must wait for a new major versioncomponent-cryptoCrypto primitives and low-level interfacesneeds-design-approval

Type

No type

Projects

Status

1.0 MVP DI

Status

Done

Status

Mbed TLS 4.0 candidates

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions