Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
160 KiB
Transitioning to the PSA API
I have code written for
mbedtls_
cryptography APIs. How do I migrate topsa_
APIs?
Introduction
Mbed TLS is gradually moving from legacy mbedtls_xxx
APIs to newer psa_xxx
APIs for cryptography. Note that this only concerns cryptography APIs, not X.509 or SSL/TLS APIs.
This guide is intended to help migrate existing applications that use Mbed TLS for cryptography. It aims to cover common use cases, but cannot cover all possible scenarios.
Suggested reading
This document is long, but you probably don't need to read all of it. You should start with the following sections:
Then use the summary of API modules, the table of contents or a text search to locate the sections that interest you, based on what legacy interfaces your code is currently using.
Where can I find documentation?
Tutorial: See the getting started guide.
Reference: The PSA Crypto API specification is available online. Mbed TLS implements a large subset of the specification which is documented in the psa/crypto*.h
headers.
Additional resources
- Mbed TLS open issues
- PSA API open issues (not just cryptography APIs)
- Mbed TLS mailing list
Why change the API?
- Mbed TLS APIs are traditionally very transparent: the caller can access internal fields of operations. This is less true in the 3.x major version than before, but still the case to some extent. This offers applications some flexibility, but it removes flexibility from the implementation. For example, it is hard to support hardware acceleration, because the API constrains how the data must be represented. PSA APIs were designed to be more opaque, giving more freedom to the implementation.
- Mbed TLS legacy APIs require key material to be present in the application memory. The PSA Crypto API natively supports operations on keys stored in an external location (secure enclave, secure element, HSM, etc.).
- PSA APIs have consistent conventions which many legacy APIs in Mbed TLS do not follow. For example, many legacy cryptography functions require the caller to know how large an output buffer needs to be based on the selected algorithm, whereas in the PSA API, all buffer arguments have a well-defined size and those sizes are checked.
- Mbed TLS legacy APIs require passing around a random generator argument where needed. This has historically been problematic with functions that were created without an RNG argument but later needed one as part of a security countermeasure. The PSA crypto subsystem maintains a global random generator, resolving this problem.
Migration timeline
- Mbed TLS 2.15.0 (Nov 2018): first release with a draft implementation of the PSA API.
- Mbed TLS 2.18.0 (Jun 2019): The PSA API is available in the default build.
- Mbed TLS 3.1.0 (Dec 2021): TLS 1.3 support is the first major feature that requires the PSA API.
- Mbed TLS 4.0.0 (2024?): X.509 and TLS require the PSA API. Removal of some legacy crypto APIs.
- Mbed TLS 5.0.0 (??): Removal of the remaining non-PSA crypto APIs.
General considerations
Configuration of the PSA subsystem
To make the PSA API available, make sure that the configuration option MBEDTLS_PSA_CRYPTO_C
is enabled. (It is enabled in the default configuration.)
You should probably enable MBEDTLS_USE_PSA_CRYPTO
as well (it is disabled by default). This option causes the PK, X.509 and TLS modules to use PSA crypto under the hood. Some functions that facilitate the transition (for example, to convert between metadata encodings or between key representations) are only available when MBEDTLS_USE_PSA_CRYPTO
is enabled.
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”.
Header files
Applications only need to include a single header file:
#include <psa/crypto.h>
General application layout
Before any cryptographic operation, call psa_crypto_init
and check that it succeeds. (A failure indicates an abnormal system state from which most applications cannot recover.)
If you wish to free all resources associated with PSA cryptography, call mbedtls_psa_crypto_free
.
The PSA subsystem has an internal random generator. As a consequence, you do not need to instantiate one manually (no need to create an mbedtls_entropy_context
and an mbedtls_xxx_drbg_context
).
Error codes
Mbed TLS functions return a status of type int
: 0 for success (or occasionally a positive value which is the output length), or a negative value MBEDTLS_ERR_xxx
indicating an error.
PSA functions return a status of type psa_status_t
: PSA_SUCCESS == 0
for success, or a negative value PSA_ERROR_xxx
indicating an error.
Memory management
Apart from keys, as described in “Key management” below, APIs that need to preserve state between function calls store this state in a structure allocated by the calling code. For example, multipart operations store state in a multipart operation object.
All PSA operation objects must be zero-initialized (or equivalently, initialized with the provided PSA_XXX_INIT
macro or psa_xxx_init()
function) before calling any API function.
Functions that output data require an output buffer of sufficient size. For all PSA crypto API functions that have an output buffer, there is a corresponding macro, generally called PSA_XXX_OUTPUT_SIZE
, that calculates a sufficient size for the output buffer, given the relevant parameters. In some cases, there may be macros with less precision which can be resolved at compile time. For example, for the size of a buffer containing a hash, you can use PSA_HASH_LENGTH(hash_alg)
where hash_alg
is a specific hash algorithm, or PSA_HASH_MAX_SIZE
for a buffer that is long enough for any supported hash. See the relevant sections of this document and of the reference documentation for more details.
Key management
One of the major differences between the legacy API and the PSA API is that in the PSA API, access to keys is indirect. Operations that require a key take a parameter of type psa_key_id_t
, which is an identifier for the key. This allows the API to be used with keys that are not directly accessible to the application, for example because they are stored in a secure environment that does not allow the key material to be exported.
To use a key:
- First create a key object with a key creation function. The two most common ones are
psa_import_key
if you have the key material available andpsa_generate_key
to create a random key. The key creation function has the key identifier as an output parameter. - Use the key as desired, passing the key identifier obtained during the key creation.
- Finally destroy the key object with
psa_destroy_key
.
See “Cipher key management”, “MAC key management”, “Key lifecycle for asymmetric cryptography”, “Creating keys for asymmetric cryptography” and “Diffie-Hellman key pair management” for more details about key management in specific workflows, including information about choosing the key's attributes.
If you need access to the key material, call psa_export_key
. If you need the public key corresponding to a key pair object, call psa_export_public_key
.
Note that a key consumes a key store entry, which is distinct from heap memory, until it is destroyed or the application exits. (This is not true for persistent keys, which instead consume disk space. Since persistent keys have no analog in the legacy API, we will not discuss them further in this document.)
Summary of API modules
Header | Function prefix | PSA equivalent |
---|---|---|
aes.h |
mbedtls_aes_ |
Symmetric encryption |
aria.h |
mbedtls_aria_ |
Symmetric encryption |
asn1.h |
mbedtls_asn1_ |
No change (PK support interface) |
asn1write.h |
mbedtls_asn1_write_ |
No change (PK support interface) |
base64.h |
mbedtls_base64_ |
No change (PK support interface) |
bignum.h |
mbedtls_mpi_ |
None (no low-level arithmetic) |
build_info.h |
MBEDTLS_ |
No change (not a crypto API) |
camellia.h |
mbedtls_camellia_ |
Symmetric encryption |
ccm.h |
mbedtls_ccm_ |
Symmetric encryption, Authenticated cipher operations |
chacha20.h |
mbedtls_chacha20_ |
Symmetric encryption |
chachapoly.h |
mbedtls_chachapoly_ |
Symmetric encryption, Authenticated cipher operations |
check_config.h |
N/A | No public APIs (internal support header) |
cipher.h |
mbedtls_cipher_ |
Symmetric encryption |
cmac.h |
mbedtls_cipher_cmac_ |
Hashes and MAC, MAC calculation |
compat-2.x.h |
various | None (transitional APIs) |
config_psa.h |
N/A | No public APIs (internal support header) |
constant_time.h |
mbedtls_ct_ |
Constant-time functions |
ctr_drbg.h |
mbedtls_ctr_drbg_ |
Random generation interface, Deterministic pseudorandom generation |
debug.h |
mbedtls_debug_ |
No change (not a crypto API) |
des.h |
mbedtls_des_ |
Symmetric encryption |
dhm.h |
mbedtls_dhm_ |
Asymmetric cryptography |
ecdh.h |
mbedtls_ecdh_ |
Asymmetric cryptography |
ecdsa.h |
mbedtls_ecdsa_ |
Asymmetric cryptography |
ecjpake.h |
mbedtls_ecjpake_ |
EC-JPAKE |
ecp.h |
mbedtls_ecp_ |
Asymmetric cryptography |
entropy.h |
mbedtls_entropy_ |
Random generation interface, Entropy sources |
error.h |
mbedtls_*err* |
Error messages |
gcm.h |
mbedtls_gcm_ |
Symmetric encryption, Authenticated cipher operations |
hkdf.h |
mbedtls_hkdf_ |
HKDF |
hmac_drbg.h |
mbedtls_hmac_drbg_ |
Random generation interface, Deterministic pseudorandom generation |
lms.h |
mbedtls_lms_ |
No change (LMS signatures) |
mbedtls_config.h |
MBEDTLS_ |
Compile-time configuration |
md.h |
mbedtls_md_ |
Hashes and MAC |
md5.h |
mbedtls_md5_ |
Hashes and MAC |
memory_buffer_alloc.h |
mbedtls_memory_buffer_alloc_ |
No change (not a crypto API) |
net_sockets.h |
mbedtls_net_ |
No change (not a crypto API) |
nist_kw.h |
mbedtls_nist_kw_ |
Migration path not yet defined |
oid.h |
mbedtls_oid_ |
No change (PK support interface) |
pem.h |
mbedtls_pem_ |
No change (PK support interface) |
pk.h |
mbedtls_pk_ |
Asymmetric cryptography |
pkcs5.h |
mbedtls_pkcs5_ |
PKCS#5 module |
pkcs7.h |
mbedtls_pkcs7_ |
No change (not a crypto API) |
pkcs12.h |
mbedtls_pkcs12_ |
PKCS#12 module |
platform.h |
mbedtls_platform_ |
No change (not a crypto API) |
platform_time.h |
mbedtls_*time* |
No change (not a crypto API) |
platform_util.h |
mbedtls_platform_ |
No change (not a crypto API) |
poly1305.h |
mbedtls_poly1305_ |
None (but there is Chacha20-Poly1305 AEAD) |
private_access.h |
N/A | No public APIs (internal support header) |
psa_util.h |
N/A | No public APIs (internal support header) |
ripemd160.h |
mbedtls_ripemd160_ |
Hashes and MAC |
rsa.h |
mbedtls_rsa_ |
Asymmetric cryptography |
sha1.h |
mbedtls_sha1_ |
Hashes and MAC |
sha3.h |
mbedtls_sha3_ |
Hashes and MAC |
sha256.h |
mbedtls_sha256_ |
Hashes and MAC |
sha512.h |
mbedtls_sha512_ |
Hashes and MAC |
ssl.h |
mbedtls_ssl_ |
No change (not a crypto API) |
ssl_cache.h |
mbedtls_ssl_cache_ |
No change (not a crypto API) |
ssl_ciphersuites.h |
mbedtls_ssl_ciphersuite_ |
No change (not a crypto API) |
ssl_cookie.h |
mbedtls_ssl_cookie_ |
No change (not a crypto API) |
ssl_ticket.h |
mbedtls_ssl_ticket_ |
No change (not a crypto API) |
threading.h |
mbedtls_threading_ |
No change (not a crypto API) |
timing.h |
mbedtls_timing_ |
No change (not a crypto API) |
version.h |
mbedtls_version_ |
No change (not a crypto API) |
x509.h |
mbedtls_x509 |
No change (not a crypto API) |
x509_crl.h |
mbedtls_x509 |
No change (not a crypto API) |
x509_crt.h |
mbedtls_x509 |
No change (not a crypto API) |
x509_csr.h |
mbedtls_x509 |
No change (not a crypto API) |
Compile-time configuration
Cryptographic mechanism availability
This section only applies if MBEDTLS_PSA_CRYPTO_CONFIG
is enabled. This option is disabled in the default configuration.
When the configuration option MBEDTLS_PSA_CRYPTO_CONFIG
is enabled, the cryptographic mechanisms available through the PSA API are determined by the contents of the header file "psa/crypto_config.h"
. You can override the file location with the macro MBEDTLS_PSA_CRYPTO_CONFIG_FILE
, and you can set MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE
to the path of an additional file (similar to MBEDTLS_CONFIG_FILE
and MBEDTLS_USER_CONFIG_FILE
for legacy configuration symbols).
The availability of cryptographic mechanisms in the PSA API is based on a systematic pattern:
-
To make
PSA_ALG_aaa
available, enablePSA_WANT_ALG_aaa
. For parametrized algorithms, there is aPSA_WANT_
symbol both for the main macro and for each argument. For example, to makePSA_ALG_HMAC(PSA_ALG_SHA_256)
available, enable bothPSA_WANT_ALG_HMAC
andPSA_WANT_ALG_SHA_256
. -
To make
PSA_KEY_TYPE_ttt
available, enablePSA_WANT_KEY_TYPE_ttt
.As an exception, starting in Mbed TLS 3.5.0, for key pair types, the feature selection is more fine-grained, with an additional suffix:
PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_BASIC
enables basic support for the key type, and in particular support for operations with a key of that type for enabled algorithms. This is automatically enabled if any of the otherPSA_WANT_KEY_TYPE_xxx_KEY_PAIR_yyy
options are enabled.PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_IMPORT
enables support forpsa_import_key
to import a key of that type.PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_GENERATE
enables support forpsa_generate_key
to randomly generate a key of that type.PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_DERIVE
enables support forpsa_key_derivation_output_key
to deterministically derive a key of that type.PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_EXPORT
enables support forpsa_export_key
to export a key of that type.
Enabling any support for a key pair type automatically enables support for the corresponding public key type, as well as support for
psa_export_public_key
on the private key. -
To make
PSA_ECC_FAMILY_fff
available for size sss, enablePSA_WANT_ECC_fff_sss
.
Note that all PSA_WANT_xxx
symbols must be set to a non-zero value. In particular, setting PSA_WANT_xxx
to an empty value may not be handled consistently.
For example, the following configuration enables hashing with SHA-256, AEAD with AES-GCM, signature with deterministic ECDSA using SHA-256 on the curve secp256r1 using a randomly generated key as well as the corresponding verification, and ECDH key exchange on secp256r1 and Curve25519.
#define PSA_WANT_ALG_SHA_256 1
#define PSA_WANT_KEY_TYPE_AES 1
#define PSA_WANT_ALG_GCM 1
#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1
// ^^ In Mbed TLS <= 3.4, enable PSA_WANT_KEY_TYPE_ECC_KEY_PAIR instead
// ^^ implicitly enables PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC, PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY
#define PSA_WANT_ECC_SECP_R1_256 1 // secp256r1 (suitable for ECDSA and ECDH)
#define PSA_WANT_ECC_MONTGOMERY_255 1 // Curve25519 (suitable for ECDH)
#define PSA_WANT_ALG_DETERMINISTIC_ECDSA 1
#define PSA_WANT_ALG_ECDH
If a mechanism is not enabled by PSA_WANT_xxx
, Mbed TLS will normally not include it. This allows builds that use few features to have a small code size. However, this is not guaranteed: a mechanism that is not explicitly requested can be enabled because it is a dependency of another configuration option, because it is used internally, or because the granularity is not fine enough to distinguish between it and another mechanism that is requested.
Under the hood, PSA_WANT_xxx
enables the necessary legacy modules. Note that if a mechanism has a PSA accelerator driver, the corresponding legacy module is typically not needed. Thus applications that use a cryptographic mechanism both through the legacy API and through the PSA API need to explicitly enable both the PSA_WANT_xxx
symbols and the MBEDTLS_xxx
symbols.
Optimization options
When PSA Crypto mechanisms are implemented by the built-in code from Mbed TLS, the legacy optimization options (e.g. MBEDTLS_SHA256_SMALLER
, MBEDTLS_ECP_WINDOW_SIZE
, etc.) apply to the PSA implementation as well (they invoke the same code under the hood).
The PSA Crypto API may use accelerator drivers. In this case any options controlling the driver behavior are driver-specific.
Alternative implementations (MBEDTLS_xxx_ALT
options)
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. 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 for more information.
Self-tests
There is currently no PSA equivalent to the self-tests enabled by MBEDTLS_SELF_TEST
.
Miscellaneous support modules
Error messages
At the time of writing, there is no equivalent to the error messages provided by mbedtls_strerror
. However, you can use the companion program programs/psa/psa_constant_names
to convert various numbers (psa_status_t
, psa_algorithm_t
, psa_key_type_t
, psa_ecc_family_t
, psa_dh_family_t
, psa_key_usage_t
) to a programmer-friendly representation. The conversion doesn't depend on the library configuration or the target platform, so you can use a native build of this program even if you cross-compile your application.
$ programs/psa/psa_constant_names error -138
PSA_ERROR_BUFFER_TOO_SMALL
$ programs/psa/psa_constant_names type 0x7112
PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)
$ programs/psa/psa_constant_names alg 0x06000609
PSA_ALG_ECDSA(PSA_ALG_SHA_256)
The other functions in error.h
are specific to the construction of Mbed TLS error code and are not relevant to the PSA API. PSA error codes are never the combination of multiple codes.
Constant-time functions
The PSA API does not have an equivalent to the timing-side-channel-resistance utility functions in constant_time.h
. Continue using constant_time.h
as needed.
Note that the PSA API does include features that reduce the need for mbedtls_ct_memcmp
:
- To compare a MAC with a reference value, use
psa_mac_verify
rather thanpsa_mac_compute
followed bymbedtls_ct_memcmp
, or usepsa_mac_verify_setup
andpsa_mac_verify_finish
in the multi-part case. See “MAC calculation”. - The AEAD decryption functions take care of verifying the tag. See “Authenticated cipher operations”.
Symmetric encryption
All PSA APIs have algorithm agility, where the functions depend only on the nature of the operation and the choice of a specific algorithm comes from an argument. There is no special API for a particular block cipher (aes.h
, aria.h
, camellia.h
, des.h
), a particular block cipher mode (ccm.h
, gcm.h
) or a particular stream cipher (chacha20.h
, chachapoly.h
). To migrate code using those low-level modules, please follow the recommendations in the following sections, using the same principles as the corresponding cipher.h
API.
Cipher mechanism selection
Instead of mbedtls_cipher_id_t
(MBEDTLS_CIPHER_ID_xxx
constants), mbedtls_cipher_type_t
(MBEDTLS_CIPHER_base_size_mode
constants), mbedtls_cipher_mode_t
(MBEDTLS_CIPHER_MODE_xxx
constants) and mbedtls_cipher_padding_t
(MBEDTLS_CIPHER_PADDING_xxx
constants), use the PSA_KEY_TYPE_xxx
and PSA_ALG_xxx
constants.
For modes that are based on a block cipher, the key type encodes the choice of block cipher:
PSA_KEY_TYPE_AES
,
PSA_KEY_TYPE_ARIA
,
PSA_KEY_TYPE_CAMELLIA
,
PSA_KEY_TYPE_DES
.
The algorithm encodes the mode and if relevant the padding type:
- Unauthenticated cipher modes:
PSA_ALG_CTR
,PSA_ALG_CFB
,PSA_ALG_OFB
,PSA_ALG_XTS
,PSA_ALG_ECB_NO_PADDING
,PSA_ALG_CBC_NO_PADDING
,PSA_ALG_CBC_PKCS7
,PSA_ALG_CCM_STAR_NO_TAG
. - Other padding modes, which are obsolete, are not available in the PSA API. If you need them, handle the padding in your application code and use the
NO_PADDING
algorithm. - AEAD modes:
PSA_ALG_CCM
,PSA_ALG_GCM
. - KW/KWP modes are not available in the PSA API at the time of writing.
For the ChaCha20 unauthenticated cipher, use PSA_KEY_TYPE_CHACHA20
with PSA_ALG_STREAM_CIPHER
.
For the Chacha20+Poly1305 AEAD, use PSA_KEY_TYPE_CHACHA20
with PSA_ALG_CHACHA20_POLY1305
Cipher mechanism availability
For each key type value PSA_KEY_TYPE_xxx
, the symbol PSA_WANT_KEY_TYPE_xxx
is defined with a non-zero value if the library is built with support for that key type. For each algorithm value PSA_ALG_yyy
, the symbol PSA_WANT_ALG_yyy
is defined with a non-zero value if the library is built with support for that algorithm. Note that for a mechanism to be supported, both the key type and the algorithm must be supported.
For example, to test if AES-CBC-PKCS7 is supported, in the legacy API, you could write:
#if defined(MBEDTLS_AES_C) && \
defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_CIPHER_PADDING_PKCS7)
The equivalent in the PSA API is
#if PSA_WANT_KEY_TYPE_AES && PSA_WANT_ALG_CBC_PKCS7
Cipher metadata
Both APIs express key sizes in bits. Note however that in the PSA API, the size of a buffer is always expressed in bytes, even if that buffer contains a key.
The following table lists corresponding PSA macros for maximum-size macros that take all supported algorithms into account.
Legacy macro | PSA macro |
---|---|
MBEDTLS_MAX_IV_LENGTH |
PSA_CIPHER_IV_MAX_SIZE , PSA_AEAD_NONCE_MAX_SIZE |
MBEDTLS_MAX_BLOCK_LENGTH |
PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE |
MBEDTLS_MAX_KEY_LENGTH |
no equivalent |
There is no equivalent to the type mbedtls_cipher_info_t
and the functions mbedtls_cipher_info_from_type
and mbedtls_cipher_info_from_values
in the PSA API because it is unnecessary. All macros and functions operate directly on key type values (psa_key_type_t
, PSA_KEY_TYPE_xxx
constants) and algorithm values (psa_algorithm_t
, PSA_ALG_xxx
constants).
Legacy function | PSA macro |
---|---|
mbedtls_cipher_info_get_iv_size |
PSA_CIPHER_IV_LENGTH , PSA_AEAD_NONCE_LENGTH |
mbedtls_cipher_info_get_block_size |
not available (use specific macros for the IV, nonce or tag length) |
The following features have no PSA equivalent:
mbedtls_cipher_list
: the PSA API does not currently have a discovery mechanism for cryptographic mechanisms, but one may be added in the future.mbedtls_cipher_info_has_variable_key_bitlen
,mbedtls_cipher_info_has_variable_iv_size
: the PSA API does not currently have such mechanism for high-level metadata information.mbedtls_cipher_info_from_string
: there is no equivalent of Mbed TLS's lookup based on a (nonstandard) name.
Cipher key management
The legacy API and the PSA API have a different organization of operations in several respects:
- In the legacy API, each operation object contains the necessary key material. In the PSA API, an operation object contains a reference to a key object. To perform a cryptographic operation, you must create a key object first. However, for a one-shot operation, you do not need an operation object, just a single function call.
- The legacy API uses the same interface for authenticated and non-authenticated ciphers, while the PSA API has separate functions.
- The legacy API uses the same functions for encryption and decryption, while the PSA API has separate functions where applicable.
Here is an overview of the lifecycle of a key object.
- First define the attributes of the key by filling a
psa_key_attributes_t
structure. You need to set the following parameters:- Call
psa_set_key_type
to set the key type to the desiredPSA_KEY_TYPE_xxx
value (see “Cipher mechanism selection”). - Call
psa_set_key_bits
to set the key's size in bits. This is optional withpsa_import_key
, which determines the key size from the length of the key material. - Call
psa_set_key_algorithm
to set the algorithm to the desiredPSA_ALG_xxx
value (see “Cipher mechanism selection”). By design, the same key cannot be used with multiple algorithms. - Call
psa_set_key_usage_flags
to enable at leastPSA_KEY_USAGE_ENCRYPT
orPSA_KEY_USAGE_DECRYPT
, depending on which direction you want to use the key in. To allow both directions, use the flag maskPSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT
. The same policy flags cover authenticated and non-authenticated encryption/decryption.
- Call
- Call one of the key creation functions, passing the attributes defined in the previous step, to get an identifier of type
psa_key_id_t
to the key object.- Use
psa_import_key
to directly import key material. - If the key is randomly generated, use
psa_generate_key
. - If the key is derived from other material (for example from a key exchange), use the key derivation interface and create the key with
psa_key_derivation_output_key
.
- Use
- Call the functions in the following sections to perform operations on the key. The same key object can be used in multiple operations.
- To free the resources used by the key object, call
psa_destroy_key
after all operations with that key are finished.
Unauthenticated cipher operations
Recall the workflow of an unauthenticated cipher operation in the legacy Mbed TLS cipher API:
- Create a cipher context of type
mbedtls_cipher_context_t
and initialize it withmbedtls_cipher_init
. - Establish the operation parameters (algorithm, key, mode) with
mbedtls_cipher_setup
,mbedtls_cipher_setkey
(ormbedtls_cipher_setup_psa
),mbedtls_cipher_set_padding_mode
if applicable. - Set the IV with
mbedtls_cipher_set_iv
(except for ECB which does not use an IV). - For a one-shot operation, call
mbedtls_cipher_crypt
. To pass the input in multiple parts, callmbedtls_cipher_update
as many times as necessary followed bymbedtls_cipher_finish
. - Finally free the resources associated with the operation object by calling
mbedtls_cipher_free
.
For a one-shot operation (where the whole plaintext or ciphertext is passed as a single input), the equivalent workflow with the PSA API is to call a single function:
psa_cipher_encrypt
to perform encryption with a random IV of the default size (indicated byPSA_CIPHER_IV_LENGTH
). (To encrypt with a specified IV, use the multi-part API described below.) You can use the macroPSA_CIPHER_ENCRYPT_OUTPUT_SIZE
orPSA_CIPHER_ENCRYPT_OUTPUT_MAX_SIZE
to determine a sufficient size for the output buffer.psa_cipher_decrypt
to perform decryption with a specified IV. You can use the macroPSA_CIPHER_DECRYPT_OUTPUT_SIZE
orPSA_CIPHER_DECRYPT_OUTPUT_MAX_SIZE
to determine a sufficient size for the output buffer.
For a multi-part operation, the equivalent workflow with the PSA API is as follows:
- Create an operation object of type
psa_cipher_operation_t
and zero-initialize it (or use the correspondingINIT
macro). - Select the key and algorithm with
psa_cipher_encrypt_setup
orpsa_cipher_decrypt_setup
depending on the desired direction. - When encrypting with a random IV, use
psa_cipher_generate_iv
. When encrypting with a chosen IV, or when decrypting, set the IV withpsa_cipher_set_iv
. Skip this step with ECB since it does not use an IV. - Call
psa_cipher_update
as many times as needed. You can usePSA_CIPHER_UPDATE_OUTPUT_SIZE
orPSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE
to determine a sufficient size for the output buffer. - Call
psa_cipher_finish
to obtain the last part of the output. You can usePSA_CIPHER_FINISH_OUTPUT_SIZE
orPSA_CIPHER_FINISH_OUTPUT_MAX_SIZE
to determine a sufficient size for the output buffer.
If you need to interrupt the operation after calling the setup function without calling the finish function, call psa_cipher_abort
.
Authenticated cipher operations
Recall the workflow of an authenticated cipher operation in the legacy Mbed TLS cipher API (or similar workflows in the chachapoly
, ccm
and gcm
modules):
- Create a cipher context of type
mbedtls_cipher_context_t
and initialize it withmbedtls_cipher_init
. - Establish the operation parameters (algorithm, key, mode) with
mbedtls_cipher_setup
,mbedtls_cipher_setkey
(ormbedtls_cipher_setup_psa
),mbedtls_cipher_set_padding_mode
if applicable. - Set the nonce with
mbedtls_cipher_set_iv
(or thestarts
function for low-level modules). For CCM, which requires direct use of theccm
module, also callmbedtls_ccm_set_lengths
to set the length of the additional data and of the plaintext. - Call
mbedtls_cipher_update_ad
to pass the unencrypted additional data. - Call
mbedtls_cipher_update
as many times as necessary to pass the input plaintext or ciphertext. - Call
mbedtls_cipher_finish
to obtain the last part of the output. Then callmbedtls_cipher_write_tag
(when encrypting) ormbedtls_cipher_check_tag
(when decrypting) to process the authentication tag. - Finally free the resources associated with the operation object by calling
mbedtls_cipher_free
.
Steps 3–6 can be replaced by a single call to mbedtls_cipher_auth_encrypt_ext
or mbedtls_cipher_auth_decrypt_ext
for a one-shot operation (where the whole plaintext or ciphertext is passed as a single input).
For a one-shot operation, the PSA API allows you to call a single function:
psa_aead_encrypt
to perform authenticated encryption with a random nonce of the default size (indicated byPSA_AEAD_NONCE_LENGTH
), with the authentication tag written at the end of the output. (To encrypt with a specified nonce, or to separate the tag from the rest of the ciphertext, use the multi-part API described below.) You can use the macroPSA_AEAD_ENCRYPT_OUTPUT_SIZE
orPSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE
to determine a sufficient size for the output buffer.psa_aead_decrypt
to perform authenticated decryption of a ciphertext with the authentication tag at the end. (If the tag is separate, use the multi-part API described below.) You can use the macroPSA_AEAD_DECRYPT_OUTPUT_SIZE
orPSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE
to determine a sufficient size for the output buffer.
For a multi-part operation, the equivalent workflow with the PSA API is as follows:
- Create an operation object of type
psa_aead_operation_t
and zero-initialize it (or use the correspondingINIT
macro). - Select the key and algorithm with
psa_aead_encrypt_setup
orpsa_aead_decrypt_setup
depending on the desired direction. - When encrypting with a random nonce, use
psa_aead_generate_nonce
. When encrypting with a chosen nonce, or when decrypting, set the nonce withpsa_aead_set_nonce
. If the algorithm is CCM, you must also callpsa_aead_set_lengths
before or after setting the nonce (for other algorithms, this is permitted but not needed). - Call
psa_aead_update_ad
as many times as needed. - Call
psa_aead_update
as many times as needed. You can usePSA_AEAD_UPDATE_OUTPUT_SIZE
orPSA_AEAD_UPDATE_OUTPUT_MAX_SIZE
to determine a sufficient size for the output buffer. - Finally:
- When encrypting, call
psa_aead_finish
to obtain the last part of the ciphertext and the authentication tag. You can usePSA_AEAD_FINISH_OUTPUT_SIZE
orPSA_AEAD_FINISH_OUTPUT_MAX_SIZE
to determine a sufficient size for the output buffer. - When decrypting, call
psa_aead_verify
to obtain the last part of the plaintext and check the authentication tag. You can usePSA_AEAD_VERIFY_OUTPUT_SIZE
orPSA_AEAD_VERIFY_OUTPUT_MAX_SIZE
to determine a sufficient size for the output buffer.
- When encrypting, call
If you need to interrupt the operation after calling the setup function without calling the finish or verify function, call psa_aead_abort
.
Miscellaneous cipher operation management
The equivalent of mbedtls_cipher_reset
is to call psa_cipher_abort
or psa_aead_abort
. Note that you must set the key again with a setup function: the PSA API does not have a special way to reuse an operation object with the same key.
There is no equivalent for the mbedtls_cipher_get_xxx
functions to extract information from an ongoing PSA cipher or AEAD operation. Applications that need this information will need to save it from the key and operation parameters.
Hashes and MAC
The PSA API groups functions by purpose rather than by underlying primitive: there is a MAC API (equivalent to md.h
for HMAC, and cmac.h
for CMAC) and a hash API (equivalent to md.h
for hashing). There is no special API for a particular hash algorithm (md5.h
, sha1.h
, sha256.h
, sha512.h
, sha3.h
). To migrate code using those low-level modules, please follow the recommendations in the following section, using the same principles as the corresponding md.h
API.
The PSA API does not have a direct interface for the AES-CMAC-PRF-128 algorithm from RFC 4615 calculated by mbedtls_aes_cmac_prf_128
at the time of writing. You can implement it using the MAC interface with an AES key and the CMAC algorithm.
Hash mechanism selection
The equivalent to mbedtls_md_type_t
and MBEDTLS_MD_XXX
constants is the type psa_algorithm_t
and PSA_ALG_xxx
constants (the type encompasses all categories of cryptographic algorithms, not just hashes). PSA offers a similar selection of algorithms, but note that SHA-1 and SHA-2 are spelled slightly differently.
Mbed TLS constant | PSA constant |
---|---|
MBEDTLS_MD_MD5 |
PSA_ALG_MD5 |
MBEDTLS_MD_SHA1 |
PSA_ALG_SHA_1 |
MBEDTLS_MD_SHA224 |
PSA_ALG_SHA_224 |
MBEDTLS_MD_SHA256 |
PSA_ALG_SHA_256 |
MBEDTLS_MD_SHA384 |
PSA_ALG_SHA_384 |
MBEDTLS_MD_SHA512 |
PSA_ALG_SHA_512 |
MBEDTLS_MD_RIPEMD160 |
PSA_ALG_RIPEMD160 |
MBEDTLS_MD_SHA3_224 |
PSA_ALG_SHA3_224 |
MBEDTLS_MD_SHA3_256 |
PSA_ALG_SHA3_256 |
MBEDTLS_MD_SHA3_384 |
PSA_ALG_SHA3_384 |
MBEDTLS_MD_SHA3_512 |
PSA_ALG_SHA3_512 |
The following helper functions can be used to convert between the 2 types:
mbedtls_md_psa_alg_from_type()
converts from legacymbedtls_md_type_t
to PSA'spsa_algorithm_t
.mbedtls_md_type_from_psa_alg()
converts from PSA'spsa_algorithm_t
to legacymbedtls_md_type_t
.
MAC mechanism selection
PSA Crypto has a generic API with the same functions for all MAC mechanisms. The mechanism is determined by a combination of an algorithm value of type psa_algorithm_t
and a key type value of type psa_key_type_t
.
- For HMAC, the algorithm is
PSA_ALG_HMAC
(hash)
wherehash
is the underlying hash algorithm (see “Hash mechanism selection”), for examplePSA_ALG_HMAC(PSA_ALG_SHA_256)
for HMAC-SHA-256. The key type isPSA_KEY_TYPE_HMAC
regardless of the hash algorithm. - For CMAC, the algorithm is
PSA_ALG_CMAC
regardless of the underlying block cipher. The key type determines the block cipher:PSA_KEY_TYPE_AES
,PSA_KEY_TYPE_ARIA
,PSA_KEY_TYPE_CAMELLIA
orPSA_KEY_TYPE_DES
.
Hash and MAC mechanism availability
For each key type value PSA_KEY_TYPE_xxx
, the symbol PSA_WANT_KEY_TYPE_xxx
is defined with a non-zero value if the library is built with support for that key type. For each algorithm value PSA_ALG_yyy
, the symbol PSA_WANT_ALG_yyy
is defined with a non-zero value if the library is built with support for that algorithm. For a compound mechanism, all parts must be supported. In particular, for HMAC, all three of PSA_WANT_KEY_TYPE_HMAC
, PSA_WANT_ALG_HMAC
and the underlying hash must be enabled. (A configuration with only one of PSA_WANT_KEY_TYPE_HMAC
and PSA_WANT_ALG_HMAC
is technically possible but not useful.)
For example, to test if HMAC-SHA-256 is supported, in the legacy API, you could write:
#if defined(MBEDTLS_MD_C) && defined(MBEDTLS_SHA256_C)
The equivalent in the PSA API is
#if PSA_WANT_KEY_TYPE_HMAC && PSA_WANT_ALG_HMAC && PSA_WANT_ALG_SHA_256
To test if AES-CMAC is supported, in the legacy API, you could write:
if defined(MBEDTLS_AES_C) && defined(MBEDTLS_CMAC_C)
The equivalent in the PSA API is
#if PSA_WANT_KEY_TYPE_AES && PSA_WANT_ALG_CMAC
Hash algorithm metadata
There is no equivalent to the type mbedtls_md_info_t
and the functions mbedtls_md_info_from_type
and mbedtls_md_get_type
in the PSA API because it is unnecessary. All macros and functions operate directly on algorithm (psa_algorithm_t
, PSA_ALG_xxx
constants).
Legacy macro | PSA macro |
---|---|
MBEDTLS_MD_MAX_SIZE |
PSA_HASH_MAX_SIZE |
MBEDTLS_MD_MAX_BLOCK_SIZE |
PSA_HMAC_MAX_HASH_BLOCK_SIZE |
mbedtls_md_get_size |
PSA_HASH_LENGTH |
mbedtls_md_get_size_from_type |
PSA_HASH_LENGTH |
The following features have no PSA equivalent:
mbedtls_md_list
: the PSA API does not currently have a discovery mechanism for cryptographic mechanisms, but one may be added in the future.mbedtls_md_info_from_ctx
mbedtls_cipher_info_from_string
,mbedtls_md_get_name
: there is no equivalent of Mbed TLS's lookup based on a (nonstandard) name.
Hash calculation
The equivalent of mbedtls_md
for a one-shot hash calculation is psa_hash_compute
. In addition, to compare the hash of a message with an expected value, you can call psa_hash_compare
instead of mbedtls_md
followed by memcmp
or a constant-time equivalent.
For a multi-part hash calculation, the legacy process is as follows:
- Create a digest context of type
mbedtls_md_context_t
and initialize it withmbedtls_md_init
. - Call
mbedtls_md_setup
to select the hash algorithm, withhmac=0
. Then callmbedtls_md_starts
to start the hash operation. - Call
mbedtls_md_update
as many times as necessary. - Call
mbedtls_md_finish
. If verifying the hash against an expected value, compare the result with the expected value. - Finally free the resources associated with the operation object by calling
mbedtls_md_free
.
The equivalent process in the PSA API is as follows:
- Create an operation object of type
psa_hash_operation_t
and zero-initialize it (or use the correspondingINIT
macro). - Call
psa_hash_setup
to specify the algorithm. - Call
psa_hash_update
as many times as necessary. - To obtain the hash, call
psa_hash_finish
. Alternatively, to verify the hash against an expected value, callpsa_hash_verify
.
If you need to interrupt the operation after calling the setup function without calling the finish or verify function, call psa_hash_abort
.
There is no equivalent to mbedtls_md_file
in the PSA API. Load the file data and calculate its hash.
MAC key management
The legacy API and the PSA API have a different organization of operations in several respects:
- In the legacy API, each operation object contains the necessary key material. In the PSA API, an operation object contains a reference to a key object. To perform a cryptographic operation, you must create a key object first. However, for a one-shot operation, you do not need an operation object, just a single function call.
- The legacy API uses the same interface for authenticated and non-authenticated ciphers, while the PSA API has separate functions.
- The legacy API uses the same functions for encryption and decryption, while the PSA API has separate functions where applicable.
Here is an overview of the lifecycle of a key object.
- First define the attributes of the key by filling a
psa_key_attributes_t
structure. You need to set the following parameters:- Call
psa_set_key_type
to set the key type to the desiredPSA_KEY_TYPE_xxx
value (see “Cipher mechanism selection”). - Call
psa_set_key_bits
to set the key's size in bits. This is optional withpsa_import_key
, which determines the key size from the length of the key material. - Call
psa_set_key_algorithm
to set the algorithm to the desiredPSA_ALG_xxx
value (see “Cipher mechanism selection”). By design, the same key cannot be used with multiple algorithms. - Call
psa_set_key_usage_flags
to enable at leastPSA_KEY_USAGE_SIGN_MESSAGE
to calculate a MAC orPSA_KEY_USAGE_VERIFY_MESSAGE
to verify the MAC of a message. To allow both directions, use the flag maskPSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE
.
- Call
- Call one of the key creation functions, passing the attributes defined in the previous step, to get an identifier of type
psa_key_id_t
to the key object.- Use
psa_import_key
to directly import key material. - If the key is randomly generated, use
psa_generate_key
. - If the key is derived from other material (for example from a key exchange), use the key derivation interface and create the key with
psa_key_derivation_output_key
.
- Use
- Call the functions in the following sections to perform operations on the key. The same key object can be used in multiple operations.
- To free the resources used by the key object, call
psa_destroy_key
after all operations with that key are finished.
MAC calculation
The process for a HMAC operation in the legacy API is as follows:
- Create a digest context of type
mbedtls_md_context_t
and initialize it withmbedtls_md_init
. - Call
mbedtls_md_setup
to select the hash algorithm, withhmac=1
. Then callmbedtls_md_hmac_starts
to set the key. - Call
mbedtls_md_hmac_update
as many times as necessary. - Call
mbedtls_md_hmac_finish
. If verifying the MAC against an expected value, compare the result with the expected value. Note that this comparison should be in constant time to avoid a side channel vulnerability, for example usingmbedtls_ct_memcmp
. - Finally free the resources associated with the operation object by calling
mbedtls_md_free
.
The process for a CMAC operation in the legacy API is as follows:
- Create a cipher context of type
mbedtls_cipher_context_t
and initialize it withmbedtls_cipher_init
. - Call
mbedtls_cipher_setup
to select the block cipher. Then callmbedtls_md_cmac_starts
to set the key. - Call
mbedtls_cipher_cmac_update
as many times as necessary. - Call
mbedtls_cipher_cmac_finish
. If verifying the MAC against an expected value, compare the result with the expected value. Note that this comparison should be in constant time to avoid a side channel vulnerability, for example usingmbedtls_ct_memcmp
. - Finally free the resources associated with the operation object by calling
mbedtls_cipher_free
.
The process in the PSA API to calculate a MAC is as follows:
- Create an operation object of type
psa_mac_operation_t
and zero-initialize it (or use the correspondingINIT
macro). - Call
psa_mac_sign_setup
to specify the algorithm and the key. See “MAC key management” for how to obtain a key identifier. - Call
psa_mac_update
as many times as necessary. - To obtain the MAC, call
psa_mac_sign_finish
.
To verify a MAC against an expected value, use the following process instead:
- Create an operation object of type
psa_mac_operation_t
and zero-initialize it (or use the correspondingINIT
macro). - Call
psa_mac_verify_setup
to specify the algorithm and the key. See “MAC key management” for how to obtain a key identifier. - Call
psa_mac_update
as many times as necessary. - To verify the MAC against an expected value, call
psa_mac_verify_finish
.
If you need to interrupt the operation after calling the setup function without calling the finish function, call psa_mac_abort
.
The PSA API also offers functions for a one-shot MAC calculation, similar to mbedtls_cipher_cmac
and mbedtls_md_hmac
:
psa_mac_compute
to calculate the MAC of a buffer in memory.psa_mac_verify
to verify the MAC of a buffer in memory against an expected value.
In both cases, see “MAC key management” for how to obtain a key identifier.
Miscellaneous hash or MAC operation management
The equivalent of mbedtls_md_reset
, mbedtls_md_hmac_reset
or mbedtls_cmac_reset
is to call psa_hash_abort
or psa_mac_abort
. Note that you must call a setup function to specify the algorithm and the key (for MAC) again, and they can be different ones.
The equivalent of mbedtls_md_clone
to clone a hash operation is psa_hash_clone
. A PSA MAC operation cannot be cloned.
Key derivation
HKDF
PSA Crypto provides access to HKDF, HKDF-Extract and HKDF-Expand via its key derivation interface. This is a generic interface using an operation object with one function call for each input and one function call for each output.
- Create an operation object of type
psa_key_derivation_operation_t
and zero-initialize it (or use the correspondingINIT
macro). - Call
psa_key_derivation_setup
to select the algorithm, which is a value of typepsa_algorithm_t
. For HKDF and variants, use one of the macrosPSA_ALG_HKDF
,PSA_ALG_HKDF_EXTRACT
orPSA_ALG_HKDF_EXPAND
with the hash algorithm passed as an argument. For examplePSA_ALG_HKDF(PSA_ALG_SHA_256)
selects HKDF-SHA-256. - Call
psa_key_derivation_input_bytes
on each of the inputs in the order listed below. (Usepsa_key_derivation_input_key
instead for an input that is a PSA key object.) The input step value for each step is as follows:PSA_KEY_DERIVATION_INPUT_SALT
for the salt used during the extraction step. Omit this step for HKDF-Expand. For HKDF, you may omit this step if the salt is empty.PSA_KEY_DERIVATION_INPUT_SECRET
for the secret input.PSA_KEY_DERIVATION_INPUT_INFO
for the info string used during the expansion step. Omit this step for HKDF-Extract.
- Call
psa_key_derivation_output_bytes
to obtain the output of the derivation. You may call this function more than once to retrieve the output in successive chunks. Usepsa_key_derivation_output_key
instead if you want to use a chunk as a PSA key. - Call
psa_key_derivation_abort
to free the resources associated with the key derivation object.
PKCS#5 module
Applications currently using mbedtls_pkcs5_pbkdf2_hmac
or mbedtls_pkcs5_pbkdf2_hmac_ext
can switch to the PSA key derivation API for PBKDF2. This is a generic interface using an operation object with one function call for each input and one function call for each output.
- Create an operation object of type
psa_key_derivation_operation_t
and zero-initialize it (or use the correspondingINIT
macro). - Call
psa_key_derivation_setup
to select the algorithm, which is a value of typepsa_algorithm_t
. For PBKDF2-HMAC, selectPSA_ALG_PBKDF2_HMAC(hash)
wherehash
is the underlying hash algorithm (see “Hash mechanism selection”). - Call
psa_key_derivation_input_cost
with the stepPSA_KEY_DERIVATION_INPUT_COST
to select the iteration count. - Call
psa_key_derivation_input_bytes
on each of the inputs in the order listed below. (Usepsa_key_derivation_input_key
instead for an input that is a PSA key object.) The input step value for each step is as follows:PSA_KEY_DERIVATION_INPUT_SALT
for the salt used during the extraction step. You may repeat this step to pass the salt in pieces (for example a salt and a pepper).PSA_KEY_DERIVATION_INPUT_SECRET
for the password.
- Call
psa_key_derivation_output_bytes
to obtain the output of the derivation. You may call this function more than once to retrieve the output in successive chunks. Usepsa_key_derivation_output_key
instead if you want to use a chunk as a PSA key.
If you want to verify the output against an expected value (for authentication, rather than to derive key material), callpsa_key_derivation_verify_bytes
orpsa_key_derivation_verify_key
instead ofpsa_key_derivation_output_bytes
. (Note that theverify
functions are not yet present in the 3.5 release of Mbed TLS. They are expected to be released in version 3.6.0.) - Call
psa_key_derivation_abort
to free the resources associated with the key derivation object.
The function mbedtls_pkcs5_pbes2
is only intended as a support function to parse encrypted private keys in the PK module. It has no PSA equivalent.
PKCS#12 module
The functions mbedtls_pkcs12_derivation
and mbedtls_pkcs12_pbe
are only intended as support functions to parse encrypted private keys in the PK module. They have no PSA equivalent.
Random generation
Random generation interface
The PSA subsystem has an internal random generator. As a consequence, you do not need to instantiate one manually, so most applications using PSA crypto do not need the interfaces from entropy.h
, ctr_drbg.h
and hmac_drbg.h
. See the next sections for remaining use cases for entropy and DRBG.
The PSA API uses its internal random generator to generate keys (psa_generate_key
), nonces for encryption (psa_cipher_generate_iv
, psa_cipher_encrypt
, psa_aead_generate_nonce
, psa_aead_encrypt
, psa_asymmetric_encrypt
), and other random material as needed. If you need random data for some other purposes, call psa_generate_random
.
If your application mixes uses of the PSA crypto API and the mbedtls API and you need to pass an RNG argument to a legacy or X.509/TLS function, include the header file <mbedtls/psa_util.h>
and use:
mbedtls_psa_get_random
as thef_rng
argument;MBEDTLS_PSA_RANDOM_STATE
as thep_rng
argument.
You can remove the Mbed TLS RNG boilerplate (mbedtls_entropy_init
, mbedtls_ctr_drbg_init
, mbedtls_ctr_drbg_seed
, mbedtls_ctr_drbg_random
, mbedtls_ctr_drbg_free
, mbedtls_entropy_free
— or hmac_drbg
equivalents of the ctr_drbg
functions) once you have finished replacing the references to mbedtls_ctr_drbg_random
(or mbedtls_hmac_drbg_random
) by mbedtls_psa_get_random
.
Entropy sources
Unless explicitly configured otherwise, the PSA random generator uses the default entropy sources configured through the legacy interface (MBEDTLS_ENTROPY_xxx
symbols). Its set of sources is equivalent to an entropy object configured with mbedtls_entropy_init
.
A future version of Mbed TLS will include a PSA interface for configuring entropy sources. This is likely to replace the legacy interface in Mbed TLS 4.0.
Deterministic pseudorandom generation
The PSA API does not have a dedicated interface for pseudorandom generation. The key derivation interface can serve a similar purpose in some applications, but it does not offer CTR_DRBG or HMAC_DRBG. If you need these algorithms, keep using ctr_drbg.h
and hmac_drbg.h
, but note that they may be removed from the public API in Mbed TLS 4.0.
Asymmetric cryptography
The PSA API supports RSA (see “RSA mechanism selection”), elliptic curve cryptography (see “ECC mechanism selection” and “EC-JPAKE”) and finite-field Diffie-Hellman (see “Diffie-Hellman mechanism selection”).
Key lifecycle for asymmetric cryptography
In the PSA API, keys are referenced by an identifier of type psa_key_id_t
.
(Some documentation references mbedtls_svc_key_id_t
; the two types are identical except when the library is configured for use in a multi-client cryptography service.)
The PSA key identifier tends to play the same role as an mbedtls_pk_context
, mbedtls_rsa_context
or mbedtls_ecp_keypair
structure in the legacy API. However, there are major differences in the way the two APIs can be used to create keys or to obtain information about a key.
Here is an overview of the lifecycle of a PSA key object.
- First define the attributes of the key by filling a
psa_key_attributes_t
structure. You need to set the following parameters:- Call
psa_set_key_type
to set the key type to the desiredPSA_KEY_TYPE_xxx
value (see “RSA mechanism selection”, “Elliptic curve mechanism selection” and “Diffie-Hellman mechanism selection”). - Call
psa_set_key_bits
to set the key's conceptual size in bits. This is optional withpsa_import_key
, which determines the key size from the length of the key material. - Call
psa_set_key_algorithm
to set the permitted algorithm to the desiredPSA_ALG_xxx
value (see “RSA mechanism selection”, “Elliptic curve mechanism selection” and “Diffie-Hellman mechanism selection” as well as “Public-key cryptography policies”). - Call
psa_set_key_usage_flags
to enable the desired usage types (see “Public-key cryptography policies”).
- Call
- Call one of the key creation functions, passing the attributes defined in the previous step, to get an identifier of type
psa_key_id_t
to the key object.- Use
psa_import_key
to directly import key material. - If the key is randomly generated, use
psa_generate_key
. - If the key is derived from other material (for example from a key exchange), use the key derivation interface and create the key with
psa_key_derivation_output_key
.
- Use
- Call the functions in the following sections to perform operations on the key. The same key object can be used in multiple operations.
- To free the resources used by the key object, call
psa_destroy_key
after all operations with that key are finished.
Public-key cryptography policies
A key's policy indicates what algorithm(s) it can be used with (usage algorithm policy) and what operations are permitted (usage flags).
The following table lists the relevant usage flags for asymmetric cryptography. You can pass those flags (combined with bitwise-or) to psa_set_key_usage_flags
.
Usage | Flag |
---|---|
export public key | 0 (always permitted) |
export private key | PSA_KEY_USAGE_EXPORT |
Sign a message directly | PSA_KEY_USAGE_SIGN_MESSAGE |
Sign an already-calculated hash | at least one of PSA_KEY_USAGE_SIGN_MESSAGE or PSA_KEY_USAGE_SIGN_HASH |
Verify a message directly | PSA_KEY_USAGE_VERIFY_MESSAGE |
Verify an already-calculated hash | at least one of PSA_KEY_USAGE_VERIFY_MESSAGE or PSA_KEY_USAGE_VERIFY_HASH |
Encryption | PSA_KEY_USAGE_ENCRYPT |
Decryption | PSA_KEY_USAGE_DECRYPT |
Key agreement | PSA_KEY_USAGE_DERIVE |
The sections “RSA mechanism selection”, “Elliptic curve mechanism selection” and “Diffie-Hellman mechanism selection” cover the available algorithm values for each key type. Normally, a key can only be used with a single algorithm, following standard good practice. However, there are two ways to relax this requirement.
- Many signature algorithms encode a hash algorithm. Sometimes the same key may need to be used to sign messages with multiple different hashes. In an algorithm policy, you can use
PSA_ALG_ANY_HASH
instead of a hash algorithm value to allow the key to be used with any hash. For example,psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PSS(PSA_ALG_ANY_HASH))
allows the key to be used with RSASSA-PSS, with different hash algorithms in each operation. - In addition to the algorithm (or wildcard) selected with
psa_set_key_algorithm
, you can usepsa_set_key_enrollment_algorithm
to permit a second algorithm (or wildcard). This is intended for scenarios where a key is normally used with a single algorithm, but needs to be used with a different algorithm for enrollment (such as an ECDH key for which an ECDSA proof-of-possession is also required).
Asymmetric cryptographic mechanisms
RSA mechanism selection
The PK types MBEDTLS_PK_RSA
, MBEDTLS_PK_RSASSA_PSS
and MBEDTLS_PK_RSA_ALT
correspond to RSA key types in the PSA API. In the PSA API, key pairs and public keys are separate object types.
See “RSA-ALT interface” for more information about MBEDTLS_PK_RSA_ALT
.
The PSA API uses policies and algorithm parameters rather than key types to distinguish between RSA-based mechanisms. The PSA algorithm selection corresponds to the mbedtls_pk_type_t
value passed to mbedtls_pk_{sign,verify}_ext
. It also replaces the use of mbedtls_rsa_set_padding
on an mbedtls_rsa_context
object. See the list of algorithms below and the signature and encryption sections for more information.
An RSA public key has the type PSA_KEY_TYPE_RSA_PUBLIC_KEY
.
An RSA key pair has the type PSA_KEY_TYPE_RSA_KEY_PAIR
. A key with this type can be used both for private-key and public-key operations (there is no separate key type for a private key without the corresponding public key).
You can always use a private key for operations on the corresponding public key (as long as the policy permits it).
The following cryptographic algorithms work with RSA keys:
- PKCS#1v1.5 RSA signature:
PSA_ALG_RSA_PKCS1V15_SIGN
,PSA_ALG_RSA_PKCS1V15_SIGN_RAW
. - PKCS#1v1.5 RSA encryption:
PSA_ALG_RSA_PKCS1V15_CRYPT
. - PKCS#1 RSASSA-PSS signature:
PSA_ALG_RSA_PSS
,PSA_ALG_RSA_PSS_ANY_SALT
. - PKCS#1 RSAES-OAEP encryption:
PSA_ALG_RSA_OAEP
.
Elliptic curve mechanism selection
The PK types MBEDTLS_PK_ECKEY
, MBEDTLS_PK_ECKEY_DH
and MBEDTLS_PK_ECDSA
correspond to elliptic-curve key types in the PSA API. In the PSA API, key pairs and public keys are separate object types. The PSA API uses policies and algorithm parameters rather than key types to distinguish between the PK EC types.
An ECC public key has the type PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve)
where curve
is a curve family identifier.
An ECC key pair has the type PSA_KEY_TYPE_ECC_KEY_PAIR(curve)
where curve
is a curve family identifier. A key with this type can be used both for private-key and public-key operations (there is no separate key type for a private key without the corresponding public key).
You can always use a private key for operations on the corresponding public key (as long as the policy permits it).
A curve is fully determined by a curve family identifier and the private key size in bits. You can use the following functions to convert between the PSA and legacy elliptic curve designations:
mbedtls_ecc_group_to_psa()
converts from the legacy curve type identifier to PSA curve family and bit-size.mbedtls_ecc_group_from_psa()
converts from PSA curve family and bit-size to the legacy identifier.
The following table gives the correspondence between legacy and PSA elliptic curve designations.
Mbed TLS legacy curve identifier | PSA curve family | Curve bit-size |
---|---|---|
MBEDTLS_ECP_DP_SECP192R1 |
PSA_ECC_FAMILY_SECP_R1 |
192 |
MBEDTLS_ECP_DP_SECP224R1 |
PSA_ECC_FAMILY_SECP_R1 |
224 |
MBEDTLS_ECP_DP_SECP256R1 |
PSA_ECC_FAMILY_SECP_R1 |
256 |
MBEDTLS_ECP_DP_SECP384R1 |
PSA_ECC_FAMILY_SECP_R1 |
384 |
MBEDTLS_ECP_DP_SECP521R1 |
PSA_ECC_FAMILY_SECP_R1 |
521 |
MBEDTLS_ECP_DP_BP256R1 |
PSA_ECC_FAMILY_BRAINPOOL_P_R1 |
256 |
MBEDTLS_ECP_DP_BP384R1 |
PSA_ECC_FAMILY_BRAINPOOL_P_R1 |
384 |
MBEDTLS_ECP_DP_BP512R1 |
PSA_ECC_FAMILY_BRAINPOOL_P_R1 |
512 |
MBEDTLS_ECP_DP_CURVE25519 |
PSA_ECC_FAMILY_MONTGOMERY |
255 |
MBEDTLS_ECP_DP_SECP192K1 |
PSA_ECC_FAMILY_SECP_K1 |
192 |
MBEDTLS_ECP_DP_SECP224K1 |
not supported | N/A |
MBEDTLS_ECP_DP_SECP256K1 |
PSA_ECC_FAMILY_SECP_K1 |
256 |
MBEDTLS_ECP_DP_CURVE448 |
PSA_ECC_FAMILY_MONTGOMERY |
448 |
The following cryptographic algorithms work with ECC keys:
- ECDH key agreement (including X25519 and X448):
PSA_ALG_ECDH
. - ECDSA:
PSA_ALG_ECDSA
,PSA_ALG_ECDSA_ANY
,PSA_ALG_DETERMINISTIC_ECDSA
. - EC-JPAKE (see “EC-JPAKE”.
Diffie-Hellman mechanism selection
A finite-field Diffie-Hellman key pair has the type PSA_KEY_TYPE_DH_KEY_PAIR(group)
where group
is a group family as explained below.
A finite-field Diffie-Hellman public key has the type PSA_KEY_TYPE_DH_PUBLIC_KEY(group)
where group
is a group family as explained below. Due to the design of the API, there is rarely a need to use Diffie-Hellman public key objects.
The PSA API only supports Diffie-Hellman with predefined groups. A group is fully determined by a group family identifier and the public key size in bits.
Mbed TLS DH group P value | PSA DH group family | Bit-size |
---|---|---|
MBEDTLS_DHM_RFC7919_FFDHE2048_P_BIN |
PSA_DH_FAMILY_RFC7919 |
2048 |
MBEDTLS_DHM_RFC7919_FFDHE3072_P_BIN |
PSA_DH_FAMILY_RFC7919 |
3072 |
MBEDTLS_DHM_RFC7919_FFDHE4096_P_BIN |
PSA_DH_FAMILY_RFC7919 |
4096 |
MBEDTLS_DHM_RFC7919_FFDHE6144_P_BIN |
PSA_DH_FAMILY_RFC7919 |
6144 |
MBEDTLS_DHM_RFC7919_FFDHE8192_P_BIN |
PSA_DH_FAMILY_RFC7919 |
8192 |
A finite-field Diffie-Hellman key can be used for key agreement with the algorithm PSA_ALG_FFDH
.
Creating keys for asymmetric cryptography
The easiest way to create a key pair object is by randomly generating it with psa_generate_key
. Compared with the low-level functions from the legacy API (mbedtls_rsa_gen_key
, mbedtls_ecp_gen_privkey
, mbedtls_ecp_gen_keypair
, mbedtls_ecp_gen_keypair_base
, mbedtls_ecdsa_genkey
), this directly creates an object that can be used with high-level APIs, but removes some of the flexibility. Note that if you want to export the generated private key, you must pass the flag PSA_KEY_USAGE_EXPORT
to psa_set_key_usage_flags
; exporting the public key with psa_export_public_key
is always permitted.
For RSA keys, psa_generate_key
always uses 65537 as the public exponent. If you need a different public exponent, use the legacy interface to create the key then import it as described in “Importing legacy keys via the PK module”.
To create a key object from existing material, use psa_import_key
. While this function has the same basic goal as the PK parse functions (mbedtls_pk_parse_key
, mbedtls_pk_parse_public_key
, mbedtls_pk_parse_subpubkey
), it is limited to a single format that just contains the number(s) that make up the key, with very little metadata. This format is a substring of one of the formats accepted by the PK functions (except for finite-field Diffie-Hellman which the PK module does not support). The table below summarizes the PSA import/export format for key pairs and public keys; see the documentation of psa_export_key
and psa_export_public_key
for more details.
Key type | PSA import/export format |
---|---|
RSA key pair | PKCS#1 RSAPrivateKey DER encoding (including both private exponent and CRT parameters) |
RSA public key | PKCS#1 RSAPublicKey DER encoding |
ECC key pair | Fixed-length private value (not containing the public key) |
ECC public key (Weierstrass curve) | Fixed-length uncompressed point |
ECC public key (Montgomery curve) | Fixed-length public value |
FFDH key pair | Fixed-length private value (not containing the public key) |
FFDH public key | Fixed-length public value |
There is no equivalent of mbedtls_pk_parse_keyfile
and mbedtls_pk_parse_public_keyfile
. Either call the legacy function or load the file data manually.
A future extension of the PSA API will support other import formats. Until those are implemented, see the following subsections for ways to use the PK module for key parsing and construct a PSA key object from the PK object.
Importing legacy keys via the PK module
You can use glue functions in the PK module to create a key object using the legacy API, then import that object into the PSA subsystem. This is useful for use cases that the PSA API does not currently cover, such as:
- Parsing a key in a format with metadata without knowing its type ahead of time.
- Importing a key which you have in the form of a list of numbers, rather than the binary encoding required by
psa_import_key
. - Importing a key with less information than what the PSA API needs, for example an ECC public key in a compressed format, an RSA private key without the private exponent, or an RSA private key without the CRT parameters.
- Generating an RSA key with
e \ne 65537
.
Importing a PK key by wrapping
If you have a PK object, you can call mbedtls_pk_wrap_as_opaque
to create a PSA key object with the same key material. (This function is only present in builds with MBEDTLS_USE_PSA_CRYPTO
enabled. It is experimental and will likely be replaced by a slightly different interface in a future version of Mbed TLS). This function automatically determines the PSA key type and lets you specify the usage policy (see “Public-key cryptography policies”). Once you've called this function, you can destroy the PK object. This function calls psa_import_key
internally; call psa_destroy_key
to destroy the PSA key object once your application no longer needs it. Common scenarios where this workflow is useful are:
- You have working code that's calling
mbedtls_pk_parse_key
,mbedtls_pk_parse_public_key
,mbedtls_pk_parse_subpubkey
,mbedtls_pk_parse_keyfile
ormbedtls_pk_parse_public_keyfile
to create a PK object. - You have working code that's using the
rsa.h
orecp.h
API to create a key object, and there is no PSA equivalent.
You can use this workflow to import an RSA key via an mbedtls_rsa_context
object or an ECC key via an mbedtls_ecp_keypair
object:
- Call
mbedtls_pk_init
thenmbedtls_pk_setup
to set up a PK context for the desired key type (MBEDTLS_PK_RSA
orMBEDTLS_PK_ECKEY
). - Call
mbedtls_pk_rsa
ormbedtls_pk_ec
to obtain the underlying low-level context. - Call
mbedtls_rsa_xxx
ormbedtls_ecp_xxx
functions to construct the desired key. For example:mbedtls_rsa_import
ormbedtls_rsa_import_raw
followed bymbedtls_rsa_complete
to create an RSA private key without all the parameters required by the PSA API.mbedtls_rsa_gen_key
to generate an RSA private key with a custom public exponent.
- Call
mbedtls_pk_wrap_as_opaque
as described above to create a corresponding PSA key object. - Call
mbedtls_pk_free
to free the resources associated with the PK object.
Importing a PK key by export-import
This section explains how to export a PK object in the PSA import format. The process depends on the key type. You can use mbedtls_pk_get_type
or mbedtls_pk_can_do
to distinguish between RSA and ECC keys. The snippets below assume that the key is in an mbedtls_pk_context pk
, and omit error checking.
For an RSA private key:
unsigned char buf[PSA_EXPORT_KEY_PAIR_MAX_SIZE];
size_t length = mbedtls_pk_write_key_der(&pk, buf, sizeof(buf));
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_attributes(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_... | ...);
psa_set_key_algorithm(&attributes, PSA_ALGORITHM_...);
psa_key_id_t key_id = 0;
psa_import_key(&attributes, buf + sizeof(buf) - length, length, &key_id);
mbedtls_pk_free(&pk);
For an ECC private key (a future version of Mbed TLS will provide a more direct way to find the curve family):
unsigned char buf[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)];
mbedtls_ecp_keypair *ec = mbedtls_pk_ec(&pk);
psa_ecc_curve_t curve;
{
mbedtls_ecp_group grp;
mbedtls_ecp_group_init(&grp);
mbedtls_ecp_point Q;
mbedtls_ecp_point_init(&Q);
mbedtls_mpi d;
mbedtls_mpi_init(&d);
mbedtls_ecp_export(ec, &grp, &d, &Q);
size_t bits;
curve = mbedtls_ecc_group_to_psa(grp.id, &bits);
mbedtls_ecp_group_free(&grp);
mbedtls_ecp_point_free(&Q);
mbedtls_mpi_free(&d);
}
size_t length;
mbedtls_ecp_write_key_ext(ec, &length, buf, sizeof(buf));
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(curve));
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_... | ...);
psa_set_key_algorithm(&attributes, PSA_ALGORITHM_...);
psa_key_id_t key_id = 0;
psa_import_key(&attributes, buf, length, &key_id);
mbedtls_pk_free(&pk);
For an RSA or ECC public key:
unsigned char buf[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
size_t length = mbedtls_pk_write_pubkey(&pk, buf, sizeof(buf));
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_attributes(&attributes, ...); // need to determine the type manually
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_... | ...);
psa_set_key_algorithm(&attributes, PSA_ALGORITHM_...);
psa_key_id_t key_id = 0;
psa_import_key(&attributes, buf + sizeof(buf) - length, length, &key_id);
mbedtls_pk_free(&pk);
Importing an elliptic curve key from ECP
This section explains how to use the ecp.h
API to create an elliptic curve key in a format suitable for psa_import_key
.
You can use this, for example, to import an ECC key in the form of a compressed point by calling mbedtls_ecp_point_read_binary
then following the process below.
The following code snippet illustrates how to import a private key which is initially in an mbedtls_ecp_keypair
object. (This includes mbedtls_ecdsa_keypair
objects since that is just a type alias.) Error checks are omitted for simplicity. A future version of Mbed TLS will provide a function to calculate the curve family.
mbedtls_ecp_keypair ec;
mbedtls_ecp_keypair_init(&ec);
// Omitted: fill ec with key material
// (the public key will not be used and does not need to be set)
unsigned char buf[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)];
size_t length;
mbedtls_ecp_write_key_ext(&ec, &length, buf, sizeof(buf));
psa_ecc_curve_t curve = ...; // need to determine the curve family manually
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_attributes(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(curve));
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_... | ...);
psa_set_key_algorithm(&attributes, PSA_ALGORITHM_...);
psa_key_id_t key_id = 0;
psa_import_key(&attributes, buf, length, &key_id);
mbedtls_ecp_keypair_free(&ec);
The following code snippet illustrates how to import a private key which is initially in an mbedtls_ecp_keypair
object. Error checks are omitted for simplicity.
mbedtls_ecp_group grp;
mbedtls_ecp_group_init(&grp);
mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_...);
mbedtls_ecp_point pt;
mbedtls_ecp_point_init(&pt);
// Omitted: fill pt with key material
unsigned char buf[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_PUBLIC_KEY_MAX_SIZE)];
size_t length;
mbedtls_ecp_point_write_binary(&grp, &pt, &length, buf, sizeof(buf));
psa_ecc_curve_t curve = ...; // need to determine the curve family manually
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_attributes(&attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve));
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_... | ...);
psa_set_key_algorithm(&attributes, PSA_ALGORITHM_...);
psa_key_id_t key_id = 0;
psa_import_key(&attributes, buf, length, &key_id);
mbedtls_ecp_point_free(&pt);
mbedtls_ecp_group_free(&grp);
Key pair and public key metadata
There is no equivalent to the type mbedtls_pk_info_t
and the functions mbedtls_pk_info_from_type
in the PSA API because it is unnecessary. All macros and functions operate directly on key type values (psa_key_type_t
, PSA_KEY_TYPE_xxx
constants) and algorithm values (psa_algorithm_t
, PSA_ALG_xxx
constants).
You can call psa_get_key_attributes
to populate a structure with the attributes of a key, then functions such as psa_get_key_type
and psa_get_key_bits
to obtain a key's type (PSA_KEY_TYPE_xxx
value) and size (nominal size in bits).
The bit-size from psa_get_key_bits
is the same as the one from mbedtls_pk_get_bitlen
. To convert to bytes as mbedtls_pk_get_len
or mbedtls_rsa_get_len
do, you can use the macro PSA_BITS_TO_BYTES
. However, note that the PSA API has generic macros for each related buffer size (export, signature size, etc.), so you should generally use those instead. The present document lists those macros where it explains the usage of the corresponding function.
Most code that calls mbedtls_pk_get_type
or mbedtls_pk_can_do
only requires the key's type as reported by psa_get_key_type
. For code that uses both mbedtls_pk_context
objects and PSA metadata encoding, mbedtls_pk_can_do_ext
checks the compatibility between a key object and a mechanism. If needed, you can also access a key's policy from its attributes with psa_get_key_usage_flags
, psa_get_key_algorithm
and psa_get_key_enrollment_algorithm
. The algorithm policy also conveys the padding and hash information provided by mbedtls_rsa_get_padding_mode
and mbedtls_rsa_get_md_alg
.
Exporting a public key or a key pair
To export a PSA key pair or public key, call psa_export_key
. If the key is a key pair, its policy must allow PSA_KEY_USAGE_EXPORT
(see “Public-key cryptography policies”).
To export a PSA public key or to export the public key of a PSA key pair object, call psa_export_public_key
. This is always permitted regardless of the key's policy.
The export format is the same format used for psa_import_key
, described in “Creating keys for asymmetric cryptography” above.
A future extension of the PSA API will support other export formats. Until those are implemented, see “Exporting a PK key by wrapping” for ways to use the PK module to format a PSA key.
Exporting a PK key by wrapping
You can wrap a PSA key object in a PK key context with mbedtls_pk_setup_opaque
. This allows you to call functions such as mbedtls_pk_write_key_der
, mbedtls_pk_write_pubkey_der
, mbedtls_pk_write_pubkey_pem
, mbedtls_pk_write_key_pem
or mbedtls_pk_write_pubkey
to export the key data in various formats.
Signature operations
The equivalent of mbedtls_pk_sign
or mbedtls_pk_sign_ext
to sign an already calculated hash is psa_sign_hash
.
The key must be a key pair allowing the usage PSA_KEY_USAGE_SIGN_HASH
(see “Public-key cryptography policies”).
Use PSA_SIGN_OUTPUT_SIZE
or PSA_SIGNATURE_MAX_SIZE
(similar to MBEDTLS_PK_SIGNATURE_MAX_SIZE
) to determine a sufficient size for the output buffer.
This is also the equivalent of the type-specific functions mbedtls_rsa_pkcs1_sign
, mbedtls_rsa_rsassa_pkcs1_v15_sign
, mbedtls_rsa_rsassa_pss_sign
, mbedtls_rsa_rsassa_pss_sign_ext
, mbedtls_ecdsa_sign
, mbedtls_ecdsa_sign_det_ext
and mbedtls_ecdsa_write_signature
. Note that the PSA API uses the raw format for ECDSA signatures, not the ASN.1 format; see “ECDSA signature” for more details.
The equivalent of mbedtls_pk_verify
or mbedtls_pk_verify_ext
to verify an already calculated hash is psa_verify_hash
.
The key must be a public key (or a key pair) allowing the usage PSA_KEY_USAGE_VERIFY_HASH
(see “Public-key cryptography policies”).
This is also the equivalent of the type-specific functions mbedtls_rsa_pkcs1_verify
, mbedtls_rsa_rsassa_pkcs1_v15_verify
, mbedtls_rsa_rsassa_pss_verify
, mbedtls_rsa_rsassa_pss_verify_ext
, mbedtls_ecdsa_verify
amd mbedtls_ecdsa_read_signature
. Note that the PSA API uses the raw format for ECDSA signatures, not the ASN.1 format; see “ECDSA signature” for more details.
Generally, psa_sign_hash
and psa_verify_hash
require the input to have the correct length for the hash (this has historically not always been enforced in the corresponding legacy APIs).
See also “Restartable ECDSA signature” for a restartable variant of this API.
The PSA API also has functions psa_sign_message
and psa_verify_message
. These functions combine the hash calculation with the signature calculation or verification.
For psa_sign_message
, either the usage flag PSA_KEY_USAGE_SIGN_MESSAGE
or PSA_KEY_USAGE_SIGN_HASH
is sufficient.
For psa_verify_message
, either the usage flag PSA_KEY_USAGE_VERIFY_MESSAGE
or PSA_KEY_USAGE_VERIFY_HASH
is sufficient.
Most signature algorithms involve a hash algorithm. See “Hash mechanism selection”.
The following subsections describe the PSA signature mechanisms that correspond to legacy Mbed TLS mechanisms.
ECDSA signature
Note: in the PSA API, the format of an ECDSA signature is the raw fixed-size format. This is different from the legacy API which uses the ASN.1 DER format for ECDSA signatures. A future version of Mbed TLS will provide a way to convert between the two formats.
ECDSA is the mechanism provided by mbedtls_pk_sign
and mbedtls_pk_verify
for ECDSA keys, as well as by mbedtls_ecdsa_sign
, mbedtls_ecdsa_sign_det_ext
, mbedtls_ecdsa_write_signature
, mbedtls_ecdsa_verify
and mbedtls_ecdsa_read_signature
.
The PSA API offers three algorithm constructors for ECDSA. They differ only for signature, and have exactly the same behavior for verification.
PSA_ALG_ECDSA(hash)
is a randomized ECDSA signature of a hash calculated with the algorithmhash
.PSA_ALG_ECDSA_ANY
is equivalent toPSA_ALG_ECDSA
, but does not require specifying a hash as part of the algorithm. It can only be used withpsa_sign_hash
andpsa_verify_hash
, with no constraint on the length of the hash.PSA_ALG_DETERMINISTIC_ECDSA(hash)
is a deterministic ECDSA signature of a hash calculated with the algorithmhash
. This is the same as the functionality offered byMBEDTLS_ECDSA_DETERMINISTIC
in the legacy API.- For
psa_sign_message
withPSA_ALG_DETERMINISTIC_ECDSA
, the same hash algorithm is used to hash the message and to parametrize the deterministic signature generation.
- For
Unlike the legacy API, where mbedtls_pk_sign
and mbedtls_ecdsa_write_signature
automatically select deterministic ECDSA if both are available, the PSA API requires the application to select the preferred variant. ECDSA verification cannot distinguish between randomized and deterministic ECDSA (except in so far as if the same message is signed twice and the signatures are different, then at least one of the signatures is not the determinstic variant), so in most cases switching between the two is a compatible change.
Restartable ECDSA signature
The legacy API includes an API for “restartable” ECC operations: the operation returns after doing partial computation, and can be resumed. This is intended for highly constrained devices where long cryptographic calculations need to be broken up to poll some inputs, where interrupt-based scheduling is not desired. The legacy API consists of the functions mbedtls_pk_sign_restartable
, mbedtls_pk_verify_restartable
, mbedtls_ecdsa_sign_restartable
, mbedtls_ecdsa_verify_restartable
, mbedtls_ecdsa_write_signature_restartable
, mbedtls_ecdsa_read_signature_restartable
, as well as several configuration and data manipulation functions.
The PSA API offers similar functionality via “interruptible” public-key operations. As of Mbed TLS 3.5, it is only implemented for ECDSA, for the same curves as the legacy API. This will likely be extended to ECDH in the short term. At the time of writing, no extension is planned to other curves or other algorithms.
The flow of operations for an interruptible signature operation is as follows:
- Create an operation object of type
psa_sign_hash_interruptible_operation_t
and zero-initialize it (or use the correspondingINIT
macro). - Call
psa_sign_hash_start
with the private key object and the hash to verify. - Call
psa_sign_hash_complete
repeatedly until it returns a status other thanPSA_OPERATION_INCOMPLETE
.
The flow of operations for an interruptible signature verification operation is as follows:
- Create an operation object of type
psa_verify_hash_interruptible_operation_t
and zero-initialize it (or use the correspondingINIT
macro). - Call
psa_verify_hash_start
with the private key object and the hash and signature to verify. - Call
psa_verify_hash_complete
repeatedly until it returns a status other thanPSA_OPERATION_INCOMPLETE
.
If you need to cancel the operation after calling the start function without waiting for the loop calling the complete function to finish, call psa_sign_hash_abort
or psa_verify_hash_abort
.
Call psa_interruptible_set_max_ops
to set the number of basic operations per call. This is the same unit as mbedtls_ecp_set_max_ops
. You can retrieve the current value with psa_interruptible_get_max_ops
. The value is PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
if operations are not restartable, which corresponds to mbedtls_ecp_restart_is_enabled()
being false.
PKCS#1 v1.5 RSA signature
This mechanism corresponds to mbedtls_pk_sign
, mbedtls_pk_verify
, mbedtls_rsa_pkcs1_sign
and mbedtls_rsa_pkcs1_verify
for an RSA key, unless PSS has been selected with mbedtls_rsa_set_padding
on the underlying RSA key context. This mechanism also corresponds to mbedtls_rsa_rsassa_pkcs1_v15_sign
and mbedtls_rsa_rsassa_pkcs1_v15_verify
.
The PSA API has two algorithm constructors:
PSA_ALG_RSA_PKCS1V15_SIGN(hash)
formats the hash as specified in PKCS#1. The hash algorithm corresponds to themd_alg
parameter of the legacy functions.PSA_ALG_RSA_PKCS1V15_SIGN_RAW
uses the “hash” input in lieu of a DigestInfo structure. This is the same as calling the legacy functions withmd_alg=MBEDTLS_MD_NONE
.
PKCS#1 RSASSA-PSS signature
This mechanism corresponds to mbedtls_pk_sign_ext
and mbedtls_pk_verify_ext
for an RSA key, as well as mbedtls_pk_sign
, mbedtls_pk_verify
, mbedtls_rsa_pkcs1_sign
and mbedtls_rsa_pkcs1_verify
if PSS has been selected on the underlying RSA context with mbedlts_rsa_set_padding
.
It also corresponds to mbedtls_rsa_rsassa_pss_sign
and mbedtls_rsa_rsassa_pss_sign_ext
, mbedtls_rsa_rsassa_pss_verify
and mbedtls_rsa_rsassa_pss_verify_ext
.
The PSA API has two algorithm constructors: PSA_ALG_RSA_PSS(hash)
and PSA_ALG_RSA_PSS_ANY_SALT(hash)
. They differ only for verification, and have exactly the same behavior for signature. The hash algorithm hash
corresponds to the md_alg
parameter passed to the legacy API. It is used to hash the message, to create the salted hash, and for the mask generation with MGF1. The PSA API does not support using different hash algorithms for these different purposes.
With respect to the salt length:
- When signing, the salt is random, and the salt length is the largest possible salt length up to the hash length. This is the same as passing
MBEDTLS_RSA_SALT_LEN_ANY
as the salt length toxxx_ext
legacy functions or using a legacy function that does not have asaltlen
argument. - When verifying,
PSA_ALG_RSA_PSS
requires the the salt length to the largest possible salt length up to the hash length (i.e. the same that would be used for signing). - When verifying,
PSA_ALG_RSA_PSS_ANY_SALT
accepts any salt length. This is the same as passingMBEDTLS_RSA_SALT_LEN_ANY
as the salt length toxxx_ext
legacy functions or using a legacy function that does not have asaltlen
argument.
Asymmetric encryption and decryption
The equivalent of mbedtls_pk_encrypt
, mbedtls_rsa_pkcs1_encrypt
, mbedtls_rsa_rsaes_pkcs1_v15_encrypt
or mbedtls_rsa_rsaes_oaep_encrypt
to encrypt a short message (typically a symmetric key) is psa_asymmetric_encrypt
.
The key must be a public key (or a key pair) allowing the usage PSA_KEY_USAGE_ENCRYPT
(see “Public-key cryptography policies”).
Use the macro PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE
or PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE
to determine the output buffer size.
The equivalent of mbedtls_pk_decrypt
, mbedtls_rsa_pkcs1_decrypt
, mbedtls_rsa_rsaes_pkcs1_v15_decrypt
or mbedtls_rsa_rsaes_oaep_decrypt
to decrypt a short message (typically a symmetric key) is psa_asymmetric_decrypt
.
The key must be a key pair allowing the usage PSA_KEY_USAGE_DECRYPT
(see “Public-key cryptography policies”).
Use the macro PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE
or PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE
to determine the output buffer size.
The following subsections describe the PSA asymmetric encryption mechanisms that correspond to legacy Mbed TLS mechanisms.
RSA PKCS#1v1.5 encryption
This is the mechanism used by the PK functions and by mbedtls_rsa_pkcs1_{encrypt,decrypt}
unless mbedtls_rsa_set_padding
has been called on the underlying RSA key context.
This is also the mechanism used by mbedtls_rsa_rsaes_pkcs1_v15_{encrypt,decrypt}
.
The PSA algorithm is PSA_ALG_RSA_PKCS1V15_CRYPT
.
Beware that PKCS#1v1.5 decryption is subject to padding oracle attacks. Revealing when psa_asymmetric_decrypt
returns PSA_ERROR_INVALID_PADDING
may allow an adversary to decrypt arbitrary ciphertexts.
RSA RSAES-OAEP
This is the mechanism used by mbedtls_rsa_rsaes_oaep_{encrypt,decrypt}
.
The PSA algorithm is PSA_ALG_RSA_OAEP(hash)
where hash
is a hash algorithm value (PSA_ALG_xxx
, see “Hash mechanism selection”).
As with the PK API, the mask generation is MGF1, the label is empty, and the same hash algorithm is used for MGF1 and to hash the label. The PSA API does not offer a way to choose a different label or a different hash algorithm for the label.
Private-public key consistency
There is no direct equivalent of the functions mbedtls_rsa_check_privkey
, mbedtls_rsa_check_pubkey
,mbedtls_ecp_check_privkey
, mbedtls_ecp_check_pubkey
. The PSA API performs some basic checks when it imports a key, and may perform additional checks before performing an operation if needed, so it will never perform an operation on a key that does not satisfy these checks, but the details of when the check is performed may change between versions of the library.
The legacy API provides functions mbedtls_pk_check_pair
, mbedtls_rsa_check_pub_priv
and mbedtls_ecp_check_pub_priv
, which can be used to check the consistency between a private key and a public key. To perform such a check with the PSA API, you can export the public keys; this works because the PSA representation of public keys is canonical.
- Prepare a key object containing the private key, for example with
psa_import_key
. - Prepare a key object containing the public key, for example with
psa_import_key
. - Export both public keys with
psa_export_public_key
(this is possible regardless of the usage policies on the keys) and compare the output.// Error checking omitted unsigned char pub1[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE]; unsigned char pub2[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE]; size_t length1, length2; psa_export_public_key(key1, pub1, sizeof(pub1), &length1); psa_export_public_key(key2, pub2, sizeof(pub2), &length2); if (length1 == length2 && !memcmp(pub1, pub2, length1)) puts("The keys match"); else puts("The keys do not match");
PK functionality with no PSA equivalent
There is no PSA equivalent of the debug functionality provided by mbedtls_pk_debug
. Use psa_export_key
to export the key if desired.
There is no PSA equivalent to Mbed TLS's custom key type names exposed by mbedtls_pk_get_name
.
Key agreement
The PSA API has a generic interface for key agreement, covering the main use of both ecdh.h
and dhm.h
.
Diffie-Hellman key pair management
The PSA API manipulates keys as such, rather than via an operation context. Thus, to use Diffie-Hellman, you need to create a key object, then perform the key exchange, then destroy the key. There is no equivalent to the types mbedtls_ecdh_context
and mbedtls_dhm_context
.
Here is an overview of the lifecycle of a key object.
- First define the attributes of the key by filling a
psa_key_attributes_t
structure. You need to set the following parameters:- Call
psa_set_key_type
to set the key type to the desiredPSA_KEY_TYPE_xxx
value:PSA_KEY_TYPE_DH_KEY_PAIR(group)
for finite-field Diffie-Hellman (see “Diffie-Hellman mechanism selection”).
PSA_KEY_TYPE_ECC_KEY_PAIR(curve)
for elliptic-curve Diffie-Hellman (see “Elliptic curve mechanism selection”).- Call
psa_set_key_bits
to set the private key size in bits. This is optional withpsa_import_key
, which determines the key size from the length of the key material. - Call
psa_set_key_algorithm
to select the appropriate algorithm: PSA_ALG_ECDH
orPSA_ALG_FFDH
for a raw key agreement.PSA_ALG_KEY_AGREEMENT(ka, kdf)
if the key will be used as part of a key derivation, where:ka
is eitherPSA_ALG_ECDH
orPSA_ALG_FFDH
.kdf
is a key derivation algorithm.
- Call
psa_set_key_usage_flags
to enable at leastPSA_KEY_USAGE_DERIVE
. See “Public-key cryptography policies” for more information.
- Call
- Call one of the key creation functions, passing the attributes defined in the previous step, to get an identifier of type
psa_key_id_t
to the key object.- Use
psa_generate_key
to generate a random key. This is normally the case for a Diffie-Hellman key. - Use
psa_import_key
to directly import key material. - If the key is derived deterministically from other material, use the key derivation interface and create the key with
psa_key_derivation_output_key
.
- Use
- Call the functions in the following sections to perform operations on the key. The same key object can be used in multiple operations.
- To free the resources used by the key object, call
psa_destroy_key
after all operations with that key are finished.
Performing a key agreement
Call psa_export_public_key
to obtain the public key that needs to be sent to the other party.
Use the macros PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE
or PSA_EXPORT_PUBLIC_KEY_MAX_SIZE
to determine a sufficient size for the output buffer.
Call psa_raw_key_agreement
to calculate the shared secret from your private key and the other party's public key.
Use the macros PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE
or PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE
to determine a sufficient size for the output buffer.
Call psa_key_derivation_key_agreement
instead of psa_raw_key_agreement
to use the resulting shared secret as the secret input to a key derivation. See “HKDF” for an example of the key derivation interface.
Translating a legacy key agreement contextless workflow
A typical workflow for ECDH using the legacy API without a context object is:
- Initialize objects:
mbedtls_ecp_group grp
for the curve;mbedtls_mpi our_priv
for our private key;mbedtls_ecp_point our_pub
for our public key;mbedtls_ecp_point their_pub
for their public key (this may be the same variable asour_pub
if the application does not need to hold both at the same time);mbedtls_mpi z
for the shared secret (this may be the same variable asour_priv
when doing ephemeral ECDH).
- Call
mbedtls_ecp_group_load
ongrp
to select the curve. - Call
mbedtls_ecdh_gen_public
ongrp
,our_priv
(output) andour_pub
(output) to generate a key pair and retrieve the corresponding public key. - Send
our_pub
to the peer. Retrieve the peer's public key and import it intotheir_pub
. These two actions may be performed in either order. - Call
mbedtls_ecdh_compute_shared
ongrp
,z
(output),their_pub
andour_priv
. Use the raw shared secretz
, typically, to construct a shared key. - Free
grp
,our_priv
,our_pub
,their_pub
andz
.
The corresponding workflow with the PSA API is as follows:
- Initialize objects:
psa_key_id_t our_key
: a handle to our key pair;psa_key_attributes_t attributes
: key attributes used in steps 2–3;;our_pub
: a buffer of sizePSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, bits)
(wherekey_type
is the value passed topsa_set_key_size
in step 2) orPSA_EXPORT_PUBLIC_KEY_MAX_SIZE
to hold our key.their_pub
: a buffer of the same size, to hold the peer's key. This can be the same asour_pub
if the application does not need to hold both at the same time;shared_secret
: a buffer of sizePSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(key_type, bits)
orPSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE
(if not using a key derivation operation).
- Prepare an attribute structure as described in “Diffie-Hellman key pair management”, in particular selecting the curve with
psa_set_key_type
. - Call
psa_generate_key
onattributes
andour_key
(output) to generate a key pair, thenpsa_export_public_key
onour_key
andour_pub
(output) to obtain our public key. - Send
our_pub
to the peer. Retrieve the peer's public key and import it intotheir_pub
. These two actions may be performed in either order. - Call
psa_raw_key_agreement
onour_key
,their_pub
andshared_secret
(output).
Alternatively, callpsa_key_derivation_key_agreement
to use the shared secret directly in a key derivation operation (see “Performing a key agreement”). - Call
psa_destroy_key
onkey_id
, and free the memory buffers.
Steps 4–6 are only performed once for a "true" ephemeral Diffie-Hellman. They may be repeated multiple times for a "fake ephemeral" Diffie-Hellman where the same private key is used for multiple key exchanges, but it not saved.
Translating a legacy ephemeral key agreement TLS server workflow
The legacy API offers the following workflow for an ephemeral Diffie-Hellman key agreement in a TLS 1.2 server. The PSA version of this workflow can also be used with other protocols, on the side of the party that selects the curve or group and sends its public key first.
- Setup phase:
- Initialize a context of type
mbedtls_ecdh_context
ormbedtls_dhm_context
withmbedtls_ecdh_init
ormbedtls_dhm_init
. - Call
mbedtls_ecdh_setup
ormbedtls_dhm_set_group
to select the curve or group. - Call
mbedtls_ecdh_make_params
ormbedtls_dhm_make_params
to generate our key pair and obtain a TLS ServerKeyExchange message encoding the selected curve/group and our public key.
- Initialize a context of type
- Send the ServerKeyExchange message to the peer.
- Retrieve the peer's public key.
- Call
mbedtls_ecdh_read_public
ormbedtls_dhm_read_public
on the peer's public key, then callmbedtls_ecdh_calc_secret
ormbedtls_dhm_calc_secret
to calculate the shared secret. - Free the context with
mbedtls_ecdh_free
ormbedtls_dhm_free
.
The corresponding workflow with the PSA API is as follows:
- Setup phase:
- Generate an ECDH or DHM key pair with
psa_generate_key
as described in “Diffie-Hellman key pair management”. - Call
psa_export_public_key
to obtain our public key. - Format a ServerKeyExchange message containing the curve/group selection and our public key.
- Generate an ECDH or DHM key pair with
- Send the ServerKeyExchange message to the peer.
- Retrieve the peer's public key.
- Call
psa_raw_key_agreement
onour_key
,their_pub
andshared_secret
(output).
Alternatively, callpsa_key_derivation_key_agreement
to use the shared secret directly in a key derivation operation (see “Performing a key agreement”). - Call
psa_destroy_key
to free the resources associated with our key pair.
Translating a legacy ephemeral key agreement TLS client workflow
The legacy API offers the following workflow for an ephemeral Diffie-Hellman key agreement in a TLS 1.2 client. The PSA version of this workflow can also be used with other protocols, on the side of the party that receives a message indicating both the choice of curve or group, and the peer's public key.
- Upon reception of a TLS ServerKeyExchange message received from the peer, which encodes the selected curve/group and the peer's public key:
- Initialize a context of type
mbedtls_ecdh_context
ormbedtls_dhm_context
withmbedtls_ecdh_init
ormbedtls_dhm_init
. - Call
mbedtls_ecdh_read_params
ormbedtls_dhm_read_params
to input the data from the ServerKeyExchange message.
- Initialize a context of type
- Call
mbedtls_ecdh_make_public
ormbedtls_dh_make_public
to generate our private key and export our public key. - Send our public key to the peer.
- Call
mbedtls_ecdh_calc_secret
ormbedtls_dhm_calc_secret
to calculate the shared secret. - Free the context with
mbedtls_ecdh_free
ormbedtls_dhm_free
.
The corresponding workflow with the PSA API is as follows:
- Upon reception of a TLS ServerKeyExchange message received from the peer, which encodes the selected curve/group and the peer's public key:
- Decode the selected curve/group and use this to determine a PSA key type (
PSA_KEY_TYPE_ECC_KEY_PAIR(curve)
orPSA_KEY_TYPE_DH_KEY_PAIR(group)
), a key size and an algorithm.
- Decode the selected curve/group and use this to determine a PSA key type (
- Generate an ECDH or DHM key pair with
psa_generate_key
as described in “Diffie-Hellman key pair management”. Callpsa_export_public_key
to obtain our public key. - Send our public key to the peer.
- Call
psa_raw_key_agreement
onour_key
,their_pub
andshared_secret
(output).
Alternatively, callpsa_key_derivation_key_agreement
to use the shared secret directly in a key derivation operation (see “Performing a key agreement”). - Call
psa_destroy_key
to free the resources associated with our key pair.
ECDH and DHM metadata functions
You can obtain data and metadata from an ECDH key agreement through the PSA API as follows:
- With either side, accessing the group: call
psa_get_key_attributes
on the key identifier, thenpsa_get_key_type
andpsa_get_key_bits
to obtain metadata about the key. - Accessing our public key: call
psa_export_public_key
on the PSA key identifier. - Accessing our private key: call
psa_export_key
on the key identifier. Note that the key policy must allowPSA_KEY_USAGE_EXPORT
(see “Public-key cryptography policies”). - Accessing the peer's public key: there is no PSA equivalent since the PSA API only uses the peer's public key to immediately calculate the shared secret. If your application needs the peer's public key for some other purpose, store it separately.
The functions mbedtls_dhm_get_bitlen
, mbedtls_dhm_get_len
and mbedtls_dhm_get_value
allow the caller to obtain metadata about the keys used for the key exchange. The PSA equivalents access the key identifier:
mbedtls_dhm_get_bitlen
,mbedtls_dhm_get_len
: callpsa_get_key_attributes
on the PSA key identifier, thenpsa_get_key_bits
.mbedtls_dhm_get_value
forMBEDTLS_DHM_PARAM_X
(our private key): callpsa_export_key
on the key identifier. Note that the key policy must allowPSA_KEY_USAGE_EXPORT
(see “Public-key cryptography policies”).mbedtls_dhm_get_value
forMBEDTLS_DHM_PARAM_GX
(our public key): callpsa_export_public_key
on the PSA key identifier.mbedtls_dhm_get_value
forMBEDTLS_DHM_PARAM_GY
(peer's public key): the there is no PSA equivalent since the PSA API only uses the peer's public key to immediately calculate the shared secret. If your application needs the peer's public key for some other purpose, store it separately.mbedtls_dhm_get_value
forMBEDTLS_DHM_PARAM_K
(shared secret): this is the value calculated bypsa_raw_key_agreement
orpsa_key_derivation_key_agreement
. If you need to use it multiple times (for example to derive multiple values independently), callpsa_raw_key_agreement
and make a copy.mbedtls_dhm_get_value
forMBEDTLS_DHM_PARAM_P
orMBEDTLS_DHM_PARAM_G
(group parameters): there is no PSA API to retrieve these values.
The PSA API for finite-field Diffie-Hellman only supports predefined groups. Therefore there is no equivalent to mbedtls_dhm_parse_dhm
, mbedtls_dhm_parse_dhmfile
, and the MBEDTLS_DHM_xxx_BIN
macros.
Restartable key agreement
Restartable key agreement (enabled by mbedtls_ecdh_enable_restart
) is not yet available through the PSA API. It will be added under the name “interruptible key agreement” in a future version of the library, with an interface that's similar to the interruptible signature interface described in “Restartable ECDSA signature”.
Additional information about Elliptic-curve cryptography
Information about a curve
The legacy API identifies a curve by an MBEDTLS_ECP_DP_xxx
value of type mbedtls_ecp_group_id
. The PSA API identifies a curve by a PSA_ECC_FAMILY_xxx
value and the private value's bit-size. See “Elliptic curve mechanism selection” for the correspondence between the two sets of values.
There is no PSA equivalent of the mbedtls_ecp_group
data structure (and so no equivalent to mbedtls_ecp_group_init
, mbedtls_ecp_group_load
, mbedtls_ecp_group_copy
and mbedtls_ecp_group_free
) or of the mbedtls_ecp_curve_info
data structure (and so no equivalent to mbedtls_ecp_curve_info_from_grp_id
) because they are not needed. All API elements identify the curve directly by its family and size.
The bit-size used by the PSA API is the size of the private key. For most curves, the PSA bit-size, the bit_size
field in mbedtls_ecp_curve_info
, the nbits
field in mbedtls_ecp_group
and the pbits
field in mbedtls_ecp_group
are the same. The following table lists curves for which they are different.
Curve | grp->nbits |
grp->pbits |
curve_info->bit_size |
PSA bit-size |
---|---|---|---|---|
secp224k1 | 225 | 224 | 224 | not supported |
Curve25519 | 253 | 255 | 256 | 255 |
Curve448 | 446 | 448 | 448 | 448 |
There is no exact PSA equivalent of the type mbedtls_ecp_curve_type
and the function mbedtls_ecp_get_type
, but the curve family encodes the same information. PSA_ECC_FAMILY_MONTGOMERY
is the only Montgomery family. All other families supported in Mbed TLS 3.4.0 are short Weierstrass families.
There is no PSA equivalent for the following functionality:
- The
name
field ofmbedtls_ecp_curve_info
, and the functionmbedtls_ecp_curve_info_from_name
. There is no equivalent of Mbed TLS's lookup based on the name used for the curve in TLS specifications. - The
tls_id
field ofmbedtls_ecp_curve_info
, the constantMBEDTLS_ECP_TLS_NAMED_CURVE
, and the functionsmbedtls_ecp_curve_info_from_tls_id
,mbedtls_ecp_tls_read_group
,mbedtls_ecp_tls_read_group_id
andmbedtls_ecp_tls_write_group
. The PSA crypto API does not have this dedicated support for the TLS protocol. - Retrieving the parameters of a curve from the fields of an
mbedtls_ecp_group
structure.
Information about supported curves
The PSA API does not currently have a discovery mechanism for cryptographic mechanisms (although one may be added in the future). Thus there is no equivalent for MBEDTLS_ECP_DP_MAX
and the functions mbedtls_ecp_curve_list
and mbedtls_ecp_grp_id_list
.
The API provides macros that give the maximum supported sizes for various kinds of objects. The following table lists equivalents for MBEDTLS_ECP_MAX_xxx
macros.
Legacy macro | PSA equivalent |
---|---|
MBEDTLS_ECP_MAX_BITS |
PSA_VENDOR_ECC_MAX_CURVE_BITS |
MBEDTLS_ECP_MAX_BYTES |
PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS) |
MBEDTLS_ECP_MAX_PT_LEN |
PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS) |
Restartable ECC
The PSA API supports the equivalent of restartable operations, but only for signatures at the time of writing. See “Restartable ECDSA signature”.
There is no PSA API for elliptic curve arithmetic as such, and therefore no equivalent of mbedtls_ecp_restart_ctx
and functions that operate on it.
There is PSA no equivalent of the MBEDTLS_ECP_OPS_xxx
constants.
ECC functionality with no PSA equivalent
There is no PSA equivalent of mbedtls_ecdsa_can_do
and mbedtls_ecdh_can_do
to query the capabilities of a curve at runtime. Check the documentation of each curve family to see what algorithms it supports.
There is no PSA equivalent to the types mbedtls_ecdsa_context
and mbedtls_ecdsa_restart_ctx
, and to basic ECDSA context manipulation functions including mbedtls_ecdsa_from_keypair
, because they are not needed: the PSA API does not have ECDSA-specific context types.
No curve arithmetic
The PSA API is a cryptography API, not an arithmetic API. As a consequence, there is no PSA equivalent for the ECC arithmetic functionality exposed by ecp.h
:
- Manipulation of point objects and input-output: the type
mbedtls_ecp_point
and functions operating on it (mbedtls_ecp_point_xxx
,mbedtls_ecp_copy
,mbedtls_ecp_{set,is}_zero
,mbedtls_ecp_tls_{read,write}_point
). Note that the PSA export format for public keys corresponds to the uncompressed point format (MBEDTLS_ECP_PF_UNCOMPRESSED
), sopsa_import_key
,psa_export_key
andpsa_export_public_key
are equivalent tombedtls_ecp_point_read_binary
andmbedtls_ecp_point_write_binary
for uncompressed points. The PSA API does not currently support compressed points, but it is likely that such support will be added in the future. - Manipulation of key pairs as such, with a bridge to bignum arithmetic (
mbedtls_ecp_keypair
type,mbedtls_ecp_export
). However, the PSA export format for ECC private keys used bypsa_import_key
,psa_export_key
is the same as the format used bymbedtls_ecp_read_key
andmbedtls_ecp_write_key_ext
. - Elliptic curve arithmetic (
mbedtls_ecp_mul
,mbedtls_ecp_muladd
and their restartable variants).
Additional information about RSA
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.
- 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 ofMBEDTLS_PK_RSA_ALT
). When creating a key, it will be transparent by default; to create an opaque key, callpsa_set_key_lifetime
to set the key's location to the chosen location value for the driver, e.g.psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( PSA_KEY_PERSISTENCE_VOLATILE, MY_RSA_DRIVER_LOCATION));
The PSA subsystem uses its internal random generator both for randomized algorithms and to generate blinding values. As a consequence, none of the API functions take an RNG parameter.
RSA functionality with no PSA equivalent
The PSA API does not provide direct access to the exponentiation primitive as with mbedtls_rsa_public
and mbedtls_rsa_private
. If you need an RSA-based mechanism that is not supported by the PSA API, please submit an issue on GitHub so that we can extend the API to support it.
The PSA API does not support constructing RSA keys progressively from numbers with mbedtls_rsa_import
or mbedtls_rsa_import_raw
followed by mbedtls_rsa_complete
. See “Importing a PK key by wrapping”.
There is no direct equivalent of mbedtls_rsa_export
, mbedtls_rsa_export_raw
and mbedtls_rsa_export_crt
to export some of the numbers in a key. You can export the whole key with psa_export_key
, or with psa_export_public_key
to export the public key from a key pair object. See also “Exporting a public key or a key pair”.
A PSA key object is immutable, so there is no need for an equivalent of mbedtls_rsa_copy
. (There is a function psa_copy_key
, but it is only useful to make a copy of a key with a different policy of ownership; both concepts are out of scope of this document since they have no equivalent in the legacy API.)
LMS signatures
A future version of Mbed TLS will support LMS keys and signatures through the PSA API (psa_generate_key
, psa_export_public_key
, psa_import_key
, psa_sign_hash
, psa_verify_hash
, etc.). However, this is likely to happen after Mbed TLS 4.0, therefore the next major version of Mbed TLS will likely keep the existing lms.h
interface.
PK format support interfaces
The interfaces in base64.h
, asn1.h
, asn1write.h
, oid.h
and pem.h
are intended to support X.509 and key file formats. They have no PSA equivalent since they are not directly about cryptography.
In Mbed TLS 4.0, we are planning to keep the ASN.1 interfaces mostly unchanged. The evolution of Base64, OID and PEM as separate interfaces is still undecided at the time of writing.
EC-JPAKE
The PSA API exposes EC-JPAKE via the algorithm PSA_ALG_JPAKE
and the PAKE API functions. At the time of writing, the PAKE API is still experimental, but it should offer the same functionality as the legacy ecjpake.h
. Please consult the documentation of your version of Mbed TLS for more information.
Please note a few differences between the two APIs: the legacy API is geared towards the use of EC-JPAKE in TLS 1.2, whereas the PSA API is protocol-agnostic.
- The PSA API is finer-grained and offers more flexibility in message ordering. Where the legacy API makes a single function call, the PSA API may require multiple calls.
- The legacy API uses the TLS 1.2 wire format in the input or output format of several functions. In particular, one of the messages embeds the curve identifier in the TLS protocol. The PSA API uses protocol-agnostic formats.
- The legacy API always applies the key derivation specified by TLS 1.2 to the shared secret. With the PSA API, use a key derivation with
PSA_ALG_TLS12_ECJPAKE_TO_PMS
for the same calculation.