From 22270b5048ff70813e8141924aad718d8fbfe23c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 18 Sep 2020 22:54:51 +0200 Subject: [PATCH 01/10] Fix copypasta punctuation in some function prototypes 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 56e2b29e9..f28e9a8ac 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -5,7 +5,7 @@ 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/08/19 19:47:39 GMT" +Time-stamp: "2020/09/18 20:35:28 GMT" ## Introduction @@ -520,13 +520,13 @@ The key export entry points have the following prototypes for a driver with the ``` psa_status_t acme_export_key(const psa_key_attributes_t *attributes, const uint8_t *key_buffer, - size_t key_buffer_size); + 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); + size_t key_buffer_size, uint8_t *data, size_t data_size, size_t *data_length); From 27e69b59a574f82b05b5a0f9ab3bafedd876f7a6 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 19 Sep 2020 00:35:01 +0200 Subject: [PATCH 02/10] Fix prototypes of opaque key creation entry points The output length parameter was missing. Reported by Steven Cooreman. Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index f28e9a8ac..c7dbed3b6 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -5,7 +5,7 @@ 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/09/18 20:35:28 GMT" +Time-stamp: "2020/09/18 22:34:47 GMT" ## Introduction @@ -503,10 +503,12 @@ 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_size, + size_t *key_buffer_length); 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_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. From a8fc171418cd5f65230f27676a57045998c527cf Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 21 Sep 2020 13:54:00 +0200 Subject: [PATCH 03/10] Add validate_key entry point Validate transparent keys when they are imported. Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 37 ++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index c7dbed3b6..475d3f979 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -5,7 +5,7 @@ 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/09/18 22:34:47 GMT" +Time-stamp: "2020/09/21 11:53:38 GMT" ## Introduction @@ -339,11 +339,32 @@ The format of a key for transparent drivers is the same as in applications. Refe Transparent drivers may provide the following key management entry points: -* `"generate_key"`: called by `psa_generate_key()`, only when generating a key pair (key such that `PSA_KEY_TYPE_IS_ASYMMETRIC` 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_ASYMMETRIC` is true). +* [`"validate_key"`](#key-validation-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 importing, exporting, copying or destroying keys, or when generating or deriving symmetric keys. +Transparent drivers are not involved when exporting, copying or destroying keys, or when importing, generating or deriving symmetric keys. + +#### Key validation with transparent drivers + +When a driver creates a key, it is responsible for ensuring that the key is valid. But when a key is imported, no processing of the key happens: the implementation just stores the key material. (It may store it in an encoded form, but this is an implementation choice which is not visible at the level of PSA specifications.) It is important to validate the incoming key material, to avoid storing a key that will later be unacceptable for operations or that could even cause functional or security issues during operations. + +To avoid delayed problems caused by imported invalid keys, an implementation that supports transparent drivers must validate transparent keys on import. For supported key types, this means: + +* 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 (``), check the size and range, and that the point is on the curve. TODO: what else? + +A driver can provide code to perform the required validation by providing a `"validate_key"` entry point. This entry points returns `PSA_SUCCESS` if the key is valid or an applicable error code if it isn't. + +``` +psa_status_t psa_validate_key(const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length); +``` ### Fallback @@ -675,6 +696,14 @@ ECC key pairs are represented as the private key value only. The public key need 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? + +#### Key validation with opaque drivers + +Are there mandatory validations that an opaque driver must perform on import? + ### Opaque drivers #### Opaque driver persistent state From 233f91d5c1d2b9e2fd52ccc0cccdfd3401f36115 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 2 Oct 2020 17:48:04 +0200 Subject: [PATCH 04/10] Add bits output to validate_key and import_key When importing a key, the code that parses the input needs to determine the key size ("bits" attribute). This is specific to import since other key creation methods require the caller to supply a size. Therefore, add an extra output parameter `bits` to the "import_key" entry point for opaque drivers. Likewise, add a `bits` output parameter to the "validate_key" entry point for transparent drivers. Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 42 +++++++++++++++++++++------ 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index 475d3f979..7e4d751fc 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -5,7 +5,7 @@ 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/09/21 11:53:38 GMT" +Time-stamp: "2020/10/02 15:59:46 GMT" ## Introduction @@ -360,10 +360,22 @@ To avoid delayed problems caused by imported invalid keys, an implementation tha A driver can provide code to perform the required validation by providing a `"validate_key"` entry point. This entry points returns `PSA_SUCCESS` if the key is valid or an applicable error code if it isn't. +The `"validate_key"` entry point has an additional role, which is to determine the size of a key. +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 may be `0`, which indicates that the size must be calculated from the data. +In this case, the core will call the `"validate_key"` entry point with an `attributes` structure such that `psa_get_key_bits(attributes)` returns 0, and the `"validate_key"` entry point must return the actual key size in the `bits` output parameter. +The semantics of `bits` is as follows: + +* The core sets `*bits` to `psa_get_key_bits(attributes)` before calling the `"validate_key"` entry point. +* If `*bits == 0`, the driver must determine the key size from the data, and return `PSA_ERROR_INVALID_ARGUMENT` if this is not possible. +* If `*bits != 0`, the driver may either determine the key size from the data and store it in `*bits`, or check the value of `*bits*` against the data and return an error if it does not match. +* If the `"validate_key"` entry point returns `PSA_SUCCESS`, but `psa_get_key_bits(attributes) != 0` and `psa_get_key_bits(attributes) != *bits` on output, the core considers the key as invalid due to the size mismatch. + ``` -psa_status_t psa_validate_key(const psa_key_attributes_t *attributes, - const uint8_t *data, - size_t data_length); +psa_status_t acme_validate_key(const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + size_t *bits); ``` ### Fallback @@ -525,7 +537,8 @@ psa_status_t acme_import_key(const psa_key_attributes_t *attributes, size_t data_length, uint8_t *key_buffer, size_t key_buffer_size, - size_t *key_buffer_length); + 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, @@ -536,6 +549,21 @@ If the driver has an [`"allocate_key"` entry point](#key-management-in-a-secure- TODO: derivation, copy +#### Key validation and size on import + +The `"import_key"` entry point must validate the key so that if a key is imported successfully, permitted operations on the key will succeed if the input data is valid and enough resources are available. For key types that are defined in the PSA Cryptography specification, opaque drivers must guarantee the properties that transparent drivers guarantee if [`"validate_key"`](#key-validation-with-transparent-drivers) succeeds. + +Rationale: The key must be validated on import to provide in-time feedback when attempting to inject a bad key. The minimum requirement for validation is the same as for `"validate_key"` to set a minimum security baseline (especially for operations such as key agreement where accepting an invalid key could result in leaking secret material). + +The `"import_key"` entry point may need to determine 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 may be `0`, which indicates that the size must be calculated from the data. +In this case, the core will call the `"import_key"` entry point with an `attributes` structure such that `psa_get_key_bits(attributes)` returns 0, and the `"import_key"` entry point must return the actual key size in the `bits` output parameter. 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 return `PSA_ERROR_INVALID_ARGUMENT` if this is not possible. +* If `*bits != 0`, the driver must check the value of `*bits*` against the data and return an error if it does not match. + #### Key export entry points in opaque drivers The key export entry points have the following prototypes for a driver with the prefix `"acme"`: @@ -700,10 +728,6 @@ The specification doesn't mention when the public key might be calculated. The c Should the entry point be called for symmetric keys as well? -#### Key validation with opaque drivers - -Are there mandatory validations that an opaque driver must perform on import? - ### Opaque drivers #### Opaque driver persistent state From e4cbb2bb73d37fa3b523dd28afc3fd6a164060a6 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 12 Oct 2020 23:39:18 +0200 Subject: [PATCH 05/10] Minor clarifications Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index 7e4d751fc..ef92c693b 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -5,7 +5,7 @@ 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/10/02 15:59:46 GMT" +Time-stamp: "2020/10/12 21:34:43 GMT" ## Introduction @@ -348,9 +348,9 @@ Transparent drivers are not involved when exporting, copying or destroying keys, #### Key validation with transparent drivers -When a driver creates a key, it is responsible for ensuring that the key is valid. But when a key is imported, no processing of the key happens: the implementation just stores the key material. (It may store it in an encoded form, but this is an implementation choice which is not visible at the level of PSA specifications.) It is important to validate the incoming key material, to avoid storing a key that will later be unacceptable for operations or that could even cause functional or security issues during operations. +When a driver creates a key, it is responsible for ensuring that the key is valid. But when a key is imported, no processing of the key happens: the PSA Cryptography implementation just stores the key material. (It may store it in an encoded form, but this is an implementation choice which is not visible at the level of PSA specifications.) It is important to validate the incoming key material, to avoid storing a key that will later be unacceptable for operations or that could even cause functional or security issues during operations. -To avoid delayed problems caused by imported invalid keys, an implementation that supports transparent drivers must validate transparent keys on import. For supported key types, this means: +To avoid delayed problems caused by imported invalid keys, a PSA Cryptography implementation that supports transparent drivers must validate transparent keys on import. For supported key types, this means: * 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. @@ -358,7 +358,7 @@ To avoid delayed problems caused by imported invalid keys, an implementation tha * For elliptic curve private keys (`PSA_KEY_TYPE_ECC_KEY_PAIR`), check the size and range. TODO: what else? * For elliptic curve public keys (``), check the size and range, and that the point is on the curve. TODO: what else? -A driver can provide code to perform the required validation by providing a `"validate_key"` entry point. This entry points returns `PSA_SUCCESS` if the key is valid or an applicable error code if it isn't. +A driver can provide code to perform the required validation by providing a `"validate_key"` entry point. This entry point returns `PSA_SUCCESS` if the key is valid or an applicable error code if it isn't. The `"validate_key"` entry point has an additional role, which is to determine the size of a key. The PSA Cryptography API exposes the key size as part of the key attributes. From 12760595e7e6c8415b48526362f3eea282daa5dc Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 26 Oct 2020 18:07:01 +0100 Subject: [PATCH 06/10] Replace validate_key by import_key When importing a transparent key, the key needs to be not only validated, but also possibly converted, if it is not already in the canonical representation. So change the validate_key entry point to an import_key entry point. Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 60 +++++++++++++++++---------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index ef92c693b..0a7f71ffb 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -5,7 +5,7 @@ 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/10/12 21:34:43 GMT" +Time-stamp: "2020/10/26 16:54:57 GMT" ## Introduction @@ -339,13 +339,45 @@ The format of a key for transparent drivers is the same as in applications. Refe Transparent drivers may provide the following key management entry points: -* [`"validate_key"`](#key-validation-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). +* [`"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 + +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) below. +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. + +#### Key size determination on import + +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 may be `0`, which indicates that the size must be calculated from the data. +In this case, the core will call the `"import_key"` entry point with an `attributes` structure such that `psa_get_key_bits(attributes)` returns 0, and the `"import_key"` entry point must return the actual key size in the `bits` output parameter. +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 return `PSA_ERROR_INVALID_ARGUMENT` if this is not possible. +* If `*bits != 0`, the driver may either determine the key size from the data and store it in `*bits`, or check the value of `*bits*` against the data and return an error if it does not match. +* If the `"import_key"` entry point returns `PSA_SUCCESS`, but `psa_get_key_bits(attributes) != 0` and `psa_get_key_bits(attributes) != *bits` on output, the core considers the key as invalid due to the size mismatch. + #### Key validation with transparent drivers When a driver creates a key, it is responsible for ensuring that the key is valid. But when a key is imported, no processing of the key happens: the PSA Cryptography implementation just stores the key material. (It may store it in an encoded form, but this is an implementation choice which is not visible at the level of PSA specifications.) It is important to validate the incoming key material, to avoid storing a key that will later be unacceptable for operations or that could even cause functional or security issues during operations. @@ -358,25 +390,7 @@ To avoid delayed problems caused by imported invalid keys, a PSA Cryptography im * For elliptic curve private keys (`PSA_KEY_TYPE_ECC_KEY_PAIR`), check the size and range. TODO: what else? * For elliptic curve public keys (``), check the size and range, and that the point is on the curve. TODO: what else? -A driver can provide code to perform the required validation by providing a `"validate_key"` entry point. This entry point returns `PSA_SUCCESS` if the key is valid or an applicable error code if it isn't. - -The `"validate_key"` entry point has an additional role, which is to determine the size of a key. -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 may be `0`, which indicates that the size must be calculated from the data. -In this case, the core will call the `"validate_key"` entry point with an `attributes` structure such that `psa_get_key_bits(attributes)` returns 0, and the `"validate_key"` entry point must return the actual key size in the `bits` output parameter. -The semantics of `bits` is as follows: - -* The core sets `*bits` to `psa_get_key_bits(attributes)` before calling the `"validate_key"` entry point. -* If `*bits == 0`, the driver must determine the key size from the data, and return `PSA_ERROR_INVALID_ARGUMENT` if this is not possible. -* If `*bits != 0`, the driver may either determine the key size from the data and store it in `*bits`, or check the value of `*bits*` against the data and return an error if it does not match. -* If the `"validate_key"` entry point returns `PSA_SUCCESS`, but `psa_get_key_bits(attributes) != 0` and `psa_get_key_bits(attributes) != *bits` on output, the core considers the key as invalid due to the size mismatch. - -``` -psa_status_t acme_validate_key(const psa_key_attributes_t *attributes, - const uint8_t *data, - size_t data_length, - size_t *bits); -``` +A driver can provide code to perform the required validation by providing an `"import_key"` entry point. This entry point returns `PSA_SUCCESS` if the key is valid or an applicable error code if it isn't. ### Fallback @@ -551,9 +565,9 @@ TODO: derivation, copy #### Key validation and size on import -The `"import_key"` entry point must validate the key so that if a key is imported successfully, permitted operations on the key will succeed if the input data is valid and enough resources are available. For key types that are defined in the PSA Cryptography specification, opaque drivers must guarantee the properties that transparent drivers guarantee if [`"validate_key"`](#key-validation-with-transparent-drivers) succeeds. +The `"import_key"` entry point must validate the key so that if a key is imported successfully, permitted operations on the key will succeed if the input data is valid and enough resources are available. For key types that are defined in the PSA Cryptography specification, opaque drivers must guarantee the properties that transparent drivers guarantee if [`"import_key"`](#key-validation-with-transparent-drivers) succeeds. -Rationale: The key must be validated on import to provide in-time feedback when attempting to inject a bad key. The minimum requirement for validation is the same as for `"validate_key"` to set a minimum security baseline (especially for operations such as key agreement where accepting an invalid key could result in leaking secret material). +Rationale: The key must be validated on import to provide in-time feedback when attempting to inject a bad key. The minimum requirement for validation sets a minimum security baseline (especially for operations such as key agreement where accepting an invalid key could result in leaking secret material). The `"import_key"` entry point may need to determine the key size. The PSA Cryptography API exposes the key size as part of the key attributes. From ce3ec6ffd6ed3d6b8ea37df9178f80ae8fe74f82 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 27 Oct 2020 18:31:50 +0100 Subject: [PATCH 07/10] Unify the sections on key creation Now that transparent drivers have an "import_key" entry point, the key creation interfaces for transparent drivers and opaque drivers are very similar. Unify the sections that describe their behavior, including key validation and key size determination. Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 106 +++++++++++++++----------- 1 file changed, 63 insertions(+), 43 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index 0a7f71ffb..b193d1ca1 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -5,7 +5,7 @@ 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/10/26 16:54:57 GMT" +Time-stamp: "2020/10/27 17:31:13 GMT" ## Introduction @@ -189,6 +189,11 @@ The signature of a driver entry point generally looks like the signature of the * 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. `const 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. #### General considerations on driver entry point parameters @@ -311,7 +316,63 @@ TODO ### Driver entry points for key management -The driver entry points for key management differs significantly between [transparent drivers](#key-management-with-transparent-drivers) and [opaque drivers](#key-management-with-transparent-drivers). Refer to the applicable section for each driver type. +The driver entry points for key management differ significantly between [transparent drivers](#key-management-with-transparent-drivers) and [opaque drivers](#key-management-with-transparent-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); +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 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 may need to determine 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 may be `0`, which indicates that the size must be calculated from the data. +In this case, the core will call the `"import_key"` entry point with an `attributes` structure such that `psa_get_key_bits(attributes)` returns 0, and the `"import_key"` entry point must return the actual key size in the `bits` output parameter. 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 an error 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? ### Miscellaneous driver entry points @@ -366,32 +427,6 @@ 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. -#### Key size determination on import - -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 may be `0`, which indicates that the size must be calculated from the data. -In this case, the core will call the `"import_key"` entry point with an `attributes` structure such that `psa_get_key_bits(attributes)` returns 0, and the `"import_key"` entry point must return the actual key size in the `bits` output parameter. -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 return `PSA_ERROR_INVALID_ARGUMENT` if this is not possible. -* If `*bits != 0`, the driver may either determine the key size from the data and store it in `*bits`, or check the value of `*bits*` against the data and return an error if it does not match. -* If the `"import_key"` entry point returns `PSA_SUCCESS`, but `psa_get_key_bits(attributes) != 0` and `psa_get_key_bits(attributes) != *bits` on output, the core considers the key as invalid due to the size mismatch. - -#### Key validation with transparent drivers - -When a driver creates a key, it is responsible for ensuring that the key is valid. But when a key is imported, no processing of the key happens: the PSA Cryptography implementation just stores the key material. (It may store it in an encoded form, but this is an implementation choice which is not visible at the level of PSA specifications.) It is important to validate the incoming key material, to avoid storing a key that will later be unacceptable for operations or that could even cause functional or security issues during operations. - -To avoid delayed problems caused by imported invalid keys, a PSA Cryptography implementation that supports transparent drivers must validate transparent keys on import. For supported key types, this means: - -* 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 (``), check the size and range, and that the point is on the curve. TODO: what else? - -A driver can provide code to perform the required validation by providing an `"import_key"` entry point. This entry point returns `PSA_SUCCESS` if the key is valid or an applicable error code if it isn't. - ### 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. @@ -563,21 +598,6 @@ If the driver has an [`"allocate_key"` entry point](#key-management-in-a-secure- TODO: derivation, copy -#### Key validation and size on import - -The `"import_key"` entry point must validate the key so that if a key is imported successfully, permitted operations on the key will succeed if the input data is valid and enough resources are available. For key types that are defined in the PSA Cryptography specification, opaque drivers must guarantee the properties that transparent drivers guarantee if [`"import_key"`](#key-validation-with-transparent-drivers) succeeds. - -Rationale: The key must be validated on import to provide in-time feedback when attempting to inject a bad key. The minimum requirement for validation sets a minimum security baseline (especially for operations such as key agreement where accepting an invalid key could result in leaking secret material). - -The `"import_key"` entry point may need to determine 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 may be `0`, which indicates that the size must be calculated from the data. -In this case, the core will call the `"import_key"` entry point with an `attributes` structure such that `psa_get_key_bits(attributes)` returns 0, and the `"import_key"` entry point must return the actual key size in the `bits` output parameter. 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 return `PSA_ERROR_INVALID_ARGUMENT` if this is not possible. -* If `*bits != 0`, the driver must check the value of `*bits*` against the data and return an error if it does not match. - #### Key export entry points in opaque drivers The key export entry points have the following prototypes for a driver with the prefix `"acme"`: From 28b3a946e917f627d0c0e1eb9ead4b821807178e Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Nov 2020 13:08:11 +0100 Subject: [PATCH 08/10] Fix copypasta Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index b193d1ca1..21b724d12 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -190,7 +190,7 @@ The signature of a driver entry point generally looks like the signature of the * 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. `const uint8_t *key_buffer`: a buffer for the key material or 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. @@ -316,7 +316,7 @@ 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-transparent-drivers). This section describes common elements. Refer to the applicable section for each driver type for more information. +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"`: From 99e52f6313e2c8232019860b752c496d03c022ba Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Nov 2020 13:09:50 +0100 Subject: [PATCH 09/10] Clarifications around key import Rework the section describing key import, in particular to clarify key size determination and checking. There is no intended semantic change. Note an open question around support for implementation-specific import formats. Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index 21b724d12..b42c4b174 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -5,7 +5,7 @@ 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/10/27 17:31:13 GMT" +Time-stamp: "2020/11/24 11:03:32 GMT" ## Introduction @@ -327,7 +327,7 @@ psa_status_t acme_import_key(const psa_key_attributes_t *attributes, uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length, - size_t *bits); + 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, @@ -338,7 +338,7 @@ 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 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). +* 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. @@ -346,14 +346,15 @@ All key creation entry points must ensure that the resulting key is valid as spe #### Key size determination on import -The `"import_key"` entry point may need to determine the key size. +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 may be `0`, which indicates that the size must be calculated from the data. -In this case, the core will call the `"import_key"` entry point with an `attributes` structure such that `psa_get_key_bits(attributes)` returns 0, and the `"import_key"` entry point must return the actual key size in the `bits` output parameter. The semantics of `bits` is as follows: +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 an error 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. +* 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 @@ -409,7 +410,7 @@ Transparent drivers are not involved when exporting, copying or destroying keys, #### Key import with transparent drivers -The key import entry points has the following prototype for a driver with the prefix `"acme"`: +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, @@ -762,6 +763,12 @@ The specification doesn't mention when the public key might be calculated. The c 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 From 4228671d0fcf3f3f0927242e9a629055fd7182cf Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Nov 2020 13:10:58 +0100 Subject: [PATCH 10/10] Copyediting Signed-off-by: Gilles Peskine --- docs/proposed/psa-driver-interface.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md index b42c4b174..2e061e543 100644 --- a/docs/proposed/psa-driver-interface.md +++ b/docs/proposed/psa-driver-interface.md @@ -362,7 +362,7 @@ Key creation entry points must produce valid key data. Key data is _valid_ if op * 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.. +* 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. @@ -424,7 +424,7 @@ psa_status_t acme_import_key(const psa_key_attributes_t *attributes, 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) below. +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.