From 51977355dcd5dd2b3ddd11215c68ebc519ae9de0 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 7 Dec 2020 16:59:59 +0100 Subject: [PATCH 01/19] Remove the time stamp Having a time stamp identifying each revision of the document is useful, but it's also a pain because it creates a conflict whenever there are multiple pending changes at the same time. The gain isn't worth the pain, so I'm removing the time stamp. Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index d82579462..cdd2f0fb2 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -5,8 +5,6 @@ This document describes an interface for cryptoprocessor drivers in the PSA cryp 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. -Time-stamp: "2020/11/24 11:03:32 GMT" - ## Introduction ### Purpose of the driver interface From e80978a260bb499d82fb3289f9d7fcde0c4f2436 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 13:07:14 +0100 Subject: [PATCH 02/19] Specification for random generation and entropy drivers Transparent drivers may provide a DRBG interface through "add_entropy" and "get_random" entry points. This interface may also be used with a non-deterministic generator, for chips that include a TRNG. Opaque driver may provide a "get_entropy" entry point. Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 125 ++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index cdd2f0fb2..c6858201c 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -194,6 +194,8 @@ The signature of a driver entry point generally looks like the signature of the 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. For transparent drivers, these are [random generation entry points](#random-generation-entry-points). For opaque drivers, these are [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: @@ -426,6 +428,90 @@ This entry point has several roles: 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 allows it to generate random data. 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 must be able to incorporate entropy provided by an outside source. +* 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"` (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): the core calls this function to [inject entropy](#entropy-injection). +* `"get_random"` (entry point): the core calls this function whenever it needs to [obtain random data](#the-get_random-entry-point). +* `"initial_entropy_size"` (integer): the minimum number of bytes of entropy that the core must supply before the driver can output random data. +* `"reseed_entropy_size"` (integer): the minimum number of bytes of entropy that the core must supply when the driver runs out of entropy. + +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"` 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 high-entropy data to seed the random generator. +* `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 any 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 `"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. + +#### 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. 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"`. +* `output`: on success or partial success, the first `*output_length` bytes of this buffer contain cryptographic-quality random data. +* `output_size`: the size of the `output` buffer in bytes. +* `*output_length`: on exit, 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 driver may return the following status codes: + +* `PSA_SUCCESS`: the `output` buffer contains `*output_length` bytes of random data. +* `PSA_ERROR_INSUFFICIENT_ENTROPY`: the core must supply additional entropy by calling the `"add_entropy"` entry point with at least `"reseed_entropy_size"` bytes. In this case, if `*output_length` is nonzero, the core will use the first `*output_length` bytes of the `output` buffer as random data, and will call `"get_random"` again for the remaining `output_size - *output_length` bytes after calling `"add_entropy"`. +* `PSA_ERROR_NOT_SUPPORTED`: the random generator is not available. The core will not use the content of `output` or `output_length`. 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. The core will not use the content of `output` or `output_length`. + ### 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. @@ -620,6 +706,45 @@ The core will only call `acme_export_public_key` on a private key. Drivers imple 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. +### Entropy collection entry point + +An opaque driver can declare an entropy source by providing a `"get_entropy"` entry point. This entry point has the following prototypes 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. +* `output`: on success, this buffer contains non-deterministic data with an estimated entropy of at least `*estimate_bits` bits. +* `output_size`: the size of the `output` buffer in bytes. + +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` is clear. +* Other error codes indicate a transient or permanent failure of the entropy source. + +#### 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`: 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. + ### 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). From 5263e1ecdd1e5d09eeb39d26913da3ec16570fe0 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 14:14:28 +0100 Subject: [PATCH 03/19] Transparent drivers can have get_entropy as well The `get_entropy` entry point can be provided by multiple transparent drivers, and the core will call all of them. But apart from that, `get_entropy` doesn't involve an opaque key or a location, so it can be in a transparent driver. Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 82 ++++++++++++++------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index c6858201c..b036ccbf7 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -194,7 +194,7 @@ The signature of a driver entry point generally looks like the signature of the 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. For transparent drivers, these are [random generation entry points](#random-generation-entry-points). For opaque drivers, these are [entropy collection entry points](#entropy-collection-entry-point). +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 @@ -375,6 +375,47 @@ This section describes some minimal validity requirements for standard key types * 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 prototypes 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. +* `output`: on success, this buffer contains non-deterministic data with an estimated entropy of at least `*estimate_bits` bits. +* `output_size`: the size of the `output` buffer in bytes. + +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` is clear. +* 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`: 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 @@ -706,45 +747,6 @@ The core will only call `acme_export_public_key` on a private key. Drivers imple 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. -### Entropy collection entry point - -An opaque driver can declare an entropy source by providing a `"get_entropy"` entry point. This entry point has the following prototypes 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. -* `output`: on success, this buffer contains non-deterministic data with an estimated entropy of at least `*estimate_bits` bits. -* `output_size`: the size of the `output` buffer in bytes. - -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` is clear. -* Other error codes indicate a transient or permanent failure of the entropy source. - -#### 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`: 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. - ### 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). From 0e3b7ced4cf5e2bc1f047e8cd271f8a8c11d5744 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 14:20:03 +0100 Subject: [PATCH 04/19] Don't require a call to add_entropy when 0 bytes are needed If an RNG peripheral includes an entropy source, it would presumably declare "initial_entropy_size" and "reseed_entropy_size" to be 0. In this case, don't require the core to call "add_entropy". Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index b036ccbf7..c80b406be 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -486,8 +486,8 @@ This operation family requires the following type, entry points and parameters ( * `"init_random"` (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): the core calls this function to [inject entropy](#entropy-injection). * `"get_random"` (entry point): the core calls this function whenever it needs to [obtain random data](#the-get_random-entry-point). -* `"initial_entropy_size"` (integer): the minimum number of bytes of entropy that the core must supply before the driver can output random data. -* `"reseed_entropy_size"` (integer): the minimum number of bytes of entropy that the core must supply when the driver runs out of entropy. +* `"initial_entropy_size"` (integer): 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 includes an entropy source of its own. +* `"reseed_entropy_size"` (integer): the minimum number of bytes of entropy that the core must supply when the driver runs out of entropy. This can be `0` if the driver includes an entropy source of its own. Random generation is not parametrized by an algorithm. The choice of algorithm is up to the driver. @@ -501,7 +501,7 @@ 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"` will be 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 @@ -526,7 +526,7 @@ The core may call this function at any time. For example, to enforce prediction * Before any 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 `"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. +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"`. #### The `"get_random"` entry point @@ -541,7 +541,7 @@ psa_status_t acme_get_random(acme_random_context_t *context, The semantics of the parameters is as follows: -* `context`: a random generation context. 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"`. +* `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"`, the core must have called `"init_random"` if present, and otherwise the context is all-bits zero. * `output`: on success or partial success, the first `*output_length` bytes of this buffer contain cryptographic-quality random data. * `output_size`: the size of the `output` buffer in bytes. * `*output_length`: on exit, 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. From 390c5a2c6fa8aa1a332ba9d48cf8ac946b673366 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 14:27:43 +0100 Subject: [PATCH 05/19] It is not meaningful for reseed_entropy_size to be 0 Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index c80b406be..cc1f45529 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -483,11 +483,11 @@ If no driver implements the random generation entry point family, the core provi 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"` (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): the core calls this function to [inject entropy](#entropy-injection). -* `"get_random"` (entry point): the core calls this function whenever it needs to [obtain random data](#the-get_random-entry-point). -* `"initial_entropy_size"` (integer): 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 includes an entropy source of its own. -* `"reseed_entropy_size"` (integer): the minimum number of bytes of entropy that the core must supply when the driver runs out of entropy. This can be `0` if the driver includes an entropy source of its own. +* `"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, mandatory): the core calls this function to [inject entropy](#entropy-injection). +* `"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, optional): 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 includes an entropy source of its own. If omitted, the value is `0`. +* `"reseed_entropy_size"` (integer, optional): the minimum number of bytes of entropy that the core must supply 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 chooses a value which is at least the expected security strength of the device. Random generation is not parametrized by an algorithm. The choice of algorithm is up to the driver. From a14326f054e0bec64ff7196197f5c509e0bdbf10 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 13 Nov 2020 14:40:57 +0100 Subject: [PATCH 06/19] Make add_entropy optional A random generation driver does not need to support entropy injection. This will limit it to platforms where the RNG peripheral is the sole entropy source and without an RNG seed saved into persistent storage. Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index cc1f45529..38b5953b6 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -484,9 +484,9 @@ This operation family requires the following type, entry points and parameters ( * 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, mandatory): the core calls this function to [inject entropy](#entropy-injection). +* `"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. * `"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, optional): 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 includes an entropy source of its own. If omitted, the value is `0`. +* `"initial_entropy_size"` (integer, optional): 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. If omitted, the value is `0`. * `"reseed_entropy_size"` (integer, optional): the minimum number of bytes of entropy that the core must supply 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 chooses a value which is at least the expected security strength of the device. Random generation is not parametrized by an algorithm. The choice of algorithm is up to the driver. @@ -528,6 +528,15 @@ The core may call this function at any time. For example, to enforce prediction 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"`. +#### 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"`: @@ -541,7 +550,7 @@ psa_status_t acme_get_random(acme_random_context_t *context, 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"`, the core must have called `"init_random"` if present, and otherwise the context is all-bits zero. +* `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 or partial success, the first `*output_length` bytes of this buffer contain cryptographic-quality random data. * `output_size`: the size of the `output` buffer in bytes. * `*output_length`: on exit, 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. From 05ab2646a3223bffc2d2d20038b8d2c6dc500c70 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 16 Nov 2020 21:46:40 +0100 Subject: [PATCH 07/19] get_entropy: recommendations on the output_size Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index 38b5953b6..0e6d46aa1 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -391,7 +391,9 @@ 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. * `output`: on success, this buffer contains non-deterministic data with an estimated entropy of at least `*estimate_bits` bits. -* `output_size`: the size of the `output` buffer in bytes. +* `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: From b89b4b90253b54ad1f4806272e14101e10100fcf Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 16 Nov 2020 21:52:21 +0100 Subject: [PATCH 08/19] get_entropy: recommendations on conditioning and entropy estimates Explicitly recommend that the driver accounts for environmental conditions that can affect the amount of entropy. Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index 0e6d46aa1..3b46084ae 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -389,8 +389,8 @@ psa_status_t acme_get_entropy(uint32_t flags, 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. -* `output`: on success, this buffer contains non-deterministic data with an estimated entropy of at least `*estimate_bits` bits. +* `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, excessive 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`. @@ -398,7 +398,7 @@ Note that there is no output parameter indicating how many bytes the driver wrot 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` is clear. +* `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"`. From 3eb65fbba6d4443f6a3e17e02432d6c5d2a0f50d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 16 Nov 2020 21:53:16 +0100 Subject: [PATCH 09/19] Open question: should add_entropy take an estimated_entropy_bits parameter? Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index 3b46084ae..9b98406a4 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -915,6 +915,16 @@ An example use case for updating the persistent state at arbitrary times is to r `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. +