From fc0c4ed9a3103e0e6534311923668879fc8e0875 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Sat, 26 Nov 2022 16:20:59 -0500 Subject: Removed openssl, and curl, and added mbedded tls. Almost fully removed curl, needs more testing. Fixed most issues, now trying to cross compile. Fix? Sigh. --- lib/mbedtls-2.27.0/docs/.gitignore | 3 + .../docs/PSACryptoDriverModelSpec.pdf | Bin 0 -> 565092 bytes lib/mbedtls-2.27.0/docs/architecture/Makefile | 26 + .../mbed-crypto-storage-specification.md | 316 ++++++ .../psa-crypto-implementation-structure.md | 73 ++ .../testing/driver-interface-test-strategy.md | 133 +++ .../docs/architecture/testing/invasive-testing.md | 367 +++++++ .../testing/psa-storage-format-testing.md | 103 ++ .../docs/architecture/testing/test-framework.md | 58 ++ .../docs/architecture/tls13-experimental.md | 68 ++ lib/mbedtls-2.27.0/docs/getting_started.md | 894 +++++++++++++++++ lib/mbedtls-2.27.0/docs/proposed/Makefile | 25 + lib/mbedtls-2.27.0/docs/proposed/README | 4 + .../docs/proposed/psa-conditional-inclusion-c.md | 244 +++++ .../docs/proposed/psa-driver-developer-guide.md | 45 + .../docs/proposed/psa-driver-integration-guide.md | 45 + .../docs/proposed/psa-driver-interface.md | 1002 ++++++++++++++++++++ 17 files changed, 3406 insertions(+) create mode 100644 lib/mbedtls-2.27.0/docs/.gitignore create mode 100644 lib/mbedtls-2.27.0/docs/PSACryptoDriverModelSpec.pdf create mode 100644 lib/mbedtls-2.27.0/docs/architecture/Makefile create mode 100644 lib/mbedtls-2.27.0/docs/architecture/mbed-crypto-storage-specification.md create mode 100644 lib/mbedtls-2.27.0/docs/architecture/psa-crypto-implementation-structure.md create mode 100644 lib/mbedtls-2.27.0/docs/architecture/testing/driver-interface-test-strategy.md create mode 100644 lib/mbedtls-2.27.0/docs/architecture/testing/invasive-testing.md create mode 100644 lib/mbedtls-2.27.0/docs/architecture/testing/psa-storage-format-testing.md create mode 100644 lib/mbedtls-2.27.0/docs/architecture/testing/test-framework.md create mode 100644 lib/mbedtls-2.27.0/docs/architecture/tls13-experimental.md create mode 100644 lib/mbedtls-2.27.0/docs/getting_started.md create mode 100644 lib/mbedtls-2.27.0/docs/proposed/Makefile create mode 100644 lib/mbedtls-2.27.0/docs/proposed/README create mode 100644 lib/mbedtls-2.27.0/docs/proposed/psa-conditional-inclusion-c.md create mode 100644 lib/mbedtls-2.27.0/docs/proposed/psa-driver-developer-guide.md create mode 100644 lib/mbedtls-2.27.0/docs/proposed/psa-driver-integration-guide.md create mode 100644 lib/mbedtls-2.27.0/docs/proposed/psa-driver-interface.md (limited to 'lib/mbedtls-2.27.0/docs') diff --git a/lib/mbedtls-2.27.0/docs/.gitignore b/lib/mbedtls-2.27.0/docs/.gitignore new file mode 100644 index 0000000..33ae5ac --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/.gitignore @@ -0,0 +1,3 @@ +*.html +*.pdf +!PSACryptoDriverModelSpec.pdf diff --git a/lib/mbedtls-2.27.0/docs/PSACryptoDriverModelSpec.pdf b/lib/mbedtls-2.27.0/docs/PSACryptoDriverModelSpec.pdf new file mode 100644 index 0000000..cf11380 Binary files /dev/null and b/lib/mbedtls-2.27.0/docs/PSACryptoDriverModelSpec.pdf differ diff --git a/lib/mbedtls-2.27.0/docs/architecture/Makefile b/lib/mbedtls-2.27.0/docs/architecture/Makefile new file mode 100644 index 0000000..d8db2e0 --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/architecture/Makefile @@ -0,0 +1,26 @@ +PANDOC = pandoc + +default: all + +all_markdown = \ + mbed-crypto-storage-specification.md \ + testing/driver-interface-test-strategy.md \ + testing/invasive-testing.md \ + testing/test-framework.md \ + # This line is intentionally left blank + +html: $(all_markdown:.md=.html) +pdf: $(all_markdown:.md=.pdf) +all: html pdf + +.SUFFIXES: +.SUFFIXES: .md .html .pdf + +.md.html: + $(PANDOC) -o $@ $< +.md.pdf: + $(PANDOC) -o $@ $< + +clean: + rm -f *.html *.pdf + rm -f testing/*.html testing/*.pdf diff --git a/lib/mbedtls-2.27.0/docs/architecture/mbed-crypto-storage-specification.md b/lib/mbedtls-2.27.0/docs/architecture/mbed-crypto-storage-specification.md new file mode 100644 index 0000000..914bca3 --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/architecture/mbed-crypto-storage-specification.md @@ -0,0 +1,316 @@ +Mbed Crypto storage specification +================================= + +This document specifies how Mbed Crypto uses storage. + +Mbed Crypto may be upgraded on an existing device with the storage preserved. Therefore: + +1. Any change may break existing installations and may require an upgrade path. +1. This document retains historical information about all past released versions. Do not remove information from this document unless it has always been incorrect or it is about a version that you are sure was never released. + +Mbed Crypto 0.1.0 +----------------- + +Tags: mbedcrypto-0.1.0b, mbedcrypto-0.1.0b2 + +Released in November 2018.
+Integrated in Mbed OS 5.11. + +Supported backends: + +* [PSA ITS](#file-namespace-on-its-for-0.1.0) +* [C stdio](#file-namespace-on-stdio-for-0.1.0) + +Supported features: + +* [Persistent transparent keys](#key-file-format-for-0.1.0) designated by a [slot number](#key-names-for-0.1.0). +* [Nonvolatile random seed](#nonvolatile-random-seed-file-format-for-0.1.0) on ITS only. + +This is a beta release, and we do not promise backward compatibility, with one exception: + +> On Mbed OS, if a device has a nonvolatile random seed file produced with Mbed OS 5.11.x and is upgraded to a later version of Mbed OS, the nonvolatile random seed file is preserved or upgraded. + +We do not make any promises regarding key storage, or regarding the nonvolatile random seed file on other platforms. + +### Key names for 0.1.0 + +Information about each key is stored in a dedicated file whose name is constructed from the key identifier. The way in which the file name is constructed depends on the storage backend. The content of the file is described [below](#key-file-format-for-0.1.0). + +The valid values for a key identifier are the range from 1 to 0xfffeffff. This limitation on the range is not documented in user-facing documentation: according to the user-facing documentation, arbitrary 32-bit values are valid. + +The code uses the following constant in an internal header (note that despite the name, this value is actually one plus the maximum permitted value): + + #define PSA_MAX_PERSISTENT_KEY_IDENTIFIER 0xffff0000 + +There is a shared namespace for all callers. + +### Key file format for 0.1.0 + +All integers are encoded in little-endian order in 8-bit bytes. + +The layout of a key file is: + +* magic (8 bytes): `"PSA\0KEY\0"` +* version (4 bytes): 0 +* type (4 bytes): `psa_key_type_t` value +* policy usage flags (4 bytes): `psa_key_usage_t` value +* policy usage algorithm (4 bytes): `psa_algorithm_t` value +* key material length (4 bytes) +* key material: output of `psa_export_key` +* Any trailing data is rejected on load. + +### Nonvolatile random seed file format for 0.1.0 + +The nonvolatile random seed file contains a seed for the random generator. If present, it is rewritten at each boot as part of the random generator initialization. + +The file format is just the seed as a byte string with no metadata or encoding of any kind. + +### File namespace on ITS for 0.1.0 + +Assumption: ITS provides a 32-bit file identifier namespace. The Crypto service can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace. + +* File 0: unused. +* Files 1 through 0xfffeffff: [content](#key-file-format-for-0.1.0) of the [key whose identifier is the file identifier](#key-names-for-0.1.0). +* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-0.1.0). +* Files 0xffff0000 through 0xffffff51, 0xffffff53 through 0xffffffff: unused. + +### File namespace on stdio for 0.1.0 + +Assumption: C stdio, allowing names containing lowercase letters, digits and underscores, of length up to 23. + +An undocumented build-time configuration value `CRYPTO_STORAGE_FILE_LOCATION` allows storing the key files in a directory other than the current directory. This value is simply prepended to the file name (so it must end with a directory separator to put the keys in a different directory). + +* `CRYPTO_STORAGE_FILE_LOCATION "psa_key_slot_0"`: used as a temporary file. Must be writable. May be overwritten or deleted if present. +* `sprintf(CRYPTO_STORAGE_FILE_LOCATION "psa_key_slot_%lu", key_id)` [content](#key-file-format-for-0.1.0) of the [key whose identifier](#key-names-for-0.1.0) is `key_id`. +* Other files: unused. + +Mbed Crypto 1.0.0 +----------------- + +Tags: mbedcrypto-1.0.0d4, mbedcrypto-1.0.0 + +Released in February 2019.
+Integrated in Mbed OS 5.12. + +Supported integrations: + +* [PSA platform](#file-namespace-on-a-psa-platform-for-1.0.0) +* [library using PSA ITS](#file-namespace-on-its-as-a-library-for-1.0.0) +* [library using C stdio](#file-namespace-on-stdio-for-1.0.0) + +Supported features: + +* [Persistent transparent keys](#key-file-format-for-1.0.0) designated by a [key identifier and owner](#key-names-for-1.0.0). +* [Nonvolatile random seed](#nonvolatile-random-seed-file-format-for-1.0.0) on ITS only. + +Backward compatibility commitments: TBD + +### Key names for 1.0.0 + +Information about each key is stored in a dedicated file designated by the key identifier. In integrations where there is no concept of key owner (in particular, in library integrations), the key identifier is exactly the key identifier as defined in the PSA Cryptography API specification (`psa_key_id_t`). In integrations where there is a concept of key owner (integration into a service for example), the key identifier is made of an owner identifier (its semantics and type are integration specific) and of the key identifier (`psa_key_id_t`) from the key owner point of view. + +The way in which the file name is constructed from the key identifier depends on the storage backend. The content of the file is described [below](#key-file-format-for-1.0.0). + +* Library integration: the key file name is just the key identifier as defined in the PSA crypto specification. This is a 32-bit value. +* PSA service integration: the key file name is `(uint32_t)owner_uid << 32 | key_id` where `key_id` is the key identifier from the owner point of view and `owner_uid` (of type `int32_t`) is the calling partition identifier provided to the server by the partition manager. This is a 64-bit value. + +### Key file format for 1.0.0 + +The layout is identical to [0.1.0](#key-file-format-for-0.1.0) so far. However note that the encoding of key types, algorithms and key material has changed, therefore the storage format is not compatible (despite using the same value in the version field so far). + +### Nonvolatile random seed file format for 1.0.0 + +[Identical to 0.1.0](#nonvolatile-random-seed-file-format-for-0.1.0). + +### File namespace on a PSA platform for 1.0.0 + +Assumption: ITS provides a 64-bit file identifier namespace. The Crypto service can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace. + +Assumption: the owner identifier is a nonzero value of type `int32_t`. + +* Files 0 through 0xffffff51, 0xffffff53 through 0xffffffff: unused, reserved for internal use of the crypto library or crypto service. +* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-0.1.0). +* Files 0x100000000 through 0xffffffffffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0). The upper 32 bits determine the owner. + +### File namespace on ITS as a library for 1.0.0 + +Assumption: ITS provides a 64-bit file identifier namespace. The entity using the crypto library can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace. + +This is a library integration, so there is no owner. The key file identifier is identical to the key identifier. + +* File 0: unused. +* Files 1 through 0xfffeffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0). +* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-1.0.0). +* Files 0xffff0000 through 0xffffff51, 0xffffff53 through 0xffffffff, 0x100000000 through 0xffffffffffffffff: unused. + +### File namespace on stdio for 1.0.0 + +This is a library integration, so there is no owner. The key file identifier is identical to the key identifier. + +[Identical to 0.1.0](#file-namespace-on-stdio-for-0.1.0). + +### Upgrade from 0.1.0 to 1.0.0. + +* Delete files 1 through 0xfffeffff, which contain keys in a format that is no longer supported. + +### Suggested changes to make before 1.0.0 + +The library integration and the PSA platform integration use different sets of file names. This is annoyingly non-uniform. For example, if we want to store non-key files, we have room in different ranges (0 through 0xffffffff on a PSA platform, 0xffff0000 through 0xffffffffffffffff in a library integration). + +It would simplify things to always have a 32-bit owner, with a nonzero value, and thus reserve the range 0–0xffffffff for internal library use. + +Mbed Crypto 1.1.0 +----------------- + +Tags: mbedcrypto-1.1.0 + +Released in early June 2019.
+Integrated in Mbed OS 5.13. + +Identical to [1.0.0](#mbed-crypto-1.0.0) except for some changes in the key file format. + +### Key file format for 1.1.0 + +The key file format is identical to [1.0.0](#key-file-format-for-1.0.0), except for the following changes: + +* A new policy field, marked as [NEW:1.1.0] below. +* The encoding of key types, algorithms and key material has changed, therefore the storage format is not compatible (despite using the same value in the version field so far). + +A self-contained description of the file layout follows. + +All integers are encoded in little-endian order in 8-bit bytes. + +The layout of a key file is: + +* magic (8 bytes): `"PSA\0KEY\0"` +* version (4 bytes): 0 +* type (4 bytes): `psa_key_type_t` value +* policy usage flags (4 bytes): `psa_key_usage_t` value +* policy usage algorithm (4 bytes): `psa_algorithm_t` value +* policy enrollment algorithm (4 bytes): `psa_algorithm_t` value [NEW:1.1.0] +* key material length (4 bytes) +* key material: output of `psa_export_key` +* Any trailing data is rejected on load. + +Mbed Crypto TBD +--------------- + +Tags: TBD + +Released in TBD 2019.
+Integrated in Mbed OS TBD. + +### Changes introduced in TBD + +* The layout of a key file now has a lifetime field before the type field. +* Key files can store references to keys in a secure element. In such key files, the key material contains the slot number. + +### File namespace on a PSA platform on TBD + +Assumption: ITS provides a 64-bit file identifier namespace. The Crypto service can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace. + +Assumption: the owner identifier is a nonzero value of type `int32_t`. + +* Files 0 through 0xfffeffff: unused. +* Files 0xffff0000 through 0xffffffff: reserved for internal use of the crypto library or crypto service. See [non-key files](#non-key-files-on-tbd). +* Files 0x100000000 through 0xffffffffffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0). The upper 32 bits determine the owner. + +### File namespace on ITS as a library on TBD + +Assumption: ITS provides a 64-bit file identifier namespace. The entity using the crypto library can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace. + +This is a library integration, so there is no owner. The key file identifier is identical to the key identifier. + +* File 0: unused. +* Files 1 through 0xfffeffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0). +* Files 0xffff0000 through 0xffffffff: reserved for internal use of the crypto library or crypto service. See [non-key files](#non-key-files-on-tbd). +* Files 0x100000000 through 0xffffffffffffffff: unused. + +### Non-key files on TBD + +File identifiers in the range 0xffff0000 through 0xffffffff are reserved for internal use in Mbed Crypto. + +* Files 0xfffffe02 through 0xfffffeff (`PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + lifetime`): secure element driver storage. The content of the file is the secure element driver's persistent data. +* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-1.0.0). +* File 0xffffff54 (`PSA_CRYPTO_ITS_TRANSACTION_UID`): [transaction file](#transaction-file-format-for-tbd). +* Other files are unused and reserved for future use. + +### Key file format for TBD + +All integers are encoded in little-endian order in 8-bit bytes except where otherwise indicated. + +The layout of a key file is: + +* magic (8 bytes): `"PSA\0KEY\0"`. +* version (4 bytes): 0. +* lifetime (4 bytes): `psa_key_lifetime_t` value. +* type (4 bytes): `psa_key_type_t` value. +* policy usage flags (4 bytes): `psa_key_usage_t` value. +* policy usage algorithm (4 bytes): `psa_algorithm_t` value. +* policy enrollment algorithm (4 bytes): `psa_algorithm_t` value. +* key material length (4 bytes). +* key material: + * For a transparent key: output of `psa_export_key`. + * For an opaque key (unified driver interface): driver-specific opaque key blob. + * For an opaque key (key in a secure element): slot number (8 bytes), in platform endianness. +* Any trailing data is rejected on load. + +### Transaction file format for TBD + +The transaction file contains data about an ongoing action that cannot be completed atomically. It exists only if there is an ongoing transaction. + +All integers are encoded in platform endianness. + +All currently existing transactions concern a key in a secure element. + +The layout of a transaction file is: + +* type (2 bytes): the [transaction type](#transaction-types-on-tbd). +* unused (2 bytes) +* lifetime (4 bytes): `psa_key_lifetime_t` value that corresponds to a key in a secure element. +* slot number (8 bytes): `psa_key_slot_number_t` value. This is the unique designation of the key for the secure element driver. +* key identifier (4 bytes in a library integration, 8 bytes on a PSA platform): the internal representation of the key identifier. On a PSA platform, this encodes the key owner in the same way as [in file identifiers for key files](#file-namespace-on-a-psa-platform-on-tbd)). + +#### Transaction types on TBD + +* 0x0001: key creation. The following locations may or may not contain data about the key that is being created: + * The slot in the secure element designated by the slot number. + * The file containing the key metadata designated by the key identifier. + * The driver persistent data. +* 0x0002: key destruction. The following locations may or may not still contain data about the key that is being destroyed: + * The slot in the secure element designated by the slot number. + * The file containing the key metadata designated by the key identifier. + * The driver persistent data. + +Mbed Crypto TBD +--------------- + +Tags: TBD + +Released in TBD 2020.
+Integrated in Mbed OS TBD. + +### Changes introduced in TBD + +* The type field has been split into a type and a bits field of 2 bytes each. + +### Key file format for TBD + +All integers are encoded in little-endian order in 8-bit bytes except where otherwise indicated. + +The layout of a key file is: + +* magic (8 bytes): `"PSA\0KEY\0"`. +* version (4 bytes): 0. +* lifetime (4 bytes): `psa_key_lifetime_t` value. +* type (2 bytes): `psa_key_type_t` value. +* bits (2 bytes): `psa_key_bits_t` value. +* policy usage flags (4 bytes): `psa_key_usage_t` value. +* policy usage algorithm (4 bytes): `psa_algorithm_t` value. +* policy enrollment algorithm (4 bytes): `psa_algorithm_t` value. +* key material length (4 bytes). +* key material: + * For a transparent key: output of `psa_export_key`. + * For an opaque key (unified driver interface): driver-specific opaque key blob. + * For an opaque key (key in a secure element): slot number (8 bytes), in platform endianness. +* Any trailing data is rejected on load. diff --git a/lib/mbedtls-2.27.0/docs/architecture/psa-crypto-implementation-structure.md b/lib/mbedtls-2.27.0/docs/architecture/psa-crypto-implementation-structure.md new file mode 100644 index 0000000..cd4d427 --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/architecture/psa-crypto-implementation-structure.md @@ -0,0 +1,73 @@ +PSA Cryptograpy API implementation and PSA driver interface +=========================================================== + +## Introduction + +The [PSA Cryptography API specification](https://armmbed.github.io/mbed-crypto/psa/#application-programming-interface) defines an interface to cryptographic operations for which the Mbed TLS library provides a reference implementation. The PSA Cryptography API specification is complemented by the PSA driver interface specification which defines an interface for cryptoprocessor drivers. + +This document describes the high level organization of the Mbed TLS PSA Cryptography API implementation which is tightly related to the PSA driver interface. + +## High level organization of the Mbed TLS PSA Cryptography API implementation +In one sentence, the Mbed TLS PSA Cryptography API implementation is made of a core and PSA drivers as defined in the PSA driver interface. The key point is that software cryptographic operations are organized as PSA drivers: they interact with the core through the PSA driver interface. + +### Rationale + +* Addressing software and hardware cryptographic implementations through the same C interface reduces the core code size and its call graph complexity. The core and its dispatching to software and hardware implementations are consequently easier to test and validate. +* The organization of the software cryptographic implementations in drivers promotes modularization of those implementations. +* As hardware capabilities, software cryptographic functionalities can be described by a JSON driver description file as defined in the PSA driver interface. +* Along with JSON driver description files, the PSA driver specification defines the deliverables for a driver to be included into the Mbed TLS PSA Cryptography implementation. This provides a natural framework to integrate third party or alternative software implementations of cryptographic operations. + +## The Mbed TLS PSA Cryptography API implementation core + +The core implements all the APIs as defined in the PSA Cryptography API specification but does not perform on its own any cryptographic operation. The core relies on PSA drivers to actually +perform the cryptographic operations. The core is responsible for: + +* the key store. +* checking PSA API arguments and translating them into valid arguments for the necessary calls to the PSA driver interface. +* dispatching the cryptographic operations to the appropriate PSA drivers. + +The sketch of an Mbed TLS PSA cryptographic API implementation is thus: +```C +psa_status_t psa_api( ... ) +{ + psa_status_t status; + + /* Pre driver interface call processing: validation of arguments, building + * of arguments for the call to the driver interface, ... */ + + ... + + /* Call to the driver interface */ + status = psa_driver_wrapper_( ... ); + if( status != PSA_SUCCESS ) + return( status ); + + /* Post driver interface call processing: validation of the values returned + * by the driver, finalization of the values to return to the caller, + * clean-up in case of error ... */ +} +``` +The code of most PSA APIs is expected to match precisely the above layout. However, it is likely that the code structure of some APIs will be more complicated with several calls to the driver interface, mainly to encompass a larger variety of hardware designs. For example, to encompass hardware accelerators that are capable of verifying a MAC and those that are only capable of computing a MAC, the psa_mac_verify() API could call first psa_driver_wrapper_mac_verify() and then fallback to psa_driver_wrapper_mac_compute(). + +The implementations of `psa_driver_wrapper_` functions are generated by the build system based on the JSON driver description files of the various PSA drivers making up the Mbed TLS PSA Cryptography API implementation. The implementations are generated in a psa_crypto_driver_wrappers.c C file and the function prototypes declared in a psa_crypto_driver_wrappers.h header file. + +The psa_driver_wrapper_() functions dispatch cryptographic operations to accelerator drivers, secure element drivers as well as to the software implementations of cryptographic operations. + +Note that the implementation allows to build the library with only a C compiler by shipping a generated file corresponding to a pure software implementation. The driver entry points and their code in this generated file are guarded by pre-processor directives based on PSA_WANT_xyz macros (see [Conditional inclusion of cryptographic mechanism through the PSA API in Mbed TLS](psa-conditional-inclusion-c.html). That way, it is possible to compile and include in the library only the desired cryptographic operations. + +### Key creation + +Key creation implementation in Mbed TLS PSA core is articulated around three internal functions: psa_start_key_creation(), psa_finish_key_creation() and psa_fail_key_creation(). Implementations of key creation PSA APIs, namely psa_import_key(), psa_generate_key(), psa_key_derivation_output_key() and psa_copy_key() go by the following sequence: + 1. Check the input parameters. + 2. Call psa_start_key_creation() that allocates a key slot, prepares it with the specified key attributes, and in case of a volatile key assign it a volatile key identifier. + 3. Generate or copy the key material into the key slot. This entails the allocation of the buffer to store the key material. + 4. Call psa_finish_key_creation() that mostly saves persistent keys into persistent storage. + +In case of any error occurring at step 3 or 4, psa_fail_key_creation() is called. It wipes and cleans the slot especially the key material: reset to zero of the RAM memory that contained the key material, free the allocated buffer. + + +## Mbed TLS PSA Cryptography API implementation drivers + +A driver of the Mbed TLS PSA Cryptography API implementation (Mbed TLS PSA driver in the following) is a driver in the sense that it is compliant with the PSA driver interface specification. But it is not an actual driver that drives some hardware. It implements cryptographic operations purely in software. + +An Mbed TLS PSA driver C file is named psa_crypto_.c and its associated header file psa_crypto_.h. The functions implementing a driver entry point as defined in the PSA driver interface specification are named as mbedtls_psa__(). As an example, the psa_crypto_rsa.c and psa_crypto_rsa.h are the files containing the Mbed TLS PSA driver implementing RSA cryptographic operations. This RSA driver implements among other entry points the "import_key" entry point. The function implementing this entry point is named mbedtls_psa_rsa_import_key(). diff --git a/lib/mbedtls-2.27.0/docs/architecture/testing/driver-interface-test-strategy.md b/lib/mbedtls-2.27.0/docs/architecture/testing/driver-interface-test-strategy.md new file mode 100644 index 0000000..086fc1a --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/architecture/testing/driver-interface-test-strategy.md @@ -0,0 +1,133 @@ +# Mbed Crypto driver interface test strategy + +This document describes the test strategy for the driver interfaces in Mbed Crypto. Mbed Crypto has interfaces for secure element drivers, accelerator drivers and entropy drivers. This document is about testing Mbed Crypto itself; testing drivers is out of scope. + +The driver interfaces are standardized through PSA Cryptography functional specifications. + +## Secure element driver interface testing + +### Secure element driver interfaces + +#### Opaque driver interface + +The [unified driver interface](../../proposed/psa-driver-interface.md) supports both transparent drivers (for accelerators) and opaque drivers (for secure elements). + +Drivers exposing this interface need to be registered at compile time by declaring their JSON description file. + +#### Dynamic secure element driver interface + +The dynamic secure element driver interface (SE interface for short) is defined by [`psa/crypto_se_driver.h`](../../../include/psa/crypto_se_driver.h). This is an interface between Mbed Crypto and one or more third-party drivers. + +The SE interface consists of one function provided by Mbed Crypto (`psa_register_se_driver`) and many functions that drivers must implement. To make a driver usable by Mbed Crypto, the initialization code must call `psa_register_se_driver` with a structure that describes the driver. The structure mostly contains function pointers, pointing to the driver's methods. All calls to a driver function are triggered by a call to a PSA crypto API function. + +### SE driver interface unit tests + +This section describes unit tests that must be implemented to validate the secure element driver interface. Note that a test case may cover multiple requirements; for example a “good case” test can validate that the proper function is called, that it receives the expected inputs and that it produces the expected outputs. + +Many SE driver interface unit tests could be covered by running the existing API tests with a key in a secure element. + +#### SE driver registration + +This applies to dynamic drivers only. + +* Test `psa_register_se_driver` with valid and with invalid arguments. +* Make at least one failing call to `psa_register_se_driver` followed by a successful call. +* Make at least one test that successfully registers the maximum number of drivers and fails to register one more. + +#### Dispatch to SE driver + +For each API function that can lead to a driver call (more precisely, for each driver method call site, but this is practically equivalent): + +* Make at least one test with a key in a secure element that checks that the driver method is called. A few API functions involve multiple driver methods; these should validate that all the expected driver methods are called. +* Make at least one test with a key that is not in a secure element that checks that the driver method is not called. +* Make at least one test with a key in a secure element with a driver that does not have the requisite method (i.e. the method pointer is `NULL`) but has the substructure containing that method, and check that the return value is `PSA_ERROR_NOT_SUPPORTED`. +* Make at least one test with a key in a secure element with a driver that does not have the substructure containing that method (i.e. the pointer to the substructure is `NULL`), and check that the return value is `PSA_ERROR_NOT_SUPPORTED`. +* At least one test should register multiple drivers with a key in each driver and check that the expected driver is called. This does not need to be done for all operations (use a white-box approach to determine if operations may use different code paths to choose the driver). +* At least one test should register the same driver structure with multiple lifetime values and check that the driver receives the expected lifetime value. + +Some methods only make sense as a group (for example a driver that provides the MAC methods must provide all or none). In those cases, test with all of them null and none of them null. + +#### SE driver inputs + +For each API function that can lead to a driver call (more precisely, for each driver method call site, but this is practically equivalent): + +* Wherever the specification guarantees parameters that satisfy certain preconditions, check these preconditions whenever practical. +* If the API function can take parameters that are invalid and must not reach the driver, call the API function with such parameters and verify that the driver method is not called. +* Check that the expected inputs reach the driver. This may be implicit in a test that checks the outputs if the only realistic way to obtain the correct outputs is to start from the expected inputs (as is often the case for cryptographic material, but not for metadata). + +#### SE driver outputs + +For each API function that leads to a driver call, call it with parameters that cause a driver to be invoked and check how Mbed Crypto handles the outputs. + +* Correct outputs. +* Incorrect outputs such as an invalid output length. +* Expected errors (e.g. `PSA_ERROR_INVALID_SIGNATURE` from a signature verification method). +* Unexpected errors. At least test that if the driver returns `PSA_ERROR_GENERIC_ERROR`, this is propagated correctly. + +Key creation functions invoke multiple methods and need more complex error handling: + +* Check the consequence of errors detected at each stage (slot number allocation or validation, key creation method, storage accesses). +* Check that the storage ends up in the expected state. At least make sure that no intermediate file remains after a failure. + +#### Persistence of SE keys + +The following tests must be performed at least one for each key creation method (import, generate, ...). + +* Test that keys in a secure element survive `psa_close_key(); psa_open_key()`. +* Test that keys in a secure element survive `mbedtls_psa_crypto_free(); psa_crypto_init()`. +* Test that the driver's persistent data survives `mbedtls_psa_crypto_free(); psa_crypto_init()`. +* Test that `psa_destroy_key()` does not leave any trace of the key. + +#### Resilience for SE drivers + +Creating or removing a key in a secure element involves multiple storage modifications (M1, ..., Mn). If the operation is interrupted by a reset at any point, it must be either rolled back or completed. + +* For each potential interruption point (before M1, between M1 and M2, ..., after Mn), call `mbedtls_psa_crypto_free(); psa_crypto_init()` at that point and check that this either rolls back or completes the operation that was started. +* This must be done for each key creation method and for key destruction. +* This must be done for each possible flow, including error cases (e.g. a key creation that fails midway due to `OUT_OF_MEMORY`). +* The recovery during `psa_crypto_init` can itself be interrupted. Test those interruptions too. +* Two things need to be tested: the key that is being created or destroyed, and the driver's persistent storage. +* Check both that the storage has the expected content (this can be done by e.g. using a key that is supposed to be present) and does not have any unexpected content (for keys, this can be done by checking that `psa_open_key` fails with `PSA_ERRROR_DOES_NOT_EXIST`). + +This requires instrumenting the storage implementation, either to force it to fail at each point or to record successive storage states and replay each of them. Each `psa_its_xxx` function call is assumed to be atomic. + +### SE driver system tests + +#### Real-world use case + +We must have at least one driver that is close to real-world conditions: + +* With its own source tree. +* Running on actual hardware. +* Run the full driver validation test suite (which does not yet exist). +* Run at least one test application (e.g. the Mbed OS TLS example). + +This requirement shall be fulfilled by the [Microchip ATECC508A driver](https://github.com/ARMmbed/mbed-os-atecc608a/). + +#### Complete driver + +We should have at least one driver that covers the whole interface: + +* With its own source tree. +* Implementing all the methods. +* Run the full driver validation test suite (which does not yet exist). + +A PKCS#11 driver would be a good candidate. It would be useful as part of our product offering. + +## Transparent driver interface testing + +The [unified driver interface](../../proposed/psa-driver-interface.md) defines interfaces for accelerators. + +### Test requirements + +#### Requirements for transparent driver testing + +Every cryptographic mechanism for which a transparent driver interface exists (key creation, cryptographic operations, …) must be exercised in at least one build. The test must verify that the driver code is called. + +#### Requirements for fallback + +The driver interface includes a fallback mechanism so that a driver can reject a request at runtime and let another driver handle the request. For each entry point, there must be at least three test runs with two or more drivers available with driver A configured to fall back to driver B, with one run where A returns `PSA_SUCCESS`, one where A returns `PSA_ERROR_NOT_SUPPORTED` and B is invoked, and one where A returns a different error and B is not invoked. + +## Entropy and randomness interface testing + +TODO diff --git a/lib/mbedtls-2.27.0/docs/architecture/testing/invasive-testing.md b/lib/mbedtls-2.27.0/docs/architecture/testing/invasive-testing.md new file mode 100644 index 0000000..de611a5 --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/architecture/testing/invasive-testing.md @@ -0,0 +1,367 @@ +# Mbed TLS invasive testing strategy + +## Introduction + +In Mbed TLS, we use black-box testing as much as possible: test the documented behavior of the product, in a realistic environment. However this is not always sufficient. + +The goal of this document is to identify areas where black-box testing is insufficient and to propose solutions. + +This is a test strategy document, not a test plan. A description of exactly what is tested is out of scope. + +This document is structured as follows: + +* [“Rules”](#rules) gives general rules and is written for brevity. +* [“Requirements”](#requirements) explores the reasons why invasive testing is needed and how it should be done. +* [“Possible approaches”](#possible-approaches) discusses some general methods for non-black-box testing. +* [“Solutions”](#solutions) explains how we currently solve, or intend to solve, specific problems. + +### TLS + +This document currently focuses on data structure manipulation and storage, which is what the crypto/keystore and X.509 parts of the library are about. More work is needed to fully take TLS into account. + +## Rules + +Always follow these rules unless you have a good reason not to. If you deviate, document the rationale somewhere. + +See the section [“Possible approaches”](#possible-approaches) for a rationale. + +### Interface design for testing + +Do not add test-specific interfaces if there's a practical way of doing it another way. All public interfaces should be useful in at least some configurations. Features with a significant impact on the code size or attack surface should have a compile-time guard. + +### Reliance on internal details + +In unit tests and in test programs, it's ok to include header files from `library/`. Do not define non-public interfaces in public headers (`include/mbedtls` has `*_internal.h` headers for legacy reasons, but this approach is deprecated). In contrast, sample programs must not include header files from `library/`. + +Sometimes it makes sense to have unit tests on functions that aren't part of the public API. Declare such functions in `library/*.h` and include the corresponding header in the test code. If the function should be `static` for optimization but can't be `static` for testing, declare it as `MBEDTLS_STATIC_TESTABLE`, and make the tests that use it depend on `MBEDTLS_TEST_HOOKS` (see [“rules for compile-time options”](#rules-for-compile-time-options)). + +If test code or test data depends on internal details of the library and not just on its documented behavior, add a comment in the code that explains the dependency. For example: + +> ``` +> /* This test file is specific to the ITS implementation in PSA Crypto +> * on top of stdio. It expects to know what the stdio name of a file is +> * based on its keystore name. +> */ +> ``` + +> ``` +> # This test assumes that PSA_MAX_KEY_BITS (currently 65536-8 bits = 8191 bytes +> # and not expected to be raised any time soon) is less than the maximum +> # output from HKDF-SHA512 (255*64 = 16320 bytes). +> ``` + +### Rules for compile-time options + +If the most practical way to test something is to add code to the product that is only useful for testing, do so, but obey the following rules. For more information, see the [rationale](#guidelines-for-compile-time-options). + +* **Only use test-specific code when necessary.** Anything that can be tested through the documented API must be tested through the documented API. +* **Test-specific code must be guarded by `#if defined(MBEDTLS_TEST_HOOKS)`**. Do not create fine-grained guards for test-specific code. +* **Do not use `MBEDTLS_TEST_HOOKS` for security checks or assertions.** Security checks belong in the product. +* **Merely defining `MBEDTLS_TEST_HOOKS` must not change the behavior**. It may define extra functions. It may add fields to structures, but if so, make it very clear that these fields have no impact on non-test-specific fields. +* **Where tests must be able to change the behavior, do it by function substitution.** See [“rules for function substitution”](#rules-for-function-substitution) for more details. + +#### Rules for function substitution + +This section explains how to replace a library function `mbedtls_foo()` by alternative code for test purposes. That is, library code calls `mbedtls_foo()`, and there is a mechanism to arrange for these calls to invoke different code. + +Often `mbedtls_foo` is a macro which is defined to be a system function (like `mbedtls_calloc` or `mbedtls_fopen`), which we replace to mock or wrap the system function. This is useful to simulate I/O failure, for example. Note that if the macro can be replaced at compile time to support alternative platforms, the test code should be compatible with this compile-time configuration so that it works on these alternative platforms as well. + +Sometimes the substitutable function is a `static inline` function that does nothing (not a macro, to avoid accidentally skipping side effects in its parameters), to provide a hook for test code; such functions should have a name that starts with the prefix `mbedtls_test_hook_`. In such cases, the function should generally not modify its parameters, so any pointer argument should be const. The function should return void. + +With `MBEDTLS_TEST_HOOKS` set, `mbedtls_foo` is a global variable of function pointer type. This global variable is initialized to the system function, or to a function that does nothing. The global variable is defined in a header in the `library` directory such as `psa_crypto_invasive.h`. This is similar to the platform function configuration mechanism with `MBEDTLS_PLATFORM_xxx_ALT`. + +In unit test code that needs to modify the internal behavior: + +* The test function (or the whole test file) must depend on `MBEDTLS_TEST_HOOKS`. +* At the beginning of the test function, set the global function pointers to the desired value. +* In the test function's cleanup code, restore the global function pointers to their default value. + +## Requirements + +### General goals + +We need to balance the following goals, which are sometimes contradictory. + +* Coverage: we need to test behaviors which are not easy to trigger by using the API or which cannot be triggered deterministically, for example I/O failures. +* Correctness: we want to test the actual product, not a modified version, since conclusions drawn from a test of a modified product may not apply to the real product. +* Effacement: the product should not include features that are solely present for test purposes, since these increase the attack surface and the code size. +* Portability: tests should work on every platform. Skipping tests on certain platforms may hide errors that are only apparent on such platforms. +* Maintainability: tests should only enforce the documented behavior of the product, to avoid extra work when the product's internal or implementation-specific behavior changes. We should also not give the impression that whatever the tests check is guaranteed behavior of the product which cannot change in future versions. + +Where those goals conflict, we should at least mitigate the goals that cannot be fulfilled, and document the architectural choices and their rationale. + +### Problem areas + +#### Allocation + +Resource allocation can fail, but rarely does so in a typical test environment. How does the product cope if some allocations fail? + +Resources include: + +* Memory. +* Files in storage (PSA API only — in the Mbed TLS API, black-box unit tests are sufficient). +* Key slots (PSA API only). +* Key slots in a secure element (PSA SE HAL). +* Communication handles (PSA crypto service only). + +#### Storage + +Storage can fail, either due to hardware errors or to active attacks on trusted storage. How does the code cope if some storage accesses fail? + +We also need to test resilience: if the system is reset during an operation, does it restart in a correct state? + +#### Cleanup + +When code should clean up resources, how do we know that they have truly been cleaned up? + +* Zeroization of confidential data after use. +* Freeing memory. +* Freeing key slots. +* Freeing key slots in a secure element. +* Deleting files in storage (PSA API only). + +#### Internal data + +Sometimes it is useful to peek or poke internal data. + +* Check consistency of internal data (e.g. output of key generation). +* Check the format of files (which matters so that the product can still read old files after an upgrade). +* Inject faults and test corruption checks inside the product. + +## Possible approaches + +Key to requirement tables: + +* ++ requirement is fully met +* \+ requirement is mostly met +* ~ requirement is partially met but there are limitations +* ! requirement is somewhat problematic +* !! requirement is very problematic + +### Fine-grained public interfaces + +We can include all the features we want to test in the public interface. Then the tests can be truly black-box. The limitation of this approach is that this requires adding a lot of interfaces that are not useful in production. These interfaces have costs: they increase the code size, the attack surface, and the testing burden (exponentially, because we need to test all these interfaces in combination). + +As a rule, we do not add public interfaces solely for testing purposes. We only add public interfaces if they are also useful in production, at least sometimes. For example, the main purpose of `mbedtls_psa_crypto_free` is to clean up all resources in tests, but this is also useful in production in some applications that only want to use PSA Crypto during part of their lifetime. + +Mbed TLS traditionally has very fine-grained public interfaces, with many platform functions that can be substituted (`MBEDTLS_PLATFORM_xxx` macros). PSA Crypto has more opacity and less platform substitution macros. + +| Requirement | Analysis | +| ----------- | -------- | +| Coverage | ~ Many useful tests are not reasonably achievable | +| Correctness | ++ Ideal | +| Effacement | !! Requires adding many otherwise-useless interfaces | +| Portability | ++ Ideal; the additional interfaces may be useful for portability beyond testing | +| Maintainability | !! Combinatorial explosion on the testing burden | +| | ! Public interfaces must remain for backward compatibility even if the test architecture changes | + +### Fine-grained undocumented interfaces + +We can include all the features we want to test in undocumented interfaces. Undocumented interfaces are described in public headers for the sake of the C compiler, but are described as “do not use” in comments (or not described at all) and are not included in Doxygen-rendered documentation. This mitigates some of the downsides of [fine-grained public interfaces](#fine-grained-public-interfaces), but not all. In particular, the extra interfaces do increase the code size, the attack surface and the test surface. + +Mbed TLS traditionally has a few internal interfaces, mostly intended for cross-module abstraction leakage rather than for testing. For the PSA API, we favor [internal interfaces](#internal-interfaces). + +| Requirement | Analysis | +| ----------- | -------- | +| Coverage | ~ Many useful tests are not reasonably achievable | +| Correctness | ++ Ideal | +| Effacement | !! Requires adding many otherwise-useless interfaces | +| Portability | ++ Ideal; the additional interfaces may be useful for portability beyond testing | +| Maintainability | ! Combinatorial explosion on the testing burden | + +### Internal interfaces + +We can write tests that call internal functions that are not exposed in the public interfaces. This is nice when it works, because it lets us test the unchanged product without compromising the design of the public interface. + +A limitation is that these interfaces must exist in the first place. If they don't, this has mostly the same downside as public interfaces: the extra interfaces increase the code size and the attack surface for no direct benefit to the product. + +Another limitation is that internal interfaces need to be used correctly. We may accidentally rely on internal details in the tests that are not necessarily always true (for example that are platform-specific). We may accidentally use these internal interfaces in ways that don't correspond to the actual product. + +This approach is mostly portable since it only relies on C interfaces. A limitation is that the test-only interfaces must not be hidden at link time (but link-time hiding is not something we currently do). Another limitation is that this approach does not work for users who patch the library by replacing some modules; this is a secondary concern since we do not officially offer this as a feature. + +| Requirement | Analysis | +| ----------- | -------- | +| Coverage | ~ Many useful tests require additional internal interfaces | +| Correctness | + Does not require a product change | +| | ~ The tests may call internal functions in a way that does not reflect actual usage inside the product | +| Effacement | ++ Fine as long as the internal interfaces aren't added solely for test purposes | +| Portability | + Fine as long as we control how the tests are linked | +| | ~ Doesn't work if the users rewrite an internal module | +| Maintainability | + Tests interfaces that are documented; dependencies in the tests are easily noticed when changing these interfaces | + +### Static analysis + +If we guarantee certain properties through static analysis, we don't need to test them. This puts some constraints on the properties: + +* We need to have confidence in the specification (but we can gain this confidence by evaluating the specification on test data). +* This does not work for platform-dependent properties unless we have a formal model of the platform. + +| Requirement | Analysis | +| ----------- | -------- | +| Coverage | ~ Good for platform-independent properties, if we can guarantee them statically | +| Correctness | + Good as long as we have confidence in the specification | +| Effacement | ++ Zero impact on the code | +| Portability | ++ Zero runtime burden | +| Maintainability | ~ Static analysis is hard, but it's also helpful | + +### Compile-time options + +If there's code that we want to have in the product for testing, but not in production, we can add a compile-time option to enable it. This is very powerful and usually easy to use, but comes with a major downside: we aren't testing the same code anymore. + +| Requirement | Analysis | +| ----------- | -------- | +| Coverage | ++ Most things can be tested that way | +| Correctness | ! Difficult to ensure that what we test is what we run | +| Effacement | ++ No impact on the product when built normally or on the documentation, if done right | +| | ! Risk of getting “no impact” wrong | +| Portability | ++ It's just C code so it works everywhere | +| | ~ Doesn't work if the users rewrite an internal module | +| Maintainability | + Test interfaces impact the product source code, but at least they're clearly marked as such in the code | + +#### Guidelines for compile-time options + +* **Minimize the number of compile-time options.**
+ Either we're testing or we're not. Fine-grained options for testing would require more test builds, especially if combinatorics enters the play. +* **Merely enabling the compile-time option should not change the behavior.**
+ When building in test mode, the code should have exactly the same behavior. Changing the behavior should require some action at runtime (calling a function or changing a variable). +* **Minimize the impact on code**.
+ We should not have test-specific conditional compilation littered through the code, as that makes the code hard to read. + +### Runtime instrumentation + +Some properties can be tested through runtime instrumentation: have the compiler or a similar tool inject something into the binary. + +* Sanitizers check for certain bad usage patterns (ASan, MSan, UBSan, Valgrind). +* We can inject external libraries at link time. This can be a way to make system functions fail. + +| Requirement | Analysis | +| ----------- | -------- | +| Coverage | ! Limited scope | +| Correctness | + Instrumentation generally does not affect the program's functional behavior | +| Effacement | ++ Zero impact on the code | +| Portability | ~ Depends on the method | +| Maintainability | ~ Depending on the instrumentation, this may require additional builds and scripts | +| | + Many properties come for free, but some require effort (e.g. the test code itself must be leak-free to avoid false positives in a leak detector) | + +### Debugger-based testing + +If we want to do something in a test that the product isn't capable of doing, we can use a debugger to read or modify the memory, or hook into the code at arbitrary points. + +This is a very powerful approach, but it comes with limitations: + +* The debugger may introduce behavior changes (e.g. timing). If we modify data structures in memory, we may do so in a way that the code doesn't expect. +* Due to compiler optimizations, the memory may not have the layout that we expect. +* Writing reliable debugger scripts is hard. We need to have confidence that we're testing what we mean to test, even in the face of compiler optimizations. Languages such as gdb make it hard to automate even relatively simple things such as finding the place(s) in the binary corresponding to some place in the source code. +* Debugger scripts are very much non-portable. + +| Requirement | Analysis | +| ----------- | -------- | +| Coverage | ++ The sky is the limit | +| Correctness | ++ The code is unmodified, and tested as compiled (so we even detect compiler-induced bugs) | +| | ! Compiler optimizations may hinder | +| | ~ Modifying the execution may introduce divergence | +| Effacement | ++ Zero impact on the code | +| Portability | !! Not all environments have a debugger, and even if they do, we'd need completely different scripts for every debugger | +| Maintainability | ! Writing reliable debugger scripts is hard | +| | !! Very tight coupling with the details of the source code and even with the compiler | + +## Solutions + +This section lists some strategies that are currently used for invasive testing, or planned to be used. This list is not intended to be exhaustive. + +### Memory management + +#### Zeroization testing + +Goal: test that `mbedtls_platform_zeroize` does wipe the memory buffer. + +Solution ([debugger](#debugger-based-testing)): implemented in `tests/scripts/test_zeroize.gdb`. + +Rationale: this cannot be tested by adding C code, because the danger is that the compiler optimizes the zeroization away, and any C code that observes the zeroization would cause the compiler not to optimize it away. + +#### Memory cleanup + +Goal: test the absence of memory leaks. + +Solution ([instrumentation](#runtime-instrumentation)): run tests with ASan. (We also use Valgrind, but it's slower than ASan, so we favor ASan.) + +Since we run many test jobs with a memory leak detector, each test function or test program must clean up after itself. Use the cleanup code (after the `exit` label in test functions) to free any memory that the function may have allocated. + +#### Robustness against memory allocation failure + +Solution: TODO. We don't test this at all at this point. + +#### PSA key store memory cleanup + +Goal: test the absence of resource leaks in the PSA key store code, in particular that `psa_close_key` and `psa_destroy_key` work correctly. + +Solution ([internal interface](#internal-interfaces)): in most tests involving PSA functions, the cleanup code explicitly calls `PSA_DONE()` instead of `mbedtls_psa_crypto_free()`. `PSA_DONE` fails the test if the key store in memory is not empty. + +Note there must also be tests that call `mbedtls_psa_crypto_free` with keys still open, to verify that it does close all keys. + +`PSA_DONE` is a macro defined in `psa_crypto_helpers.h` which uses `mbedtls_psa_get_stats()` to get information about the keystore content before calling `mbedtls_psa_crypto_free()`. This feature is mostly but not exclusively useful for testing, and may be moved under `MBEDTLS_TEST_HOOKS`. + +### PSA storage + +#### PSA storage cleanup on success + +Goal: test that no stray files are left over in the key store after a test that succeeded. + +Solution: TODO. Currently the various test suites do it differently. + +#### PSA storage cleanup on failure + +Goal: ensure that no stray files are left over in the key store even if a test has failed (as that could cause other tests to fail). + +Solution: TODO. Currently the various test suites do it differently. + +#### PSA storage resilience + +Goal: test the resilience of PSA storage against power failures. + +Solution: TODO. + +See the [secure element driver interface test strategy](driver-interface-test-strategy.html) for more information. + +#### Corrupted storage + +Goal: test the robustness against corrupted storage. + +Solution ([internal interface](#internal-interfaces)): call `psa_its` functions to modify the storage. + +#### Storage read failure + +Goal: test the robustness against read errors. + +Solution: TODO + +#### Storage write failure + +Goal: test the robustness against write errors (`STORAGE_FAILURE` or `INSUFFICIENT_STORAGE`). + +Solution: TODO + +#### Storage format stability + +Goal: test that the storage format does not change between versions (or if it does, an upgrade path must be provided). + +Solution ([internal interface](#internal-interfaces)): call internal functions to inspect the content of the file. + +Note that the storage format is defined not only by the general layout, but also by the numerical values of encodings for key types and other metadata. For numerical values, there is a risk that we would accidentally modify a single value or a few values, so the tests should be exhaustive. This probably requires some compile-time analysis (perhaps the automation for `psa_constant_names` can be used here). TODO + +### Other fault injection + +#### PSA crypto init failure + +Goal: test the failure of `psa_crypto_init`. + +Solution ([compile-time option](#compile-time-options)): replace entropy initialization functions by functions that can fail. This is the only failure point for `psa_crypto_init` that is present in all builds. + +When we implement the PSA entropy driver interface, this should be reworked to use the entropy driver interface. + +#### PSA crypto data corruption + +The PSA crypto subsystem has a few checks to detect corrupted data in memory. We currently don't have a way to exercise those checks. + +Solution: TODO. To corrupt a multipart operation structure, we can do it by looking inside the structure content, but only when running without isolation. To corrupt the key store, we would need to add a function to the library or to use a debugger. + diff --git a/lib/mbedtls-2.27.0/docs/architecture/testing/psa-storage-format-testing.md b/lib/mbedtls-2.27.0/docs/architecture/testing/psa-storage-format-testing.md new file mode 100644 index 0000000..71bf968 --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/architecture/testing/psa-storage-format-testing.md @@ -0,0 +1,103 @@ +# Mbed TLS PSA keystore format stability testing strategy + +## Introduction + +The PSA crypto subsystem includes a persistent key store. It is possible to create a persistent key and read it back later. This must work even if Mbed TLS has been upgraded in the meantime (except for deliberate breaks in the backward compatibility of the storage). + +The goal of this document is to define a test strategy for the key store that not only validates that it's possible to load a key that was saved with the version of Mbed TLS under test, but also that it's possible to load a key that was saved with previous versions of Mbed TLS. + +Interoperability is not a goal: PSA crypto implementations are not intended to have compatible storage formats. Downgrading is not required to work. + +## General approach + +### Limitations of a direct approach + +The goal of storage format stability testing is: as a user of Mbed TLS, I want to store a key under version V and read it back under version W, with W ≥ V. + +Doing the testing this way would be difficult because we'd need to have version V of Mbed TLS available when testing version W. + +An alternative, semi-direct approach consists of generating test data under version V, and reading it back under version W. Done naively, this would require keeping a large amount of test data (full test coverage multiplied by the number of versions that we want to preserve backward compatibility with). + +### Save-and-compare approach + +Importing and saving a key is deterministic. Therefore we can ensure the stability of the storage format by creating test cases under a version V of Mbed TLS, where the test case parameters include both the parameters to pass to key creation and the expected state of the storage after the key is created. The test case creates a key as indicated by the parameters, then compares the actual state of the storage with the expected state. In addition, the test case also loads the key and checks that it has the expected data and metadata. + +If the test passes with version V, this means that the test data is consistent with what the implementation does. When the test later runs under version W ≥ V, it creates and reads back a storage state which is known to be identical to the state that V would have produced. Thus, this approach validates that W can read storage states created by V. + +Use a similar approach for files other than keys where possible and relevant. + +### Keeping up with storage format evolution + +Test cases should normally not be removed from the code base: if something has worked before, it should keep working in future versions, so we should keep testing it. + +If the way certain keys are stored changes, and we don't deliberately decide to stop supporting old keys (which should only be done by retiring a version of the storage format), then we should keep the corresponding test cases in load-only mode: create a file with the expected content, load it and check the data that it contains. + +## Storage architecture overview + +The PSA subsystem provides storage on top of the PSA trusted storage interface. The state of the storage is a mapping from file identifer (a 64-bit number) to file content (a byte array). These files include: + +* [Key files](#key-storage) (files containing one key's metadata and, except for some secure element keys, key material). +* The [random generator injected seed or state file](#random-generator-state) (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`). +* [Storage transaction file](#storage-transaction-resumption). +* [Driver state files](#driver-state-files). + +For a more detailed description, refer to the [Mbed Crypto storage specification](../mbed-crypto-storage-specification.md). + +In addition, Mbed TLS includes an implementation of the PSA trusted storage interface on top of C stdio. This document addresses the test strategy for [PSA ITS over file](#psa-its-over-file) in a separate section below. + +## Key storage testing + +This section describes the desired test cases for keys created with the current storage format version. When the storage format changes, if backward compatibility is desired, old test data should be kept as described under [“Keeping up with storage format evolution”](#keeping-up-with-storage-format-evolution). + +### Keystore layout + +Objective: test that the key file name corresponds to the key identifier. + +Method: Create a key with a given identifier (using `psa_import_key`) and verify that a file with the expected name is created, and no other. Repeat for different identifiers. + +### General key format + +Objective: test the format of the key file: which field goes where and how big it is. + +Method: Create a key with certain metadata with `psa_import_key`. Read the file content and validate that it has the expected layout, deduced from the storage specification. Repeat with different metadata. Ensure that there are test cases covering all fields. + +### Enumeration of test cases for keys + +Objective: ensure that the coverage is sufficient to have assurance that all keys are stored correctly. This requires a sufficient selection of key types, sizes, policies, etc. + +In particular, the tests must validate that each `PSA_xxx` constant that is stored in a key is covered by at least once test case: + +* Usage flags: `PSA_KEY_USAGE_xxx`. +* Algorithms in policies: `PSA_ALG_xxx`. +* Key types: `PSA_KEY_TYPE_xxx`, `PSA_ECC_FAMILY_xxx`, `PSA_DH_FAMILY_xxx`. + +Method: Each test case creates a key with `psa_import_key`, purges it from memory, then reads it back and exercises it. Generate test cases automatically based on an enumeration of available constants and some knowledge of what attributes (sizes, algorithms, …) and content to use for keys of a certain type. Note that the generated test cases will be checked into the repository (generating test cases at runtime would not allow us to test the stability of the format, only that a given version is internally consistent). + +### Testing with alternative lifetime values + +Objective: have test coverage for lifetimes other than the default persistent lifetime (`PSA_KEY_LIFETIME_PERSISTENT`). + +Method: + +* For alternative locations: have tests conditional on the presence of a driver for that location. +* For alternative persistence levels: TODO + +## Random generator state + +TODO + +## Driver state files + +Not yet implemented. + +TODO + +## Storage transaction resumption + +Only relevant for secure element support. Not yet fully implemented. + +TODO + +## PSA ITS over file + +TODO diff --git a/lib/mbedtls-2.27.0/docs/architecture/testing/test-framework.md b/lib/mbedtls-2.27.0/docs/architecture/testing/test-framework.md new file mode 100644 index 0000000..c4178fa --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/architecture/testing/test-framework.md @@ -0,0 +1,58 @@ +# Mbed TLS test framework + +This document is an overview of the Mbed TLS test framework and test tools. + +This document is incomplete. You can help by expanding it. + +## Unit tests + +See + +### Unit test descriptions + +Each test case has a description which succinctly describes for a human audience what the test does. The first non-comment line of each paragraph in a `.data` file is the test description. The following rules and guidelines apply: + +* Test descriptions may not contain semicolons, line breaks and other control characters, or non-ASCII characters.
+ Rationale: keep the tools that process test descriptions (`generate_test_code.py`, [outcome file](#outcome-file) tools) simple. +* Test descriptions must be unique within a `.data` file. If you can't think of a better description, the convention is to append `#1`, `#2`, etc.
+ Rationale: make it easy to relate a failure log to the test data. Avoid confusion between cases in the [outcome file](#outcome-file). +* Test descriptions should be a maximum of **66 characters**.
+ Rationale: 66 characters is what our various tools assume (leaving room for 14 more characters on an 80-column line). Longer descriptions may be truncated or may break a visual alignment.
+ We have a lot of test cases with longer descriptions, but they should be avoided. At least please make sure that the first 66 characters describe the test uniquely. +* Make the description descriptive. “foo: x=2, y=4” is more descriptive than “foo #2”. “foo: 0**Note:** To generate a random key, use `psa_generate_key()` instead of `psa_generate_random()`. + +This example shows how to generate ten bytes of random data by calling `psa_generate_random()`: +```C + psa_status_t status; + uint8_t random[10] = { 0 }; + + printf("Generate random...\t"); + fflush(stdout); + + /* Initialize PSA Crypto */ + status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + printf("Failed to initialize PSA Crypto\n"); + return; + } + + status = psa_generate_random(random, sizeof(random)); + if (status != PSA_SUCCESS) { + printf("Failed to generate a random value\n"); + return; + } + + printf("Generated random data\n"); + + /* Clean up */ + mbedtls_psa_crypto_free(); +``` + +### Deriving a new key from an existing key + +Mbed Crypto provides a key derivation API that lets you derive new keys from +existing ones. The key derivation API has functions to take inputs, including +other keys and data, and functions to generate outputs, such as new keys or +other data. + +You must first initialize and set up a key derivation context, +provided with a key and, optionally, other data. Then, use the key derivation context to either read derived data to a buffer or send derived data directly to a key slot. + +See the documentation for the particular algorithm (such as HKDF or the TLS1.2 PRF) for +information about which inputs to pass when, and when you can obtain which outputs. + +**Prerequisites to working with the key derivation APIs:** +* Initialize the library with a successful call to `psa_crypto_init()`. +* Use a key with the appropriate attributes set: + * Usage flags set for key derivation (`PSA_KEY_USAGE_DERIVE`) + * Key type set to `PSA_KEY_TYPE_DERIVE`. + * Algorithm set to a key derivation algorithm + (for example, `PSA_ALG_HKDF(PSA_ALG_SHA_256)`). + +**To derive a new AES-CTR 128-bit encryption key into a given key slot using HKDF +with a given key, salt and info:** + +1. Set up the key derivation context using the `psa_key_derivation_setup()` +function, specifying the derivation algorithm `PSA_ALG_HKDF(PSA_ALG_SHA_256)`. +1. Provide an optional salt with `psa_key_derivation_input_bytes()`. +1. Provide info with `psa_key_derivation_input_bytes()`. +1. Provide a secret with `psa_key_derivation_input_key()`, referencing a key that + can be used for key derivation. +1. Set the key attributes desired for the new derived key. We'll set + the `PSA_KEY_USAGE_ENCRYPT` usage flag and the `PSA_ALG_CTR` algorithm for this + example. +1. Derive the key by calling `psa_key_derivation_output_key()`. +1. Clean up the key derivation context. + +At this point, the derived key slot holds a new 128-bit AES-CTR encryption key +derived from the key, salt and info provided: +```C + psa_status_t status; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + static const unsigned char key[] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b }; + static const unsigned char salt[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; + static const unsigned char info[] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf8, 0xf9 }; + psa_algorithm_t alg = PSA_ALG_HKDF(PSA_ALG_SHA_256); + psa_key_derivation_operation_t operation = + PSA_KEY_DERIVATION_OPERATION_INIT; + size_t derived_bits = 128; + size_t capacity = PSA_BITS_TO_BYTES(derived_bits); + psa_key_id_t base_key; + psa_key_id_t derived_key; + + printf("Derive a key (HKDF)...\t"); + fflush(stdout); + + /* Initialize PSA Crypto */ + status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + printf("Failed to initialize PSA Crypto\n"); + return; + } + + /* Import a key for use in key derivation. If such a key has already been + * generated or imported, you can skip this part. */ + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); + psa_set_key_algorithm(&attributes, alg); + psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE); + status = psa_import_key(&attributes, key, sizeof(key), &base_key); + if (status != PSA_SUCCESS) { + printf("Failed to import a key\n"); + return; + } + psa_reset_key_attributes(&attributes); + + /* Derive a key */ + status = psa_key_derivation_setup(&operation, alg); + if (status != PSA_SUCCESS) { + printf("Failed to begin key derivation\n"); + return; + } + status = psa_key_derivation_set_capacity(&operation, capacity); + if (status != PSA_SUCCESS) { + printf("Failed to set capacity\n"); + return; + } + status = psa_key_derivation_input_bytes(&operation, + PSA_KEY_DERIVATION_INPUT_SALT, + salt, sizeof(salt)); + if (status != PSA_SUCCESS) { + printf("Failed to input salt (extract)\n"); + return; + } + status = psa_key_derivation_input_key(&operation, + PSA_KEY_DERIVATION_INPUT_SECRET, + base_key); + if (status != PSA_SUCCESS) { + printf("Failed to input key (extract)\n"); + return; + } + status = psa_key_derivation_input_bytes(&operation, + PSA_KEY_DERIVATION_INPUT_INFO, + info, sizeof(info)); + if (status != PSA_SUCCESS) { + printf("Failed to input info (expand)\n"); + return; + } + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_CTR); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 128); + status = psa_key_derivation_output_key(&attributes, &operation, + &derived_key); + if (status != PSA_SUCCESS) { + printf("Failed to derive key\n"); + return; + } + psa_reset_key_attributes(&attributes); + + printf("Derived key\n"); + + /* Clean up key derivation operation */ + psa_key_derivation_abort(&operation); + + /* Destroy the keys */ + psa_destroy_key(derived_key); + psa_destroy_key(base_key); + + mbedtls_psa_crypto_free(); +``` + +### Authenticating and encrypting or decrypting a message + +Mbed Crypto provides a simple way to authenticate and encrypt with associated data (AEAD), supporting the `PSA_ALG_CCM` algorithm. + +**Prerequisites to working with the AEAD cipher APIs:** +* Initialize the library with a successful call to `psa_crypto_init()`. +* The key attributes for the key used for derivation must have the `PSA_KEY_USAGE_ENCRYPT` or `PSA_KEY_USAGE_DECRYPT` usage flags. + +This example shows how to authenticate and encrypt a message: +```C + psa_status_t status; + static const uint8_t key[] = { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF }; + static const uint8_t nonce[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B }; + static const uint8_t additional_data[] = { + 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25, + 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 }; + static const uint8_t input_data[] = { + 0xB9, 0x6B, 0x49, 0xE2, 0x1D, 0x62, 0x17, 0x41, + 0x63, 0x28, 0x75, 0xDB, 0x7F, 0x6C, 0x92, 0x43, + 0xD2, 0xD7, 0xC2 }; + uint8_t *output_data = NULL; + size_t output_size = 0; + size_t output_length = 0; + size_t tag_length = 16; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key; + + printf("Authenticate encrypt...\t"); + fflush(stdout); + + /* Initialize PSA Crypto */ + status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + printf("Failed to initialize PSA Crypto\n"); + return; + } + + output_size = sizeof(input_data) + tag_length; + output_data = (uint8_t *)malloc(output_size); + if (!output_data) { + printf("Out of memory\n"); + return; + } + + /* Import a key */ + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_CCM); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 128); + status = psa_import_key(&attributes, key, sizeof(key), &key); + psa_reset_key_attributes(&attributes); + + /* Authenticate and encrypt */ + status = psa_aead_encrypt(key, PSA_ALG_CCM, + nonce, sizeof(nonce), + additional_data, sizeof(additional_data), + input_data, sizeof(input_data), + output_data, output_size, + &output_length); + if (status != PSA_SUCCESS) { + printf("Failed to authenticate and encrypt\n"); + return; + } + + printf("Authenticated and encrypted\n"); + + /* Clean up */ + free(output_data); + + /* Destroy the key */ + psa_destroy_key(key); + + mbedtls_psa_crypto_free(); +``` + +This example shows how to authenticate and decrypt a message: + +```C + psa_status_t status; + static const uint8_t key_data[] = { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF }; + static const uint8_t nonce[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B }; + static const uint8_t additional_data[] = { + 0xEC, 0x46, 0xBB, 0x63, 0xB0, 0x25, + 0x20, 0xC3, 0x3C, 0x49, 0xFD, 0x70 }; + static const uint8_t input_data[] = { + 0x20, 0x30, 0xE0, 0x36, 0xED, 0x09, 0xA0, 0x45, 0xAF, 0x3C, 0xBA, 0xEE, + 0x0F, 0xC8, 0x48, 0xAF, 0xCD, 0x89, 0x54, 0xF4, 0xF6, 0x3F, 0x28, 0x9A, + 0xA1, 0xDD, 0xB2, 0xB8, 0x09, 0xCD, 0x7C, 0xE1, 0x46, 0xE9, 0x98 }; + uint8_t *output_data = NULL; + size_t output_size = 0; + size_t output_length = 0; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key; + + printf("Authenticate decrypt...\t"); + fflush(stdout); + + /* Initialize PSA Crypto */ + status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + printf("Failed to initialize PSA Crypto\n"); + return; + } + + output_size = sizeof(input_data); + output_data = (uint8_t *)malloc(output_size); + if (!output_data) { + printf("Out of memory\n"); + return; + } + + /* Import a key */ + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_CCM); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 128); + status = psa_import_key(&attributes, key_data, sizeof(key_data), &key); + if (status != PSA_SUCCESS) { + printf("Failed to import a key\n"); + return; + } + psa_reset_key_attributes(&attributes); + + /* Authenticate and decrypt */ + status = psa_aead_decrypt(key, PSA_ALG_CCM, + nonce, sizeof(nonce), + additional_data, sizeof(additional_data), + input_data, sizeof(input_data), + output_data, output_size, + &output_length); + if (status != PSA_SUCCESS) { + printf("Failed to authenticate and decrypt %ld\n", status); + return; + } + + printf("Authenticated and decrypted\n"); + + /* Clean up */ + free(output_data); + + /* Destroy the key */ + psa_destroy_key(key); + + mbedtls_psa_crypto_free(); +``` + +### Generating and exporting keys + +Mbed Crypto provides a simple way to generate a key or key pair. + +**Prerequisites to using key generation and export APIs:** +* Initialize the library with a successful call to `psa_crypto_init()`. + +**To generate an ECDSA key:** +1. Set the desired key attributes for key generation by calling + `psa_set_key_algorithm()` with the chosen ECDSA algorithm (such as + `PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)`). You only want to export the public key, not the key pair (or private key); therefore, do not set `PSA_KEY_USAGE_EXPORT`. +1. Generate a key by calling `psa_generate_key()`. +1. Export the generated public key by calling `psa_export_public_key()`: +```C + enum { + key_bits = 256, + }; + psa_status_t status; + size_t exported_length = 0; + static uint8_t exported[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits)]; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key; + + printf("Generate a key pair...\t"); + fflush(stdout); + + /* Initialize PSA Crypto */ + status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + printf("Failed to initialize PSA Crypto\n"); + return; + } + + /* Generate a key */ + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH); + psa_set_key_algorithm(&attributes, + PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, key_bits); + status = psa_generate_key(&attributes, &key); + if (status != PSA_SUCCESS) { + printf("Failed to generate key\n"); + return; + } + psa_reset_key_attributes(&attributes); + + status = psa_export_public_key(key, exported, sizeof(exported), + &exported_length); + if (status != PSA_SUCCESS) { + printf("Failed to export public key %ld\n", status); + return; + } + + printf("Exported a public key\n"); + + /* Destroy the key */ + psa_destroy_key(key); + + mbedtls_psa_crypto_free(); +``` + +### More about the PSA Crypto API + +For more information about the PSA Crypto API, please see the [PSA Cryptography API Specification](https://armmbed.github.io/mbed-crypto/html/index.html). diff --git a/lib/mbedtls-2.27.0/docs/proposed/Makefile b/lib/mbedtls-2.27.0/docs/proposed/Makefile new file mode 100644 index 0000000..1c31464 --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/proposed/Makefile @@ -0,0 +1,25 @@ +PANDOC = pandoc + +default: all + +all_markdown = \ + psa-conditional-inclusion-c.md \ + psa-driver-developer-guide.md \ + psa-driver-integration-guide.md \ + psa-driver-interface.md \ + # This line is intentionally left blank + +html: $(all_markdown:.md=.html) +pdf: $(all_markdown:.md=.pdf) +all: html pdf + +.SUFFIXES: +.SUFFIXES: .md .html .pdf + +.md.html: + $(PANDOC) -o $@ $< +.md.pdf: + $(PANDOC) -o $@ $< + +clean: + rm -f *.html *.pdf diff --git a/lib/mbedtls-2.27.0/docs/proposed/README b/lib/mbedtls-2.27.0/docs/proposed/README new file mode 100644 index 0000000..09eae9a --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/proposed/README @@ -0,0 +1,4 @@ +The documents in this directory are proposed specifications for Mbed +TLS features. They are not implemented yet, or only partially +implemented. Please follow activity on the `development` branch of +Mbed TLS if you are interested in these features. diff --git a/lib/mbedtls-2.27.0/docs/proposed/psa-conditional-inclusion-c.md b/lib/mbedtls-2.27.0/docs/proposed/psa-conditional-inclusion-c.md new file mode 100644 index 0000000..2ddba7f --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/proposed/psa-conditional-inclusion-c.md @@ -0,0 +1,244 @@ +Conditional inclusion of cryptographic mechanism through the PSA API in Mbed TLS +================================================================================ + +This document is a proposed interface for deciding at build time which cryptographic mechanisms to include in the PSA Cryptography interface. + +This is currently a proposal for Mbed TLS. It is not currently on track for standardization in PSA. + +## Introduction + +### Purpose of this specification + +The [PSA Cryptography API specification](https://armmbed.github.io/mbed-crypto/psa/#application-programming-interface) specifies the interface between a PSA Cryptography implementation and an application. The interface defines a number of categories of cryptographic algorithms (hashes, MAC, signatures, etc.). In each category, a typical implementation offers many algorithms (e.g. for signatures: RSA-PKCS#1v1.5, RSA-PSS, ECDSA). When building the implementation for a specific use case, it is often desirable to include only a subset of the available cryptographic mechanisms, primarily in order to reduce the code footprint of the compiled system. + +The present document proposes a way for an application using the PSA cryptography interface to declare which mechanisms it requires. + +### Conditional inclusion of legacy cryptography modules + +Mbed TLS offers a way to select which cryptographic mechanisms are included in a build through its configuration file (`config.h`). This mechanism is based on two main sets of symbols: `MBEDTLS_xxx_C` controls the availability of the mechanism to the application, and `MBEDTLS_xxx_ALT` controls the availability of an alternative implementation, so the software implementation is only included if `MBEDTLS_xxx_C` is defined but not `MBEDTLS_xxx_ALT`. + +### PSA evolution + +In the PSA cryptography interface, the **core** (built-in implementations of cryptographic mechanisms) can be augmented with drivers. **Transparent drivers** replace the built-in implementation of a cryptographic mechanism (or, with **fallback**, the built-in implementation is tried if the driver only has partial support for the mechanism). **Opaque drivers** implement cryptographic mechanisms on keys which are stored in a separate domain such as a secure element, for which the core only does key management and dispatch using wrapped key blobs or key identifiers. + +The current model is difficult to adapt to the PSA interface for several reasons. The `MBEDTLS_xxx_ALT` symbols are somewhat inconsistent, and in particular do not work well for asymmetric cryptography. For example, many parts of the ECC code have no `MBEDTLS_xxx_ALT` symbol, so a platform with ECC acceleration that can perform all ECDSA and ECDH operations in the accelerator would still embark the `bignum` module and large parts of the `ecp_curves`, `ecp` and `ecdsa` modules. Also the availability of a transparent driver for a mechanism does not translate directly to `MBEDTLS_xxx` symbols. + +### Requirements + +[Req.interface] The application can declare which cryptographic mechanisms it needs. + +[Req.inclusion] If the application does not require a mechanism, a suitably configured Mbed TLS build must not include it. The granularity of mechanisms must work for typical use cases and has [acceptable limitations](#acceptable-limitations). + +[Req.drivers] If a PSA driver is available in the build, a suitably configured Mbed TLS build must not include the corresponding software code (unless a software fallback is needed). + +[Req.c] The configuration mechanism consists of C preprocessor definitions, and the build does not require tools other than a C compiler. This is necessary to allow building an application and Mbed TLS in development environments that do not allow third-party tools. + +[Req.adaptability] The implementation of the mechanism must be adaptable with future evolution of the PSA cryptography specifications and Mbed TLS. Therefore the interface must remain sufficiently simple and abstract. + +### Acceptable limitations + +[Limitation.matrix] If a mechanism is defined by a combination of algorithms and key types, for example a block cipher mode (CBC, CTR, CFB, …) and a block permutation (AES, CAMELLIA, ARIA, …), there is no requirement to include only specific combinations. + +[Limitation.direction] For mechanisms that have multiple directions (for example encrypt/decrypt, sign/verify), there is no requirement to include only one direction. + +[Limitation.size] There is no requirement to include only support for certain key sizes. + +[Limitation.multipart] Where there are multiple ways to perform an operation, for example single-part and multi-part, there is no mechanism to select only one or a subset of the possible ways. + +## Interface + +### PSA Crypto configuration file + +The PSA Crypto configuration file `psa/crypto_config.h` defines a series of symbols of the form `PSA_WANT_xxx` where `xxx` describes the feature that the symbol enables. The symbols are documented in the section [“PSA Crypto configuration symbols”](#psa-crypto-configuration-symbols) below. + +The symbol `MBEDTLS_PSA_CRYPTO_CONFIG` in `mbedtls/config.h` determines whether `psa/crypto_config.h` is used. + +* If `MBEDTLS_PSA_CRYPTO_CONFIG` is unset, which is the default at least in Mbed TLS 2.x versions, things are as they are today: the PSA subsystem includes generic code unconditionally, and includes support for specific mechanisms conditionally based on the existing `MBEDTLS_xxx_` symbols. +* If `MBEDTLS_PSA_CRYPTO_CONFIG` is set, the necessary software implementations of cryptographic algorithms are included based on both the content of the PSA Crypto configuration file and the Mbed TLS configuration file. For example, the code in `aes.c` is enabled if either `mbedtls/config.h` contains `MBEDTLS_AES_C` or `psa/crypto_config.h` contains `PSA_WANT_KEY_TYPE_AES`. + +### PSA Crypto configuration symbols + +#### Configuration symbol syntax + +A PSA Crypto configuration symbol is a C preprocessor symbol whose name starts with `PSA_WANT_`. + +* If the symbol is not defined, the corresponding feature is not included. +* If the symbol is defined to a preprocessor expression with the value `1`, the corresponding feature is included. +* If the symbol is defined with a different value, the behavior is currently undefined and reserved for future use. + +#### Configuration symbol usage + +The presence of a symbol `PSA_WANT_xxx` in the Mbed TLS configuration determines whether a feature is available through the PSA API. These symbols should be used in any place that requires conditional compilation based on the availability of a cryptographic mechanism through the PSA API, including: + +* In Mbed TLS test code. +* In Mbed TLS library code using `MBEDTLS_USE_PSA_CRYPTO`, for example in TLS to determine which cipher suites to enable. +* In application code that provides additional features based on cryptographic capabilities, for example additional key parsing and formatting functions, or cipher suite availability for network protocols. + +#### Configuration symbol semantics + +If a feature is not requested for inclusion in the PSA Crypto configuration file, it may still be included in the build, either because the feature has been requested in some other way, or because the library does not support the exclusion of this feature. Mbed TLS should make a best effort to support the exclusion of all features, but in some cases this may be judged too much effort for too little benefit. + +#### Configuration symbols for key types + +For each constant or constructor macro of the form `PSA_KEY_TYPE_xxx`, the symbol **`PSA_WANT_KEY_TYPE_xxx`** indicates that support for this key type is desired. + +For asymmetric cryptography, `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR` determines whether private-key operations are desired, and `PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY` determines whether public-key operations are desired. `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR` implicitly enables `PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY`: there is no way to only include private-key operations (which typically saves little code). + +#### Configuration symbols for elliptic curves + +For elliptic curve key types, only the specified curves are included. To include a curve, include a symbol of the form **`PSA_WANT_ECC_family_size`**. For example: `PSA_WANT_ECC_SECP_R1_256` for secp256r1, `PSA_WANT_ECC_MONTGOMERY_255` for Curve25519. It is an error to require an ECC key type but no curve, and Mbed TLS will reject this at compile time. + +Rationale: this is a deviation of the general principle that `PSA_ECC_FAMILY_xxx` would have a corresponding symbol `PSA_WANT_ECC_FAMILY_xxx`. This deviation is justified by the fact that it is very common to wish to include only certain curves in a family, and that can lead to a significant gain in code size. + +#### Configuration symbols for Diffie-Hellman groups + +There are no configuration symbols for Diffie-Hellman groups (`PSA_DH_GROUP_xxx`). + +Rationale: Finite-field Diffie-Hellman code is usually not specialized for any particular group, so reducing the number of available groups at compile time only saves a little code space. Constrained implementations tend to omit FFDH anyway, so the small code size gain is not important. + +#### Configuration symbols for algorithms + +For each constant or constructor macro of the form `PSA_ALG_xxx`, the symbol **`PSA_WANT_ALG_xxx`** indicates that support for this algorithm is desired. + +For parametrized algorithms, the `PSA_WANT_ALG_xxx` symbol indicates whether the base mechanism is supported. Parameters must themselves be included through their own `PSA_WANT_ALG_xxx` symbols. It is an error to include a base mechanism without at least one possible parameter, and Mbed TLS will reject this at compile time. For example, `PSA_WANT_ALG_ECDSA` requires the inclusion of randomized ECDSA for all hash algorithms whose corresponding symbol `PSA_WANT_ALG_xxx` is enabled. + +## Implementation + +### Additional non-public symbols + +#### Accounting for transparent drivers + +In addition to the [configuration symbols](#psa-crypto-configuration-symbols), we need two parallel or mostly parallel sets of symbols: + +* **`MBEDTLS_PSA_ACCEL_xxx`** indicates whether a fully-featured, fallback-free transparent driver is available. +* **`MBEDTLS_PSA_BUILTIN_xxx`** indicates whether the software implementation is needed. + +`MBEDTLS_PSA_ACCEL_xxx` is one of the outputs of the transpilation of a driver description, alongside the glue code for calling the drivers. + +`MBEDTLS_PSA_BUILTIN_xxx` is enabled when `PSA_WANT_xxx` is enabled and `MBEDTLS_PSA_ACCEL_xxx` is disabled. + +These symbols are not part of the public interface of Mbed TLS towards applications or to drivers, regardless of whether the symbols are actually visible. + +### Architecture of symbol definitions + +#### New-style definition of configuration symbols + +When `MBEDTLS_PSA_CRYPTO_CONFIG` is set, the header file `mbedtls/config.h` needs to define all the `MBEDTLS_xxx_C` configuration symbols, including the ones deduced from the PSA Crypto configuration. It does this by including the new header file **`mbedtls/config_psa.h`**, which defines the `MBEDTLS_PSA_BUILTIN_xxx` symbols and deduces the corresponding `MBEDTLS_xxx_C` (and other) symbols. + +`mbedtls/config_psa.h` includes `psa/crypto_config.h`, the user-editable file that defines application requirements. + +#### Old-style definition of configuration symbols + +When `MBEDTLS_PSA_CRYPTO_CONFIG` is not set, the configuration of Mbed TLS works as before, and the inclusion of non-PSA code only depends on `MBEDTLS_xxx` symbols defined (or not) in `mbedtls/config.h`. Furthermore, the new header file **`mbedtls/config_psa.h`** deduces PSA configuration symbols (`PSA_WANT_xxx`, `MBEDTLS_PSA_BUILTIN_xxx`) from classic configuration symbols (`MBEDTLS_xxx`). + +The `PSA_WANT_xxx` definitions in `mbedtls/config_psa.h` are needed not only to build the PSA parts of the library, but also to build code that uses these parts. This includes structure definitions in `psa/crypto_struct.h`, size calculations in `psa/crypto_sizes.h`, and application code that's specific to a given cryptographic mechanism. In Mbed TLS itself, code under `MBEDTLS_USE_PSA_CRYPTO` and conditional compilation guards in tests and sample programs need `PSA_WANT_xxx`. + +Since some existing applications use a handwritten `mbedtls/config.h` or an edited copy of `mbedtls/config.h` from an earlier version of Mbed TLS, `mbedtls/config_psa.h` must be included via an already existing header that is not `mbedtls/config.h`, so it is included via `psa/crypto.h` (for example from `psa/crypto_platform.h`). + +#### Summary of definitions of configuration symbols + +Whether `MBEDTLS_PSA_CRYPTO_CONFIG` is set or not, `mbedtls/config_psa.h` includes `mbedtls/crypto_drivers.h`, a header file generated by the transpilation of the driver descriptions. It defines `MBEDTLS_PSA_ACCEL_xxx` symbols according to the availability of transparent drivers without fallback. + +The following table summarizes where symbols are defined depending on the configuration mode. + +* (U) indicates a symbol that is defined by the user (application). +* (D) indicates a symbol that is deduced from other symbols by code that ships with Mbed TLS. +* (G) indicates a symbol that is generated from driver descriptions. + +| Symbols | With `MBEDTLS_PSA_CRYPTO_CONFIG` | Without `MBEDTLS_PSA_CRYPTO_CONFIG` | +| ------------------------- | -------------------------------- | ----------------------------------- | +| `MBEDTLS_xxx_C` | `mbedtls/config.h` (U) or | `mbedtls/config.h` (U) | +| | `mbedtls/config_psa.h` (D) | | +| `PSA_WANT_xxx` | `psa/crypto_config.h` (U) | `mbedtls/config_psa.h` (D) | +| `MBEDTLS_PSA_BUILTIN_xxx` | `mbedtls/config_psa.h` (D) | `mbedtls/config_psa.h` (D) | +| `MBEDTLS_PSA_ACCEL_xxx` | `mbedtls/crypto_drivers.h` (G) | N/A | + +#### Visibility of internal symbols + +Ideally, the `MBEDTLS_PSA_ACCEL_xxx` and `MBEDTLS_PSA_BUILTIN_xxx` symbols should not be visible to application code or driver code, since they are not part of the public interface of the library. However these symbols are needed to deduce whether to include library modules (for example `MBEDTLS_AES_C` has to be enabled if `MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES` is enabled), which makes it difficult to keep them private. + +#### Compile-time checks + +The header file **`library/psa_check_config.h`** applies sanity checks to the configuration, throwing `#error` if something is wrong. + +A mechanism similar to `mbedtls/check_config.h` detects errors such as enabling ECDSA but no curve. + +Since configuration symbols must be undefined or 1, any other value should trigger an `#error`. + +#### Automatic generation of preprocessor symbol manipulations + +A lot of the preprocessor symbol manipulation is systematic calculations that analyze the configuration. `mbedtls/config_psa.h` and `library/psa_check_config.h` should be generated automatically, in the same manner as `version_features.c`. + +### Structure of PSA Crypto library code + +#### Conditional inclusion of library entry points + +An entry point can be eliminated entirely if no algorithm requires it. + +#### Conditional inclusion of mechanism-specific code + +Code that is specific to certain key types or to certain algorithms must be guarded by the applicable symbols: `PSA_WANT_xxx` for code that is independent of the application, and `MBEDTLS_PSA_BUILTIN_xxx` for code that calls an Mbed TLS software implementation. + +## PSA standardization + +### JSON configuration mechanism + +At the time of writing, the preferred configuration mechanism for a PSA service is in JSON syntax. The translation from JSON to build instructions is not specified by PSA. + +For PSA Crypto, the preferred configuration mechanism would be similar to capability specifications of transparent drivers. The same JSON properties that are used to mean “this driver can perform that mechanism” in a driver description would be used to mean “the application wants to perform that mechanism” in the application configuration. + +### From JSON to C + +The JSON capability language allows a more fine-grained selection than the C mechanism proposed here. For example, it allows requesting only single-part mechanisms, only certain key sizes, or only certain combinations of algorithms and key types. + +The JSON capability language can be translated approximately to the boolean symbol mechanism proposed here. The approximation considers a feature to be enabled if any part of it is enabled. For example, if there is a capability for AES-CTR and one for CAMELLIA-GCM, the translation to boolean symbols will also include AES-GCM and CAMELLIA-CTR. If there is a capability for AES-128, the translation will also include AES-192 and AES-256. + +The boolean symbol mechanism proposed here can be translated to a list of JSON capabilities: for each included algorithm, include a capability with that algorithm, the key types that apply to that algorithm, no size restriction, and all the entry points that apply to that algorithm. + +## Open questions + +### Open questions about the interface + +#### Naming of symbols + +The names of [elliptic curve symbols](#configuration-symbols-for-elliptic-curves) are a bit weird: `SECP_R1_256` instead of `SECP256R1`, `MONTGOMERY_255` instead of `CURVE25519`. Should we make them more classical, but less systematic? + +#### Impossible combinations + +What does it mean to have `PSA_WANT_ALG_ECDSA` enabled but with only Curve25519? Is it a mandatory error? + +#### Diffie-Hellman + +Way to request only specific groups? Not a priority: constrained devices don't do FFDH. Specify it as may change in future versions. + +#### Coexistence with the current Mbed TLS configuration + +The two mechanisms have very different designs. Is there serious potential for confusion? Do we understand how the combinations work? + +### Open questions about the design + +#### Algorithms without a key type or vice versa + +Is it realistic to mandate a compile-time error if a key type is required, but no matching algorithm, or vice versa? Is it always the right thing, for example if there is an opaque driver that manipulates this key type? + +#### Opaque-only mechanisms + +If a mechanism should only be supported in an opaque driver, what does the core need to know about it? Do we have all the information we need? + +This is especially relevant to suppress a mechanism completely if there is no matching algorithm. For example, if there is no transparent implementation of RSA or ECDSA, `psa_sign_hash` and `psa_verify_hash` may still be needed if there is an opaque signature driver. + +### Open questions about the implementation + +#### Testability + +Is this proposal decently testable? There are a lot of combinations. What combinations should we test? + + diff --git a/lib/mbedtls-2.27.0/docs/proposed/psa-driver-developer-guide.md b/lib/mbedtls-2.27.0/docs/proposed/psa-driver-developer-guide.md new file mode 100644 index 0000000..70cb9d3 --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/proposed/psa-driver-developer-guide.md @@ -0,0 +1,45 @@ +PSA Cryptoprocessor driver developer's guide +============================================ + +**This is a specification of work in progress. The implementation is not yet merged into Mbed TLS.** + +This document describes how to write drivers of cryptoprocessors such as accelerators and secure elements for the PSA cryptography subsystem of Mbed TLS. + +This document focuses on behavior that is specific to Mbed TLS. For a reference of the interface between Mbed TLS and drivers, refer to the [PSA Cryptoprocessor Driver Interface specification](psa-driver-interface.html). + +The interface is not fully implemented in Mbed TLS yet and is disabled by default. You can enable the experimental work in progress by setting `MBEDTLS_PSA_CRYPTO_DRIVERS` in the compile-time configuration. Please note that the interface may still change: until further notice, we do not guarantee backward compatibility with existing driver code when `MBEDTLS_PSA_CRYPTO_DRIVERS` is enabled. + +## Introduction + +### Purpose + +The PSA cryptography driver interface provides a way to build Mbed TLS with additional code that implements certain cryptographic primitives. This is primarily intended to support platform-specific hardware. + +There are two types of drivers: + +* **Transparent** drivers implement cryptographic operations on keys that are provided in cleartext at the beginning of each operation. They are typically used for hardware **accelerators**. When a transparent driver is available for a particular combination of parameters (cryptographic algorithm, key type and size, etc.), it is used instead of the default software implementation. Transparent drivers can also be pure software implementations that are distributed as plug-ins to a PSA Crypto implementation. +* **Opaque** drivers implement cryptographic operations on keys that can only be used inside a protected environment such as a **secure element**, a hardware security module, a smartcard, a secure enclave, etc. An opaque driver is invoked for the specific key location that the driver is registered for: the dispatch is based on the key's lifetime. + +### Deliverables for a driver + +To write a driver, you need to implement some functions with C linkage, and to declare these functions in a **driver description file**. The driver description file declares which functions the driver implements and what cryptographic mechanisms they support. Depending on the driver type, you may also need to define some C types and macros in a header file. + +The concrete syntax for a driver description file is JSON. The structure of this JSON file is specified in the section [“Driver description syntax”](psa-driver-interface.html#driver-description-syntax) of the PSA cryptography driver interface specification. + +A driver therefore consists of: + +* A driver description file (in JSON format). +* C header files defining the types required by the driver description. The names of these header files is declared in the driver description file. +* An object file compiled for the target platform defining the functions required by the driver description. Implementations may allow drivers to be provided as source files and compiled with the core instead of being pre-compiled. + +## Driver C interfaces + +Mbed TLS calls driver entry points [as specified in the PSA Cryptography Driver Interface specification](psa-driver-interface.html#driver-entry-points) except as otherwise indicated in this section. + +## Building and testing your driver + + + +## Dependencies on the Mbed TLS configuration + + diff --git a/lib/mbedtls-2.27.0/docs/proposed/psa-driver-integration-guide.md b/lib/mbedtls-2.27.0/docs/proposed/psa-driver-integration-guide.md new file mode 100644 index 0000000..bfd765e --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/proposed/psa-driver-integration-guide.md @@ -0,0 +1,45 @@ +Building Mbed TLS with PSA cryptoprocessor drivers +================================================== + +**This is a specification of work in progress. The implementation is not yet merged into Mbed TLS.** + +This document describes how to build Mbed TLS with additional cryptoprocessor drivers that follow the PSA cryptoprocessor driver interface. + +The interface is not fully implemented in Mbed TLS yet and is disabled by default. You can enable the experimental work in progress by setting `MBEDTLS_PSA_CRYPTO_DRIVERS` in the compile-time configuration. Please note that the interface may still change: until further notice, we do not guarantee backward compatibility with existing driver code when `MBEDTLS_PSA_CRYPTO_DRIVERS` is enabled. + +## Introduction + +The PSA cryptography driver interface provides a way to build Mbed TLS with additional code that implements certain cryptographic primitives. This is primarily intended to support platform-specific hardware. + +Note that such drivers are only available through the PSA cryptography API (crypto functions beginning with `psa_`, and X.509 and TLS interfaces that reference PSA types). + +Concretely speaking, a driver consists of one or more **driver description files** in JSON format and some code to include in the build. The driver code can either be provided in binary form as additional object file to link, or in source form. + +## How to build Mbed TLS with drivers + +To build Mbed TLS with drivers: + +1. Activate `MBEDTLS_PSA_CRYPTO_DRIVERS` in the library configuration. + + ``` + cd /path/to/mbedtls + scripts/config.py set MBEDTLS_PSA_CRYPTO_DRIVERS + ``` + +2. Pass the driver description files through the Make variable `PSA_DRIVERS` when building the library. + + ``` + cd /path/to/mbedtls + make PSA_DRIVERS="/path/to/acme/driver.json /path/to/nadir/driver.json" lib + ``` + +3. Link your application with the implementation of the driver functions. + + ``` + cd /path/to/application + ld myapp.o -L/path/to/acme -lacmedriver -L/path/to/nadir -lnadirdriver -L/path/to/mbedtls -lmbedcrypto + ``` + + + + diff --git a/lib/mbedtls-2.27.0/docs/proposed/psa-driver-interface.md b/lib/mbedtls-2.27.0/docs/proposed/psa-driver-interface.md new file mode 100644 index 0000000..23274c7 --- /dev/null +++ b/lib/mbedtls-2.27.0/docs/proposed/psa-driver-interface.md @@ -0,0 +1,1002 @@ +PSA Cryptoprocessor Driver Interface +==================================== + +This document describes an interface for cryptoprocessor drivers in the PSA cryptography API. This interface complements the [PSA Cryptography API specification](https://armmbed.github.io/mbed-crypto/psa/#application-programming-interface), which describes the interface between a PSA Cryptography implementation and an application. + +This specification is work in progress and should be considered to be in a beta stage. There is ongoing work to implement this interface in Mbed TLS, which is the reference implementation of the PSA Cryptography API. At this stage, Arm does not expect major changes, but minor changes are expected based on experience from the first implementation and on external feedback. + +## Introduction + +### Purpose of the driver interface + +The PSA Cryptography API defines an interface that allows applications to perform cryptographic operations in a uniform way regardless of how the operations are performed. Under the hood, different keys may be stored and used in different hardware or in different logical partitions, and different algorithms may involve different hardware or software components. + +The driver interface allows implementations of the PSA Cryptography API to be built compositionally. An implementation of the PSA Cryptography API is composed of a **core** and zero or more **drivers**. The core handles key management, enforces key usage policies, and dispatches cryptographic operations either to the applicable driver or to built-in code. + +Functions in the PSA Cryptography API invoke functions in the core. Code from the core calls drivers as described in the present document. + +### Types of drivers + +The PSA Cryptography driver interface supports two types of cryptoprocessors, and accordingly two types of drivers. + +* **Transparent** drivers implement cryptographic operations on keys that are provided in cleartext at the beginning of each operation. They are typically used for hardware **accelerators**. When a transparent driver is available for a particular combination of parameters (cryptographic algorithm, key type and size, etc.), it is used instead of the default software implementation. Transparent drivers can also be pure software implementations that are distributed as plug-ins to a PSA Cryptography implementation (for example, an alternative implementation with different performance characteristics, or a certified implementation). +* **Opaque** drivers implement cryptographic operations on keys that can only be used inside a protected environment such as a **secure element**, a hardware security module, a smartcard, a secure enclave, etc. An opaque driver is invoked for the specific [key location](#lifetimes-and-locations) that the driver is registered for: the dispatch is based on the key's lifetime. + +### Requirements + +The present specification was designed to fulfill the following high-level requirements. + +[Req.plugins] It is possible to combine multiple drivers from different providers into the same implementation, without any prior arrangement other than choosing certain names and values from disjoint namespaces. + +[Req.compile] It is possible to compile the code of each driver and of the core separately, and link them together. A small amount of glue code may need to be compiled once the list of drivers is available. + +[Req.types] Support drivers for the following types of hardware: accelerators that operate on keys in cleartext; cryptoprocessors that can wrap keys with a built-in keys but not store user keys; and cryptoprocessors that store key material. + +[Req.portable] The interface between drivers and the core does not involve any platform-specific consideration. Driver calls are simple C function calls. Interactions with platform-specific hardware happen only inside the driver (and in fact a driver need not involve any hardware at all). + +[Req.location] Applications can tell which location values correspond to which secure element drivers. + +[Req.fallback] Accelerator drivers can specify that they do not fully support a cryptographic mechanism and that a fallback to core code may be necessary. Conversely, if an accelerator fully supports cryptographic mechanism, the core must be able to omit code for this mechanism. + +[Req.mechanisms] Drivers can specify which mechanisms they support. A driver's code will not be invoked for cryptographic mechanisms that it does not support. + +## Overview of drivers + +### Deliverables for a driver + +To write a driver, you need to implement some functions with C linkage, and to declare these functions in a **driver description file**. The driver description file declares which functions the driver implements and what cryptographic mechanisms they support. If the driver description references custom types, macros or constants, you also need to provide C header files defining those elements. + +The concrete syntax for a driver description file is JSON. The structure of this JSON file is specified in the section [“Driver description syntax”](#driver-description-syntax). + +A driver therefore consists of: + +* A driver description file (in JSON format). +* C header files defining the types required by the driver description. The names of these header files are declared in the driver description file. +* An object file compiled for the target platform defining the entry point functions specified by the driver description. Implementations may allow drivers to be provided as source files and compiled with the core instead of being pre-compiled. + +How to provide the driver description file, the C header files and the object code is implementation-dependent. + +### Driver description syntax + +The concrete syntax for a driver description file is JSON. + +#### Driver description list + +PSA Cryptography core implementations should support multiple drivers. The driver description files are passed to the implementation as an ordered list in an unspecified manner. This may be, for example, a list of file names passed on a command line, or a JSON list whose elements are individual driver descriptions. + +#### Driver description top-level element + +A driver description is a JSON object containing the following properties: + +* `"prefix"` (mandatory, string). This must be a valid prefix for a C identifier. All the types and functions provided by the driver have a name that starts with this prefix unless overridden with a `"name"` element in the applicable capability as described below. +* `"type"` (mandatory, string). One of `"transparent"` or `"opaque"`. +* `"headers"` (optional, array of strings). A list of header files. These header files must define the types, macros and constants referenced by the driver description. They may declare the entry point functions, but this is not required. They may include other PSA headers and standard headers of the platform. Whether they may include other headers is implementation-specific. If omitted, the list of headers is empty. The header files must be present at the specified location relative to a directory on the compiler's include path when compiling glue code between the core and the drivers. +* `"capabilities"` (mandatory, array of [capabilities](#driver-description-capability)). +A list of **capabilities**. Each capability describes a family of functions that the driver implements for a certain class of cryptographic mechanisms. +* `"key_context"` (not permitted for transparent drivers, mandatory for opaque drivers): information about the [representation of keys](#key-format-for-opaque-drivers). +* `"persistent_state_size"` (not permitted for transparent drivers, optional for opaque drivers, integer or string). The size in bytes of the [persistent state of the driver](#opaque-driver-persistent-state). This may be either a non-negative integer or a C constant expression of type `size_t`. +* `"location"` (not permitted for transparent drivers, optional for opaque drivers, integer or string). The [location value](#lifetimes-and-locations) for which this driver is invoked. In other words, this determines the lifetimes for which the driver is invoked. This may be either a non-negative integer or a C constant expression of type `psa_key_location_t`. + +### Driver description capability + +#### Capability syntax + +A capability declares a family of functions that the driver implements for a certain class of cryptographic mechanisms. The capability specifies which key types and algorithms are covered and the names of the types and functions that implement it. + +A capability is a JSON object containing the following properties: + +* `"entry_points"` (mandatory, list of strings). Each element is the name of a [driver entry point](#driver-entry-points) or driver entry point family. An entry point is a function defined by the driver. If specified, the core will invoke this capability of the driver only when performing one of the specified operations. The driver must implement all the specified entry points, as well as the types if applicable. +* `"algorithms"` (optional, list of strings). Each element is an [algorithm specification](#algorithm-specifications). If specified, the core will invoke this capability of the driver only when performing one of the specified algorithms. If omitted, the core will invoke this capability for all applicable algorithms. +* `"key_types"` (optional, list of strings). Each element is a [key type specification](#key-type-specifications). If specified, the core will invoke this capability of the driver only for operations involving a key with one of the specified key types. If omitted, the core will invoke this capability of the driver for all applicable key types. +* `"key_sizes"` (optional, list of integers). If specified, the core will invoke this capability of the driver only for operations involving a key with one of the specified key sizes. If omitted, the core will invoke this capability of the driver for all applicable key sizes. Key sizes are expressed in bits. +* `"names"` (optional, object). A mapping from entry point names described by the `"entry_points"` property, to the name of the C function in the driver that implements the corresponding function. If a function is not listed here, name of the driver function that implements it is the driver's prefix followed by an underscore (`_`) followed by the function name. If this property is omitted, it is equivalent to an empty object (so each entry point *suffix* is implemented by a function called *prefix*`_`*suffix*). +* `"fallback"` (optional for transparent drivers, not permitted for opaque drivers, boolean). If present and true, the driver may return `PSA_ERROR_NOT_SUPPORTED`, in which case the core should call another driver or use built-in code to perform this operation. If absent or false, the driver is expected to fully support the mechanisms described by this capability. See the section “[Fallback](#fallback)” for more information. + +#### Capability semantics + +When the PSA Cryptography implementation performs a cryptographic mechanism, it invokes available driver entry points as described in the section [“Driver entry points”](#driver-entry-points). + +A driver is considered available for a cryptographic mechanism that invokes a given entry point if all of the following conditions are met: + +* The driver specification includes a capability whose `"entry_points"` list either includes the entry point or includes an entry point family that includes the entry point. +* If the mechanism involves an algorithm: + * either the capability does not have an `"algorithms"` property; + * or the value of the capability's `"algorithms"` property includes an [algorithm specification](#algorithm-specifications) that matches this algorithm. +* If the mechanism involves a key: + * either the key is transparent (its location is `PSA_KEY_LOCATION_LOCAL_STORAGE`) and the driver is transparent; + * or the key is opaque (its location is not `PSA_KEY_LOCATION_LOCAL_STORAGE`) and the driver is an opaque driver whose location is the key's location. +* If the mechanism involves a key: + * either the capability does not have a `"key_types"` property; + * or the value of the capability's `"key_types"` property includes a [key type specification](#key-type-specifications) that matches this algorithm. +* If the mechanism involves a key: + * either the capability does not have a `"key_sizes"` property; + * or the value of the capability's `"key_sizes"` property includes the key's size. + +If a driver includes multiple applicable capabilities for a given combination of entry point, algorithm, key type and key size, and all the capabilities map the entry point to the same function name, the driver is considered available for this cryptographic mechanism. If a driver includes multiple applicable capabilities for a given combination of entry point, algorithm, key type and key size, and at least two of these capabilities map the entry point to the different function names, the driver specification is invalid. + +If multiple transparent drivers have applicable capabilities for a given combination of entry point, algorithm, key type and key size, the first matching driver in the [specification list](#driver-description-list) is invoked. If the capability has [fallback](#fallback) enabled and the first driver returns `PSA_ERROR_NOT_SUPPORTED`, the next matching driver is invoked, and so on. + +If multiple opaque drivers have the same location, the list of driver specifications is invalid. + +#### Capability examples + +Example 1: the following capability declares that the driver can perform deterministic ECDSA signatures (but not signature verification) using any hash algorithm and any curve that the core supports. If the prefix of this driver is `"acme"`, the function that performs the signature is called `acme_sign_hash`. +``` +{ + "entry_points": ["sign_hash"], + "algorithms": ["PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_ANY_HASH)"], +} +``` + +Example 2: the following capability declares that the driver can perform deterministic ECDSA signatures using SHA-256 or SHA-384 with a SECP256R1 or SECP384R1 private key (with either hash being possible in combination with either curve). If the prefix of this driver is `"acme"`, the function that performs the signature is called `acme_sign_hash`. +``` +{ + "entry_points": ["sign_hash"], + "algorithms": ["PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)", + "PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_384)"], + "key_types": ["PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)"], + "key_sizes": [256, 384] +} +``` + +### Algorithm and key specifications + +#### Algorithm specifications + +An algorithm specification is a string consisting of a `PSA_ALG_xxx` macro that specifies a cryptographic algorithm or an algorithm wildcard policy defined by the PSA Cryptography API. If the macro takes arguments, the string must have the syntax of a C macro call and each argument must be an algorithm specification or a decimal or hexadecimal literal with no suffix, depending on the expected type of argument. + +Spaces are optional after commas. Whether other whitespace is permitted is implementation-specific. + +Valid examples: +``` +PSA_ALG_SHA_256 +PSA_ALG_HMAC(PSA_ALG_SHA_256) +PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)) +PSA_ALG_RSA_PSS(PSA_ALG_ANY_HASH) +``` + +#### Key type specifications + +An algorithm specification is a string consisting of a `PSA_KEY_TYPE_xxx` macro that specifies a key type defined by the PSA Cryptography API. If the macro takes an argument, the string must have the syntax of a C macro call and each argument must be the name of a constant of suitable type (curve or group). + +The name `_` may be used instead of a curve or group to indicate that the capability concerns all curves or groups. + +Valid examples: +``` +PSA_KEY_TYPE_AES +PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1) +PSA_KEY_TYPE_ECC_KEY_PAIR(_) +``` + +### Driver entry points + +#### Overview of driver entry points + +Drivers define functions, each of which implements an aspect of a capability of a driver, such as a cryptographic operation, a part of a cryptographic operation, or a key management action. These functions are called the **entry points** of the driver. Most driver entry points correspond to a particular function in the PSA Cryptography API. For example, if a call to `psa_sign_hash()` is dispatched to a driver, it invokes the driver's `sign_hash` function. + +All driver entry points return a status of type `psa_status_t` which should use the status codes documented for PSA services in general and for PSA Cryptography in particular: `PSA_SUCCESS` indicates that the function succeeded, and `PSA_ERROR_xxx` values indicate that an error occurred. + +The signature of a driver entry point generally looks like the signature of the PSA Cryptography API that it implements, with some modifications. This section gives an overview of modifications that apply to whole classes of entry points. Refer to the reference section for each entry point or entry point family for details. + +* For entry points that operate on an existing key, the `psa_key_id_t` parameter is replaced by a sequence of three parameters that describe the key: + 1. `const psa_key_attributes_t *attributes`: the key attributes. + 2. `const uint8_t *key_buffer`: a key material or key context buffer. + 3. `size_t key_buffer_size`: the size of the key buffer in bytes. + + For transparent drivers, the key buffer contains the key material, in the same format as defined for `psa_export_key()` and `psa_export_public_key()` in the PSA Cryptography API. For opaque drivers, the content of the key buffer is entirely up to the driver. + +* For entry points that involve a multi-part operation, the operation state type (`psa_XXX_operation_t`) is replaced by a driver-specific operation state type (*prefix*`_XXX_operation_t`). + +* For entry points that are involved in key creation, the `psa_key_id_t *` output parameter is replaced by a sequence of parameters that convey the key context: + 1. `uint8_t *key_buffer`: a buffer for the key material or key context. + 2. `size_t key_buffer_size`: the size of the key buffer in bytes. + 2. `size_t *key_buffer_length`: the length of the data written to the key buffer in bytes. + +Some entry points are grouped in families that must be implemented as a whole. If a driver supports an entry point family, it must provide all the entry points in the family. + +Drivers can also have entry points related to random generation. A transparent driver can provide a [random generation interface](#random-generation-entry-points). Separately, transparent and opaque drivers can have [entropy collection entry points](#entropy-collection-entry-point). + +#### General considerations on driver entry point parameters + +Buffer parameters for driver entry points obey the following conventions: + +* An input buffer has the type `const uint8_t *` and is immediately followed by a parameter of type `size_t` that indicates the buffer size. +* An output buffer has the type `uint8_t *` and is immediately followed by a parameter of type `size_t` that indicates the buffer size. A third parameter of type `size_t *` is provided to report the actual length of the data written in the buffer if the function succeeds. +* An in-out buffer has the type `uint8_t *` and is immediately followed by a parameter of type `size_t` that indicates the buffer size. In-out buffers are only used when the input and the output have the same length. + +Buffers of size 0 may be represented with either a null pointer or a non-null pointer. + +Input buffers and other input-only parameters (`const` pointers) may be in read-only memory. Overlap is possible between input buffers, and between an input buffer and an output buffer, but not between two output buffers or between a non-buffer parameter and another parameter. + +#### Driver entry points for single-part cryptographic operations + +The following driver entry points perform a cryptographic operation in one shot (single-part operation): + +* `"hash_compute"` (transparent drivers only): calculation of a hash. Called by `psa_hash_compute()` and `psa_hash_compare()`. To verify a hash with `psa_hash_compare()`, the core calls the driver's `"hash_compute"` entry point and compares the result with the reference hash value. +* `"mac_compute"`: calculation of a MAC. Called by `psa_mac_compute()` and possibly `psa_mac_verify()`. To verify a mac with `psa_mac_verify()`, the core calls an applicable driver's `"mac_verify"` entry point if there is one, otherwise the core calls an applicable driver's `"mac_compute"` entry point and compares the result with the reference MAC value. +* `"mac_verify"`: verification of a MAC. Called by `psa_mac_verify()`. This entry point is mainly useful for drivers of secure elements that verify a MAC without revealing the correct MAC. Although transparent drivers may implement this entry point in addition to `"mac_compute"`, it is generally not useful because the core can call the `"mac_compute"` entry point and compare with the expected MAC value. +* `"cipher_encrypt"`: unauthenticated symmetric cipher encryption. Called by `psa_cipher_encrypt()`. +* `"cipher_decrypt"`: unauthenticated symmetric cipher decryption. Called by `psa_cipher_decrypt()`. +* `"aead_encrypt"`: authenticated encryption with associated data. Called by `psa_aead_encrypt()`. +* `"aead_decrypt"`: authenticated decryption with associated data. Called by `psa_aead_decrypt()`. +* `"asymmetric_encrypt"`: asymmetric encryption. Called by `psa_asymmetric_encrypt()`. +* `"asymmetric_decrypt"`: asymmetric decryption. Called by `psa_asymmetric_decrypt()`. +* `"sign_hash"`: signature of an already calculated hash. Called by `psa_sign_hash()` and possibly `psa_sign_message()`. To sign a message with `psa_sign_message()`, the core calls an applicable driver's `"sign_message"` entry point if there is one, otherwise the core calls an applicable driver's `"hash_compute"` entry point followed by an applicable driver's `"sign_hash"` entry point. +* `"verify_hash"`: verification of an already calculated hash. Called by `psa_verify_hash()` and possibly `psa_verify_message()`. To verify a message with `psa_verify_message()`, the core calls an applicable driver's `"verify_message"` entry point if there is one, otherwise the core calls an applicable driver's `"hash_compute"` entry point followed by an applicable driver's `"verify_hash"` entry point. +* `"sign_message"`: signature of a message. Called by `psa_sign_message()`. +* `"verify_message"`: verification of a message. Called by `psa_verify_message()`. +* `"key_agreement"`: key agreement without a subsequent key derivation. Called by `psa_raw_key_agreement()` and possibly `psa_key_derivation_key_agreement()`. + +### Driver entry points for multi-part operations + +#### General considerations on multi-part operations + +The entry points that implement each step of a multi-part operation are grouped into a family. A driver that implements a multi-part operation must define all of the entry points in this family as well as a type that represents the operation context. The lifecycle of a driver operation context is similar to the lifecycle of an API operation context: + +1. The core initializes operation context objects to either all-bits-zero or to logical zero (`{0}`), at its discretion. +1. The core calls the `xxx_setup` entry point for this operation family. If this fails, the core destroys the operation context object without calling any other driver entry point on it. +1. The core calls other entry points that manipulate the operation context object, respecting the constraints. +1. If any entry point fails, the core calls the driver's `xxx_abort` entry point for this operation family, then destroys the operation context object without calling any other driver entry point on it. +1. If a “finish” entry point fails, the core destroys the operation context object without calling any other driver entry point on it. The finish entry points are: *prefix*`_mac_sign_finish`, *prefix*`_mac_verify_finish`, *prefix*`_cipher_fnish`, *prefix*`_aead_finish`, *prefix*`_aead_verify`. + +If a driver implements a multi-part operation but not the corresponding single-part operation, the core calls the driver's multipart operation entry points to perform the single-part operation. + +#### Multi-part operation entry point family `"hash_multipart"` + +This family corresponds to the calculation of a hash in multiple steps. + +This family applies to transparent drivers only. + +This family requires the following type and entry points: + +* Type `"hash_operation_t"`: the type of a hash operation context. It must be possible to copy a hash operation context byte by byte, therefore hash operation contexts must not contain any embedded pointers (except pointers to global data that do not change after the setup step). +* `"hash_setup"`: called by `psa_hash_setup()`. +* `"hash_update"`: called by `psa_hash_update()`. +* `"hash_finish"`: called by `psa_hash_finish()` and `psa_hash_verify()`. +* `"hash_abort"`: called by all multi-part hash functions of the PSA Cryptography API. + +To verify a hash with `psa_hash_verify()`, the core calls the driver's *prefix*`_hash_finish` entry point and compares the result with the reference hash value. + +For example, a driver with the prefix `"acme"` that implements the `"hash_multipart"` entry point family must define the following type and entry points (assuming that the capability does not use the `"names"` property to declare different type and entry point names): + +``` +typedef ... acme_hash_operation_t; +psa_status_t acme_hash_setup(acme_hash_operation_t *operation, + psa_algorithm_t alg); +psa_status_t acme_hash_update(acme_hash_operation_t *operation, + const uint8_t *input, + size_t input_length); +psa_status_t acme_hash_finish(acme_hash_operation_t *operation, + uint8_t *hash, + size_t hash_size, + size_t *hash_length); +psa_status_t acme_hash_abort(acme_hash_operation_t *operation); +``` + +#### Operation family `"mac_multipart"` + +TODO + +#### Operation family `"mac_verify_multipart"` + +TODO + +#### Operation family `"cipher_encrypt_multipart"` + +TODO + +#### Operation family `"cipher_decrypt_multipart"` + +TODO + +#### Operation family `"aead_encrypt_multipart"` + +TODO + +#### Operation family `"aead_decrypt_multipart"` + +TODO + +#### Operation family `"key_derivation"` + +This family requires the following type and entry points: + +* Type `"key_derivation_operation_t"`: the type of a key derivation operation context. +* `"key_derivation_setup"`: called by `psa_key_derivation_setup()`. +* `"key_derivation_set_capacity"`: called by `psa_key_derivation_set_capacity()`. The core will always enforce the capacity, therefore this function does not need to do anything for algorithms where the output stream only depends on the effective generated length and not on the capacity. +* `"key_derivation_input_bytes"`: called by `psa_key_derivation_input_bytes()` and `psa_key_derivation_input_key()`. For transparent drivers, when processing a call to `psa_key_derivation_input_key()`, the core always calls the applicable driver's `"key_derivation_input_bytes"` entry point. +* `"key_derivation_input_key"` (opaque drivers only) +* `"key_derivation_output_bytes"`: called by `psa_key_derivation_output_bytes()`; also by `psa_key_derivation_output_key()` for transparent drivers. +* `"key_derivation_output_key"`: called by `psa_key_derivation_output_key()` for transparent drivers when deriving an asymmetric key pair, and also for opaque drivers. +* `"key_derivation_abort"`: called by all key derivation functions of the PSA Cryptography API. + +TODO: key input and output for opaque drivers; deterministic key generation for transparent drivers + +TODO + +### Driver entry points for key management + +The driver entry points for key management differ significantly between [transparent drivers](#key-management-with-transparent-drivers) and [opaque drivers](#key-management-with-opaque-drivers). This section describes common elements. Refer to the applicable section for each driver type for more information. + +The entry points that create or format key data have the following prototypes for a driver with the prefix `"acme"`: + +``` +psa_status_t acme_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length, + size_t *bits); // additional parameter, see below +psa_status_t acme_generate_key(const psa_key_attributes_t *attributes, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length); +``` + +TODO: derivation, copy + +* The key attributes (`attributes`) have the same semantics as in the PSA Cryptography application interface. +* For the `"import_key"` entry point, the input in the `data` buffer is either the export format or an implementation-specific format that the core documents as an acceptable input format for `psa_import_key()`. +* The size of the key data buffer `key_buffer` is sufficient for the internal representation of the key. For a transparent driver, this is the key's [export format](#key-format-for-transparent-drivers). For an opaque driver, this is the size determined from the driver description and the key attributes, as specified in the section [“Key format for opaque drivers”](#key-format-for-opaque-drivers). +* For an opaque driver with an `"allocate_key"` entry point, the content of the key data buffer on entry is the output of that entry point. +* The `"import_key"` entry point must determine or validate the key size and set `*bits` as described in the section [“Key size determination on import”](#key-size-determination-on-import) below. + +All key creation entry points must ensure that the resulting key is valid as specified in the section [“Key validation”](#key-validation) below. This is primarily important for import entry points since the key data comes from the application. + +#### Key size determination on import + +The `"import_key"` entry point must determine or validate the key size. +The PSA Cryptography API exposes the key size as part of the key attributes. +When importing a key, the key size recorded in the key attributes can be either a size specified by the caller of the API (who may not be trusted), or `0` which indicates that the size must be calculated from the data. + +When the core calls the `"import_key"` entry point to process a call to `psa_import_key`, it passes an `attributes` structure such that `psa_get_key_bits(attributes)` is the size passed by the caller of `psa_import_key`. If this size is `0`, the `"import_key"` entry point must set the `bits` input-output parameter to the correct key size. The semantics of `bits` is as follows: + +* The core sets `*bits` to `psa_get_key_bits(attributes)` before calling the `"import_key"` entry point. +* If `*bits == 0`, the driver must determine the key size from the data and set `*bits` to this size. If the key size cannot be determined from the data, the driver must return `PSA_ERROR_INVALID_ARGUMENT` (as of version 1.0 of the PSA Cryptography API specification, it is possible to determine the key size for all standard key types). +* If `*bits != 0`, the driver must check the value of `*bits` against the data and return `PSA_ERROR_INVALID_ARGUMENT` if it does not match. If the driver entry point changes `*bits` to a different value but returns `PSA_SUCCESS`, the core will consider the key as invalid and the import will fail. + +#### Key validation + +Key creation entry points must produce valid key data. Key data is _valid_ if operations involving the key are guaranteed to work functionally and not to cause indirect security loss. Operation functions are supposed to receive valid keys, and should not have to check and report invalid keys. For example: + +* If a cryptographic mechanism is defined as having keying material of a certain size, or if the keying material involves integers that have to be in a certain range, key creation must ensure that the keying material has an appropriate size and falls within an appropriate range. +* If a cryptographic operation involves a division by an integer which is provided as part of a key, key creation must ensure that this integer is nonzero. +* If a cryptographic operation involves two keys A and B (or more), then the creation of A must ensure that using it does not risk compromising B. This applies even if A's policy does not explicitly allow a problematic operation, but A is exportable. In particular, public keys that can potentially be used for key agreement are considered invalid and must not be created if they risk compromising the private key. +* On the other hand, it is acceptable for import to accept a key that cannot be verified as valid if using this key would at most compromise the key itself and material that is secured with this key. For example, RSA key import does not need to verify that the primes are actually prime. Key import may accept an insecure key if the consequences of the insecurity are no worse than a leak of the key prior to its import. + +With opaque drivers, the key context can only be used by code from the same driver, so key validity is primarily intended to report key creation errors at creation time rather than during an operation. With transparent drivers, the key context can potentially be used by code from a different provider, so key validity is critical for interoperability. + +This section describes some minimal validity requirements for standard key types. + +* For symmetric key types, check that the key size is suitable for the type. +* For DES (`PSA_KEY_TYPE_DES`), additionally verify the parity bits. +* For RSA (`PSA_KEY_TYPE_RSA_PUBLIC_KEY`, `PSA_KEY_TYPE_RSA_KEY_PAIR`), check the syntax of the key and make sanity checks on its components. TODO: what sanity checks? Value ranges (e.g. p < n), sanity checks such as parity, minimum and maximum size, what else? +* For elliptic curve private keys (`PSA_KEY_TYPE_ECC_KEY_PAIR`), check the size and range. TODO: what else? +* For elliptic curve public keys (`PSA_KEY_TYPE_ECC_PUBLIC_KEY`), check the size and range, and that the point is on the curve. TODO: what else? + +### Entropy collection entry point + +A driver can declare an entropy source by providing a `"get_entropy"` entry point. This entry point has the following prototype for a driver with the prefix `"acme"`: + +``` +psa_status_t acme_get_entropy(uint32_t flags, + size_t *estimate_bits, + uint8_t *output, + size_t output_size); +``` + +The semantics of the parameters is as follows: + +* `flags`: a bit-mask of [entropy collection flags](#entropy-collection-flags). +* `estimate_bits`: on success, an estimate of the amount of entropy that is present in the `output` buffer, in bits. This must be at least `1` on success. The value is ignored on failure. Drivers should return a conservative estimate, even in circumstances where the quality of the entropy source is degraded due to environmental conditions (e.g. undervolting, low temperature, etc.). +* `output`: on success, this buffer contains non-deterministic data with an estimated entropy of at least `*estimate_bits` bits. When the entropy is coming from a hardware peripheral, this should preferably be raw or lightly conditioned measurements from a physical process, such that statistical tests run over a sufficiently large amount of output can confirm the entropy estimates. But this specification also permits entropy sources that are fully conditioned, for example when the PSA Cryptography system is running as an application in an operating system and `"get_entropy"` returns data from the random generator in the operating system's kernel. +* `output_size`: the size of the `output` buffer in bytes. This size should be large enough to allow a driver to pass unconditioned data with a low density of entropy; for example a peripheral that returns eight bytes of data with an estimated one bit of entropy cannot provide meaningful output in less than 8 bytes. + +Note that there is no output parameter indicating how many bytes the driver wrote to the buffer. Such an output length indication is not necessary because the entropy may be located anywhere in the buffer, so the driver may write less than `output_size` bytes but the core does not need to know this. The output parameter `estimate_bits` contains the amount of entropy, expressed in bits, which may be significantly less than `output_size * 8`. + +The entry point may return the following statuses: + +* `PSA_SUCCESS`: success. The output buffer contains some entropy. +* `PSA_ERROR_INSUFFICIENT_ENTROPY`: no entropy is available without blocking. This is only permitted if the `PSA_DRIVER_GET_ENTROPY_BLOCK` flag is clear. The core may call `get_entropy` again later, giving time for entropy to be gathered or for adverse environmental conditions to be rectified. +* Other error codes indicate a transient or permanent failure of the entropy source. + +Unlike most other entry points, if multiple transparent drivers include a `"get_entropy"` point, the core will call all of them (as well as the entry points from opaque drivers). Fallback is not applicable to `"get_entropy"`. + +#### Entropy collection flags + +* `PSA_DRIVER_GET_ENTROPY_BLOCK`: If this flag is set, the driver should block until it has at least one bit of entropy. If this flag is clear, the driver should avoid blocking if no entropy is readily available. +* `PSA_DRIVER_GET_ENTROPY_KEEPALIVE`: This flag is intended to help with energy management for entropy-generating peripherals. If this flag is set, the driver should expect another call to `acme_get_entropy` after a short time. If this flag is clear, the core is not expecting to call the `"get_entropy"` entry point again within a short amount of time (but it may do so nonetheless). + +#### Entropy collection and blocking + +The intent of the `BLOCK` and `KEEPALIVE` [flags](#entropy-collection-flags) is to support drivers for TRNG (True Random Number Generator, i.e. an entropy source peripheral) that have a long ramp-up time, especially on platforms with multiple entropy sources. + +Here is a suggested call sequence for entropy collection that leverages these flags: + +1. The core makes a first round of calls to `"get_entropy"` on every source with the `BLOCK` flag clear and the `KEEPALIVE` flag set, so that drivers can prepare the TRNG peripheral. +2. The core makes a second round of calls with the `BLOCK` flag set and the `KEEPALIVE` flag clear to gather needed entropy. +3. If the second round does not collect enough entropy, the core makes more similar rounds, until the total amount of collected entropy is sufficient. + +### Miscellaneous driver entry points + +#### Driver initialization + +A driver may declare an `"init"` entry point in a capability with no algorithm, key type or key size. If so, the core calls this entry point once during the initialization of the PSA Cryptography subsystem. If the init entry point of any driver fails, the initialization of the PSA Cryptography subsystem fails. + +When multiple drivers have an init entry point, the order in which they are called is unspecified. It is also unspecified whether other drivers' `"init"` entry points are called if one or more init entry point fails. + +On platforms where the PSA Cryptography implementation is a subsystem of a single application, the initialization of the PSA Cryptography subsystem takes place during the call to `psa_crypto_init()`. On platforms where the PSA Cryptography implementation is separate from the application or applications, the initialization of the PSA Cryptography subsystem takes place before or during the first time an application calls `psa_crypto_init()`. + +The init entry point does not take any parameter. + +### Combining multiple drivers + +To declare a cryptoprocessor can handle both cleartext and wrapped keys, you need to provide two driver descriptions, one for a transparent driver and one for an opaque driver. You can use the mapping in capabilities' `"names"` property to arrange for multiple driver entry points to map to the same C function. + +## Transparent drivers + +### Key format for transparent drivers + +The format of a key for transparent drivers is the same as in applications. Refer to the documentation of [`psa_export_key()`](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#c.psa_export_key) and [`psa_export_public_key()`](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#c.psa_export_public_key) in the PSA Cryptography API specification. For custom key types defined by an implementation, refer to the documentation of that implementation. + +### Key management with transparent drivers + +Transparent drivers may provide the following key management entry points: + +* [`"import_key"`](#key-import-with-transparent-drivers): called by `psa_import_key()`, only when importing a key pair or a public key (key such that `PSA_KEY_TYPE_IS_ASYMMETRIC` is true). +* `"generate_key"`: called by `psa_generate_key()`, only when generating a key pair (key such that `PSA_KEY_TYPE_IS_KEY_PAIR` is true). +* `"key_derivation_output_key"`: called by `psa_key_derivation_output_key()`, only when deriving a key pair (key such that `PSA_KEY_TYPE_IS_KEY_PAIR` is true). +* `"export_public_key"`: called by the core to obtain the public key of a key pair. The core may call this function at any time to obtain the public key, which can be for `psa_export_public_key()` but also at other times, including during a cryptographic operation that requires the public key such as a call to `psa_verify_message()` on a key pair object. + +Transparent drivers are not involved when exporting, copying or destroying keys, or when importing, generating or deriving symmetric keys. + +#### Key import with transparent drivers + +As discussed in [the general section about key management entry points](#driver-entry-points-for-key-management), the key import entry points has the following prototype for a driver with the prefix `"acme"`: +``` +psa_status_t acme_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length, + size_t *bits); +``` + +This entry point has several roles: + +1. Parse the key data in the input buffer `data`. The driver must support the export format for the key types that the entry point is declared for. It may support additional formats as specified in the description of [`psa_import_key()`](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#c.psa_export_key) in the PSA Cryptography API specification. +2. Validate the key data. The necessary validation is described in the section [“Key validation with transparent drivers”](#key-validation-with-transparent-drivers) above. +3. [Determine the key size](#key-size-determination-on-import) and output it through `*bits`. +4. Copy the validated key data from `data` to `key_buffer`. The output must be in the canonical format documented for [`psa_export_key()`](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#c.psa_export_key) or [`psa_export_public_key()`](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html#c.psa_export_public_key), so if the input is not in this format, the entry point must convert it. + +### Random generation entry points + +A transparent driver may provide an operation family that can be used as a cryptographic random number generator. The random generation mechanism must obey the following requirements: + +* The random output must be of cryptographic quality, with a uniform distribution. Therefore, if the random generator includes an entropy source, this entropy source must be fed through a CSPRNG (cryptographically secure pseudo-random number generator). +* Random generation is expected to be fast. (If a device can provide entropy but is slow at generating random data, declare it as an [entropy driver](#entropy-collection-entry-point) instead.) +* The random generator should be able to incorporate entropy provided by an outside source. If it isn't, the random generator can only be used if it's the only entropy source on the platform. (A random generator peripheral can be declared as an [entropy source](#entropy-collection-entry-point) instead of a random generator; this way the core will combine it with other entropy sources.) +* The random generator may either be deterministic (in the sense that it always returns the same data when given the same entropy inputs) or non-deterministic (including its own entropy source). In other words, this interface is suitable both for PRNG (pseudo-random number generator, also known as DRBG (deterministic random bit generator)) and for NRBG (non-deterministic random bit generator). + +If no driver implements the random generation entry point family, the core provides an unspecified random generation mechanism. + +This operation family requires the following type, entry points and parameters (TODO: where exactly are the parameters in the JSON structure?): + +* Type `"random_context_t"`: the type of a random generation context. +* `"init_random"` (entry point, optional): if this function is present, [the core calls it once](#random-generator-initialization) after allocating a `"random_context_t"` object. +* `"add_entropy"` (entry point, optional): the core calls this function to [inject entropy](#entropy-injection). This entry point is optional if the driver is for a peripheral that includes an entropy source of its own, however [random generator drivers without entropy injection](#random-generator-drivers-without-entropy-injection) have limited portability since they can only be used on platforms with no other entropy source. This entry point is mandatory if `"initial_entropy_size"` is nonzero. +* `"get_random"` (entry point, mandatory): the core calls this function whenever it needs to [obtain random data](#the-get_random-entry-point). +* `"initial_entropy_size"` (integer, mandatory): the minimum number of bytes of entropy that the core must supply before the driver can output random data. This can be `0` if the driver is for a peripheral that includes an entropy source of its own. +* `"reseed_entropy_size"` (integer, optional): the minimum number of bytes of entropy that the core should supply via [`"add_entropy"`](#entropy-injection) when the driver runs out of entropy. This value is also a hint for the size to supply if the core makes additional calls to `"add_entropy"`, for example to enforce prediction resistance. If omitted, the core should pass an amount of entropy corresponding to the expected security strength of the device (for example, pass 32 bytes of entropy when reseeding to achieve a security strength of 256 bits). If specified, the core should pass the larger of `"reseed_entropy_size"` and the amount corresponding to the security strength. + +Random generation is not parametrized by an algorithm. The choice of algorithm is up to the driver. + +#### Random generator initialization + +The `"init_random"` entry point has the following prototype for a driver with the prefix `"acme"`: + +``` +psa_status_t acme_init_random(acme_random_context_t *context); +``` + +The core calls this entry point once after allocating a random generation context. Initially, the context object is all-bits-zero. + +If a driver does not have an `"init_random"` entry point, the context object passed to the first call to `"add_entropy"` or `"get_random"` will be all-bits-zero. + +#### Entropy injection + +The `"add_entropy"` entry point has the following prototype for a driver with the prefix `"acme"`: + +``` +psa_status_t acme_add_entropy(acme_random_context_t *context, + const uint8_t *entropy, + size_t entropy_size); +``` + +The semantics of the parameters is as follows: + +* `context`: a random generation context. On the first call to `"add_entropy"`, this object has been initialized by a call to the driver's `"init_random"` entry point if one is present, and to all-bits-zero otherwise. +* `entropy`: a buffer containing full-entropy data to seed the random generator. “Full-entropy” means that the data is uniformly distributed and independent of any other observable quantity. +* `entropy_size`: the size of the `entropy` buffer in bytes. It is guaranteed to be at least `1`, but it may be smaller than the amount of entropy that the driver needs to deliver random data, in which case the core will call the `"add_entropy"` entry point again to supply more entropy. + +The core calls this function to supply entropy to the driver. The driver must mix this entropy into its internal state. The driver must mix the whole supplied entropy, even if there is more than what the driver requires, to ensure that all entropy sources are mixed into the random generator state. The driver may mix additional entropy of its own. + +The core may call this function at any time. For example, to enforce prediction resistance, the core can call `"add_entropy"` immediately after each call to `"get_random"`. The core must call this function in two circumstances: + +* Before the first call to the `"get_random"` entry point, to supply `"initial_entropy_size"` bytes of entropy. +* After a call to the `"get_random"` entry point returns less than the required amount of random data, to supply at least `"reseed_entropy_size"` bytes of entropy. + +When the driver requires entropy, the core can supply it with one or more successive calls to the `"add_entropy"` entry point. If the required entropy size is zero, the core does not need to call `"add_entropy"`. + +#### Combining entropy sources with a random generation driver + +This section provides guidance on combining one or more [entropy sources](#entropy-collection-entry-point) (each having a `"get_entropy"` entry point) with a random generation driver (with an `"add_entropy"` entry point). + +Note that `"get_entropy"` returns data with an estimated amount of entropy that is in general less than the buffer size. The core must apply a mixing algorithm to the output of `"get_entropy"` to obtain full-entropy data. + +For example, the core may use a simple mixing scheme based on a pseudorandom function family $(F_k)$ with an $E$-bit output where $E = 8 \cdot \mathtt{entropy_size}$ and $\mathtt{entropy_size}$ is the desired amount of entropy in bytes (typically the random driver's `"initial_entropy_size"` property for the initial seeding and the `"reseed_entropy_size"` property for subsequent reseeding). The core calls the `"get_entropy"` points of the available entropy drivers, outputting a string $s_i$ and an entropy estimate $e_i$ on the $i$th call. It does so until the total entropy estimate $e_1 + e_2 + \ldots + e_n$ is at least $E$. The core then calculates $F_k(0)$ where $k = s_1 || s_2 || \ldots || s_n$. This value is a string of $\mathtt{entropy_size}$, and since $(F_k)$ is a pseudorandom function family, $F_k(0)$ is uniformly distributed over strings of $\mathtt{entropy_size}$ bytes. Therefore $F_k(0)$ is a suitable value to pass to `"add_entropy"`. + +Note that the mechanism above is only given as an example. Implementations may choose a different mechanism, for example involving multiple pools or intermediate compression functions. + +#### Random generator drivers without entropy injection + +Random generator drivers should have the capability to inject additional entropy through the `"add_entropy"` entry point. This ensures that the random generator depends on all the entropy sources that are available on the platform. A driver where a call to `"add_entropy"` does not affect the state of the random generator is not compliant with this specification. + +However, a driver may omit the `"add_entropy"` entry point. This limits the driver's portability: implementations of the PSA Cryptography specification may reject drivers without an `"add_entropy"` entry point, or only accept such drivers in certain configurations. In particular, the `"add_entropy"` entry point is required if: + +* the integration of PSA Cryptography includes an entropy source that is outside the driver; or +* the core saves random data in persistent storage to be preserved across platform resets. + +#### The `"get_random"` entry point + +The `"get_random"` entry point has the following prototype for a driver with the prefix `"acme"`: + +``` +psa_status_t acme_get_random(acme_random_context_t *context, + uint8_t *output, + size_t output_size, + size_t *output_length); +``` + +The semantics of the parameters is as follows: + +* `context`: a random generation context. If the driver's `"initial_entropy_size"` property is nonzero, the core must have called `"add_entropy"` at least once with a total of at least `"initial_entropy_size"` bytes of entropy before it calls `"get_random"`. Alternatively, if the driver's `"initial_entropy_size"` property is zero and the core did not call `"add_entropy"`, or if the driver has no `"add_entropy"` entry point, the core must have called `"init_random"` if present, and otherwise the context is all-bits zero. +* `output`: on success (including partial success), the first `*output_length` bytes of this buffer contain cryptographic-quality random data. The output is not used on error. +* `output_size`: the size of the `output` buffer in bytes. +* `*output_length`: on success (including partial success), the number of bytes of random data that the driver has written to the `output` buffer. This is preferably `output_size`, but the driver is allowed to return less data if it runs out of entropy as described below. The core sets this value to 0 on entry. The value is not used on error. + +The driver may return the following status codes: + +* `PSA_SUCCESS`: the `output` buffer contains `*output_length` bytes of cryptographic-quality random data. Note that this may be less than `output_size`; in this case the core should call the driver's `"add_entropy"` method to supply at least `"reseed_entropy_size"` bytes of entropy before calling `"get_random"` again. +* `PSA_ERROR_INSUFFICIENT_ENTROPY`: the core must supply additional entropy by calling the `"add_entropy"` entry point with at least `"reseed_entropy_size"` bytes. +* `PSA_ERROR_NOT_SUPPORTED`: the random generator is not available. This is only permitted if the driver specification for random generation has the [fallback property](#fallback) enabled. +* Other error codes such as `PSA_ERROR_COMMUNICATION_FAILURE` or `PSA_ERROR_HARDWARE_FAILURE` indicate a transient or permanent error. + +### Fallback + +Sometimes cryptographic accelerators only support certain cryptographic mechanisms partially. The capability description language allows specifying some restrictions, including restrictions on key sizes, but it cannot cover all the possibilities that may arise in practice. Furthermore, it may be desirable to deploy the same binary image on different devices, only some of which have a cryptographic accelerators. +For these purposes, a transparent driver can declare that it only supports a [capability](#driver-description-capability) partially, by setting the capability's `"fallback"` property to true. + +If a transparent driver entry point is part of a capability which has a true `"fallback"` property and returns `PSA_ERROR_NOT_SUPPORTED`, the core will call the next transparent driver that supports the mechanism, if there is one. The core considers drivers in the order given by the [driver description list](#driver-description-list). + +If all the available drivers have fallback enabled and return `PSA_ERROR_NOT_SUPPORTED`, the core will perform the operation using built-in code. +As soon as a driver returns any value other than `PSA_ERROR_NOT_SUPPORTED` (`PSA_SUCCESS` or a different error code), this value is returned to the application, without attempting to call any other driver or built-in code. + +If a transparent driver entry point is part of a capability where the `"fallback"` property is false or omitted, the core should not include any other code for this capability, whether built in or in another transparent driver. + +## Opaque drivers + +Opaque drivers allow a PSA Cryptography implementation to delegate cryptographic operations to a separate environment that might not allow exporting key material in cleartext. The opaque driver interface is designed so that the core never inspects the representation of a key. The opaque driver interface is designed to support two subtypes of cryptoprocessors: + +* Some cryptoprocessors do not have persistent storage for individual keys. The representation of a key is the key material wrapped with a master key which is located in the cryptoprocessor and never exported from it. The core stores this wrapped key material on behalf of the cryptoprocessor. +* Some cryptoprocessors have persistent storage for individual keys. The representation of a key is an identifier such as label or slot number. The core stores this identifier. + +### Key format for opaque drivers + +The format of a key for opaque drivers is an opaque blob. The content of this blob is fully up to the driver. The core merely stores this blob. + +Note that since the core stores the key context blob as it is in memory, it must only contain data that is meaningful after a reboot. In particular, it must not contain any pointers or transient handles. + +The `"key_context"` property in the [driver description](#driver-description-top-level-element) specifies how to calculate the size of the key context as a function of the key type and size. This is an object with the following properties: + +* `"base_size"` (integer or string, optional): this many bytes are included in every key context. If omitted, this value defaults to 0. +* `"key_pair_size"` (integer or string, optional): this many bytes are included in every key context for a key pair. If omitted, this value defaults to 0. +* `"public_key_size"` (integer or string, optional): this many bytes are included in every key context for a public key. If omitted, this value defaults to 0. +* `"symmetric_factor"` (integer or string, optional): every key context for a symmetric key includes this many times the key size. If omitted, this value defaults to 0. +* `"store_public_key"` (boolean, optional): If specified and true, for a key pair, the key context includes space for the public key. If omitted or false, no additional space is added for the public key. +* `"size_function"` (string, optional): the name of a function that returns the number of bytes that the driver needs in a key context for a key. This may be a pointer to function. This must be a C identifier; more complex expressions are not permitted. If the core uses this function, it supersedes all the other properties except for `"builtin_key_size"` (where applicable, if present). +* `"builtin_key_size"` (integer or string, optional): If specified, this overrides all other methods (including the `"size_function"` entry point) to determine the size of the key context for [built-in keys](#built-in-keys). This allows drivers to efficiently represent application keys as wrapped key material, but built-in keys by an internal identifier that takes up less space. + +The integer properties must be C language constants. A typical value for `"base_size"` is `sizeof(acme_key_context_t)` where `acme_key_context_t` is a type defined in a driver header file. + +#### Size of a dynamically allocated key context + +If the core supports dynamic allocation for the key context and chooses to use it, and the driver specification includes the `"size_function"` property, the size of the key context is at least +``` +size_function(key_type, key_bits) +``` +where `size_function` is the function named in the `"size_function"` property, `key_type` is the key type and `key_bits` is the key size in bits. The prototype of the size function is +``` +size_t size_function(psa_key_type_t key_type, size_t key_bits); +``` + +#### Size of a statically allocated key context + +If the core does not support dynamic allocation for the key context or chooses not to use it, or if the driver specification does not include the `"size_function"` property, the size of the key context for a key of type `key_type` and of size `key_bits` bits is: + +* For a key pair (`PSA_KEY_TYPE_IS_KEY_PAIR(key_type)` is true): + ``` + base_size + key_pair_size + public_key_overhead + ``` + where `public_key_overhead = PSA_EXPORT_PUBLIC_KEY_MAX_SIZE(key_type, key_bits)` if the `"store_public_key"` property is true and `public_key_overhead = 0` otherwise. + +* For a public key (`PSA_KEY_TYPE_IS_PUBLIC_KEY(key_type)` is true): + ``` + base_size + public_key_size + ``` + +* For a symmetric key (not a key pair or public key): + ``` + base_size + symmetric_factor * key_bytes + ``` + where `key_bytes = ((key_bits + 7) / 8)` is the key size in bytes. + +#### Key context size for a secure element with storage + +If the key is stored in the secure element and the driver only needs to store a label for the key, use `"base_size"` as the size of the label plus any other metadata that the driver needs to store, and omit the other properties. + +If the key is stored in the secure element, but the secure element does not store the public part of a key pair and cannot recompute it on demand, additionally use the `"store_public_key"` property with the value `true`. Note that this only influences the size of the key context: the driver code must copy the public key to the key context and retrieve it on demand in its `export_public_key` entry point. + +#### Key context size for a secure element without storage + +If the key is stored in wrapped form outside the secure element, and the wrapped form of the key plus any metadata has up to *N* bytes of overhead, use *N* as the value of the `"base_size"` property and set the `"symmetric_factor"` property to 1. Set the `"key_pair_size"` and `"public_key_size"` properties appropriately for the largest supported key pair and the largest supported public key respectively. + +### Key management with opaque drivers + +Opaque drivers may provide the following key management entry points: + +* `"export_key"`: called by `psa_export_key()`, or by `psa_copy_key()` when copying a key from or to a different [location](#lifetimes-and-locations). +* `"export_public_key"`: called by the core to obtain the public key of a key pair. The core may call this entry point at any time to obtain the public key, which can be for `psa_export_public_key()` but also at other times, including during a cryptographic operation that requires the public key such as a call to `psa_verify_message()` on a key pair object. +* `"import_key"`: called by `psa_import_key()`, or by `psa_copy_key()` when copying a key from another location. +* `"generate_key"`: called by `psa_generate_key()`. +* `"key_derivation_output_key"`: called by `psa_key_derivation_output_key()`. +* `"copy_key"`: called by `psa_copy_key()` when copying a key within the same [location](#lifetimes-and-locations). +* `"get_builtin_key"`: called by functions that access a key to retrieve information about a [built-in key](#built-in-keys). + +In addition, secure elements that store the key material internally must provide the following two entry points: + +* `"allocate_key"`: called by `psa_import_key()`, `psa_generate_key()`, `psa_key_derivation_output_key()` or `psa_copy_key()` before creating a key in the location of this driver. +* `"destroy_key"`: called by `psa_destroy_key()`. + +#### Key creation in a secure element without storage + +This section describes the key creation process for secure elements that do not store the key material. The driver must obtain a wrapped form of the key material which the core will store. A driver for such a secure element has no `"allocate_key"` or `"destroy_key"` entry point. + +When creating a key with an opaque driver which does not have an `"allocate_key"` or `"destroy_key"` entry point: + +1. The core allocates memory for the key context. +2. The core calls the driver's import, generate, derive or copy entry point. +3. The core saves the resulting wrapped key material and any other data that the key context may contain. + +To destroy a key, the core simply destroys the wrapped key material, without invoking driver code. + +#### Key management in a secure element with storage + +This section describes the key creation and key destruction processes for secure elements that have persistent storage for the key material. A driver for such a secure element has two mandatory entry points: + +* `"allocate_key"`: this function obtains an internal identifier for the key. This may be, for example, a unique label or a slot number. +* `"destroy_key"`: this function invalidates the internal identifier and destroys the associated key material. + +These functions have the following prototypes for a driver with the prefix `"acme"`: +``` +psa_status_t acme_allocate_key(const psa_key_attributes_t *attributes, + uint8_t *key_buffer, + size_t key_buffer_size); +psa_status_t acme_destroy_key(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size); +``` + +When creating a persistent key with an opaque driver which has an `"allocate_key"` entry point: + +1. The core calls the driver's `"allocate_key"` entry point. This function typically allocates an internal identifier for the key without modifying the state of the secure element and stores the identifier in the key context. This function should not modify the state of the secure element. It may modify the copy of the persistent state of the driver in memory. + +1. The core saves the key context to persistent storage. + +1. The core calls the driver's key creation entry point. + +1. The core saves the updated key context to persistent storage. + +If a failure occurs after the `"allocate_key"` step but before the call to the second driver entry point, the core will do one of the following: + +* Fail the creation of the key without indicating this to the driver. This can happen, in particular, if the device loses power immediately after the key allocation entry point returns. +* Call the driver's `"destroy_key"` entry point. + +To destroy a key, the core calls the driver's `"destroy_key"` entry point. + +Note that the key allocation and destruction entry points must not rely solely on the key identifier in the key attributes to identify a key. Some implementations of the PSA Cryptography API store keys on behalf of multiple clients, and different clients may use the same key identifier to designate different keys. The manner in which the core distinguishes keys that have the same identifier but are part of the key namespace for different clients is implementation-dependent and is not accessible to drivers. Some typical strategies to allocate an internal key identifier are: + +* Maintain a set of free slot numbers which is stored either in the secure element or in the driver's persistent storage. To allocate a key slot, find a free slot number, mark it as occupied and store the number in the key context. When the key is destroyed, mark the slot number as free. +* Maintain a monotonic counter with a practically unbounded range in the secure element or in the driver's persistent storage. To allocate a key slot, increment the counter and store the current value in the key context. Destroying a key does not change the counter. + +TODO: explain constraints on how the driver updates its persistent state for resilience + +TODO: some of the above doesn't apply to volatile keys + +#### Key creation entry points in opaque drivers + +The key creation entry points have the following prototypes for a driver with the prefix `"acme"`: + +``` +psa_status_t acme_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length, + size_t *bits); +psa_status_t acme_generate_key(const psa_key_attributes_t *attributes, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length); +``` + +If the driver has an [`"allocate_key"` entry point](#key-management-in-a-secure-element-with-storage), the core calls the `"allocate_key"` entry point with the same attributes on the same key buffer before calling the key creation entry point. + +TODO: derivation, copy + +#### Key export entry points in opaque drivers + +The key export entry points have the following prototypes for a driver with the prefix `"acme"`: + +``` +psa_status_t acme_export_key(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *data, + size_t data_size, + size_t *data_length); +psa_status_t acme_export_public_key(const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, + size_t key_buffer_size, + uint8_t *data, + size_t data_size, + size_t *data_length); +``` + +The core will only call `acme_export_public_key` on a private key. Drivers implementers may choose to store the public key in the key context buffer or to recalculate it on demand. If the key context includes the public key, it needs to have an adequate size; see [“Key format for opaque drivers”](#key-format-for-opaque-drivers). + +The core guarantees that the size of the output buffer (`data_size`) is sufficient to export any key with the given attributes. The driver must set `*data_length` to the exact size of the exported key. + +### Opaque driver persistent state + +The core maintains persistent state on behalf of an opaque driver. This persistent state consists of a single byte array whose size is given by the `"persistent_state_size"` property in the [driver description](#driver-description-top-level-element). + +The core loads the persistent state in memory before it calls the driver's [init entry point](#driver-initialization). It is adjusted to match the size declared by the driver, in case a driver upgrade changes the size: + +* The first time the driver is loaded on a system, the persistent state is all-bits-zero. +* If the stored persistent state is smaller than the declared size, the core pads the persistent state with all-bits-zero at the end. +* If the stored persistent state is larger than the declared size, the core truncates the persistent state to the declared size. + +The core provides the following callback functions, which an opaque driver may call while it is processing a call from the driver: +``` +psa_status_t psa_crypto_driver_get_persistent_state(uint_8_t **persistent_state_ptr); +psa_status_t psa_crypto_driver_commit_persistent_state(size_t from, size_t length); +``` + +`psa_crypto_driver_get_persistent_state` sets `*persistent_state_ptr` to a pointer to the first byte of the persistent state. This pointer remains valid during a call to a driver entry point. Once the entry point returns, the pointer is no longer valid. The core guarantees that calls to `psa_crypto_driver_get_persistent_state` within the same entry point return the same address for the persistent state, but this address may change between calls to an entry point. + +`psa_crypto_driver_commit_persistent_state` updates the persistent state in persistent storage. Only the portion at byte offsets `from` inclusive to `from + length` exclusive is guaranteed to be updated; it is unspecified whether changes made to other parts of the state are taken into account. The driver must call this function after updating the persistent state in memory and before returning from the entry point, otherwise it is unspecified whether the persistent state is updated. + +The core will not update the persistent state in storage while an entry point is running except when the entry point calls `psa_crypto_driver_commit_persistent_state`. It may update the persistent state in storage after an entry point returns. + +In a multithreaded environment, the driver may only call these two functions from the thread that is executing the entry point. + +#### Built-in keys + +Opaque drivers may declare built-in keys. Built-in keys can be accessed, but not created, through the PSA Cryptography API. + +A built-in key is identified by its location and its **slot number**. Drivers that support built-in keys must provide a `"get_builtin_key"` entry point to retrieve the key data and metadata. The core calls this entry point when it needs to access the key, typically because the application requested an operation on the key. The core may keep information about the key in cache, and successive calls to access the same slot number should return the same data. This entry point has the following prototype: + +``` +psa_status_t acme_get_builtin_key(psa_drv_slot_number_t slot_number, + psa_key_attributes_t *attributes, + uint8_t *key_buffer, + size_t key_buffer_size, + size_t *key_buffer_length); +``` + +If this function returns `PSA_SUCCESS` or `PSA_ERROR_BUFFER_TOO_SMALL`, it must fill `attributes` with the attributes of the key (except for the key identifier). On success, this function must also fill `key_buffer` with the key context. + +On entry, `psa_get_key_lifetime(attributes)` is the location at which the driver was declared and a persistence level with which the platform is attempting to register the key. The driver entry point may choose to change the lifetime (`psa_set_key_lifetime(attributes, lifetime)`) of the reported key attributes to one with the same location but a different persistence level, in case the driver has more specific knowledge about the actual persistence level of the key which is being retrieved. For example, if a driver knows it cannot delete a key, it may override the persistence level in the lifetime to `PSA_KEY_PERSISTENCE_READ_ONLY`. The standard attributes other than the key identifier and lifetime have the value conveyed by `PSA_KEY_ATTRIBUTES_INIT`. + +The output parameter `key_buffer` points to a writable buffer of `key_buffer_size` bytes. If the driver has a [`"builtin_key_size"` property](#key-format-for-opaque-drivers) property, `key_buffer_size` has this value, otherwise `key_buffer_size` has the value determined from the key type and size. + +Typically, for a built-in key, the key context is a reference to key material that is kept inside the secure element, similar to the format returned by [`"allocate_key"`](#key-management-in-a-secure-element-with-storage). A driver may have built-in keys even if it doesn't have an `"allocate_key"` entry point. + +This entry point may return the following status values: + +* `PSA_SUCCESS`: the requested key exists, and the output parameters `attributes` and `key_buffer` contain the key metadata and key context respectively, and `*key_buffer_length` contains the length of the data written to `key_buffer`. +* `PSA_ERROR_BUFFER_TOO_SMALL`: `key_buffer_size` is insufficient. In this case, the driver must pass the key's attributes in `*attributes`. In particular, `get_builtin_key(slot_number, &attributes, NULL, 0)` is a way for the core to obtain the key's attributes. +* `PSA_ERROR_DOES_NOT_EXIST`: the requested key does not exist. +* Other error codes such as `PSA_ERROR_COMMUNICATION_FAILURE` or `PSA_ERROR_HARDWARE_FAILURE` indicate a transient or permanent error. + +The core will pass authorized requests to destroy a built-in key to the [`"destroy_key"`](#key-management-in-a-secure-element-with-storage) entry point if there is one. If built-in keys must not be destroyed, it is up to the driver to reject such requests. + +## How to use drivers from an application + +### Using transparent drivers + +Transparent drivers linked into the library are automatically used for the mechanisms that they implement. + +### Using opaque drivers + +Each opaque driver is assigned a [location](#lifetimes-and-locations). The driver is invoked for all actions that use a key in that location. A key's location is indicated by its lifetime. The application chooses the key's lifetime when it creates the key. + +For example, the following snippet creates an AES-GCM key which is only accessible inside the secure element designated by the location `PSA_KEY_LOCATION_acme`. +``` +psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; +psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( + PSA_KEY_PERSISTENCE_DEFAULT, PSA_KEY_LOCATION_acme)); +psa_set_key_identifier(&attributes, 42); +psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); +psa_set_key_size(&attributes, 128); +psa_set_key_algorithm(&attributes, PSA_ALG_GCM); +psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); +psa_key_id_t key; +psa_generate_key(&attributes, &key); +``` + +## Using opaque drivers from an application + +### Lifetimes and locations + +The PSA Cryptography API, version 1.0.0, defines [lifetimes](https://armmbed.github.io/mbed-crypto/html/api/keys/attributes.html?highlight=psa_key_lifetime_t#c.psa_key_lifetime_t) as an attribute of a key that indicates where the key is stored and which application and system actions will create and destroy it. The lifetime is expressed as a 32-bit value (`typedef uint32_t psa_key_lifetime_t`). An upcoming version of the PSA Cryptography API defines more structure for lifetime values to separate these two aspects of the lifetime: + +* Bits 0–7 are a _persistence level_. This value indicates what device management actions can cause it to be destroyed. In particular, it indicates whether the key is volatile or persistent. +* Bits 8–31 are a _location indicator_. This value indicates where the key material is stored and where operations on the key are performed. Location values can be stored in a variable of type `psa_key_location_t`. + +An opaque driver is attached to a specific location. Keys in the default location (`PSA_KEY_LOCATION_LOCAL_STORAGE = 0`) are transparent: the core has direct access to the key material. For keys in a location that is managed by an opaque driver, only the secure element has access to the key material and can perform operations on the key, while the core only manipulates a wrapped form of the key or an identifier of the key. + +### Creating a key in a secure element + +The core defines a compile-time constant for each opaque driver indicating its location called `PSA_KEY_LOCATION_`*prefix* where *prefix* is the value of the `"prefix"` property in the driver description. For convenience, Mbed TLS also declares a compile-time constant for the corresponding lifetime with the default persistence called `PSA_KEY_LIFETIME_`*prefix*. Therefore, to declare an opaque key in the location with the prefix `foo` with the default persistence, call `psa_set_key_lifetime` during the key creation as follows: +``` +psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_foo); +``` + +To declare a volatile key: +``` +psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( + PSA_KEY_LOCATION_foo, + PSA_KEY_PERSISTENCE_VOLATILE)); +``` + +Generally speaking, to declare a key with a specified persistence: +``` +psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( + PSA_KEY_LOCATION_foo, + persistence)); +``` + +## Open questions + +### Value representation + +#### Integers + +It would be better if there was a uniform requirement on integer values. Do they have to be JSON integers? C preprocessor integers (which could be e.g. a macro defined in some header file)? C compile-time constants (allowing `sizeof`)? + +This choice is partly driven by the use of the values, so they might not be uniform. Note that if the value can be zero and it's plausible that the core would want to statically allocate an array of the given size, the core needs to know whether the value is 0 so that it could use code like +``` +#if ACME_FOO_SIZE != 0 + uint8_t foo[ACME_FOO_SIZE]; +#endif +``` + +### Driver declarations + +#### Declaring driver entry points + +The core may want to provide declarations for the driver entry points so that it can compile code using them. At the time of writing this paragraph, the driver headers must define types but there is no obligation for them to declare functions. The core knows what the function names and argument types are, so it can generate prototypes. + +It should be ok for driver functions to be function-like macros or function pointers. + +#### Driver location values + +How does a driver author decide which location values to use? It should be possible to combine drivers from different sources. Use the same vendor assignment as for PSA services? + +Can the driver assembly process generate distinct location values as needed? This can be convenient, but it's also risky: if you upgrade a device, you need the location values to be the same between builds. + +The current plan is for Arm to maintain a registry of vendors and assign a location namespace to each vendor. Parts of the namespace would be reserved for implementations and integrators. + +#### Multiple transparent drivers + +When multiple transparent drivers implement the same mechanism, which one is called? The first one? The last one? Unspecified? Or is this an error (excluding capabilities with fallback enabled)? + +The current choice is that the first one is used, which allows having a preference order on drivers, but may mask integration errors. + +### Driver function interfaces + +#### Driver function parameter conventions + +Should 0-size buffers be guaranteed to have a non-null pointers? + +Should drivers really have to cope with overlap? + +Should the core guarantee that the output buffer size has the size indicated by the applicable buffer size macro (which may be an overestimation)? + +### Partial computations in drivers + +#### Substitution points + +Earlier drafts of the driver interface had a concept of _substitution points_: places in the calculation where a driver may be called. Some hardware doesn't do the whole calculation, but only the “main” part. This goes both for transparent and opaque drivers. Some common examples: + +* A processor that performs the RSA exponentiation, but not the padding. The driver should be able to leverage the padding code in the core. +* A processor that performs a block cipher operation only for a single block, or only in ECB mode, or only in CTR mode. The core would perform the block mode (CBC, CTR, CCM, ...). + +This concept, or some other way to reuse portable code such as specifying inner functions like `psa_rsa_pad` in the core, should be added to the specification. + +### Key management + +#### Mixing drivers in key derivation + +How does `psa_key_derivation_output_key` work when the extraction part and the expansion part use different drivers? + +#### Public key calculation + +ECC key pairs are represented as the private key value only. The public key needs to be calculated from that. Both transparent drivers and opaque drivers provide a function to calculate the public key (`"export_public_key"`). + +The specification doesn't mention when the public key might be calculated. The core may calculate it on creation, on demand, or anything in between. Opaque drivers have a choice of storing the public key in the key context or calculating it on demand and can convey whether the core should store the public key with the `"store_public_key"` property. Is this good enough or should the specification include non-functional requirements? + +#### Symmetric key validation with transparent drivers + +Should the entry point be called for symmetric keys as well? + +#### Support for custom import formats + +[“Driver entry points for key management”](#driver-entry-points-for-key-management) states that the input to `"import_key"` can be an implementation-defined format. Is this a good idea? It reduces driver portability, since a core that accepts a custom format would not work with a driver that doesn't accept this format. On the other hand, if a driver accepts a custom format, the core should let it through because the driver presumably handles it more efficiently (in terms of speed and code size) than the core could. + +Allowing custom formats also causes a problem with import: the core can't know the size of the key representation until it knows the bit-size of the key, but determining the bit-size of the key is part of the job of the `"import_key"` entry point. For standard key types, this could plausibly be an issue for RSA private keys, where an implementation might accept a custom format that omits the CRT parameters (or that omits *d*). + +### Opaque drivers + +#### Opaque driver persistent state + +The driver is allowed to update the state at any time. Is this ok? + +An example use case for updating the persistent state at arbitrary times is to renew a key that is used to encrypt communications between the application processor and the secure element. + +`psa_crypto_driver_get_persistent_state` does not identify the calling driver, so the driver needs to remember which driver it's calling. This may require a thread-local variable in a multithreaded core. Is this ok? + +### Randomness + +#### Input to `"add_entropy"` + +Should the input to the [`"add_entropy"` entry point](#entropy-injection) be a full-entropy buffer (with data from all entropy sources already mixed), raw entropy direct from the entropy sources, or give the core a choice? + +* Raw data: drivers must implement entropy mixing. `"add_entropy"` needs an extra parameter to indicate the amount of entropy in the data. The core must not do any conditioning. +* Choice: drivers must implement entropy mixing. `"add_entropy"` needs an extra parameter to indicate the amount of entropy in the data. The core may do conditioning if it wants, but doesn't have to. +* Full entropy: drivers don't need to do entropy mixing. + +#### Flags for `"get_entropy"` + +Are the [entropy collection flags](#entropy-collection-flags) well-chosen? + +#### Random generator instantiations + +May the core instantiate a random generation context more than once? In other words, can there be multiple objects of type `acme_random_context_t`? + +Functionally, one RNG is as good as any. If the core wants some parts of the system to use a deterministic generator for reproducibility, it can't use this interface anyway, since the RNG is not necessarily deterministic. However, for performance on multiprocessor systems, a multithreaded core could prefer to use one RNG instance per thread. + + -- cgit v1.2.3