From 666975379608acb0c3a58500d9e2644e06918162 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 10 Feb 2020 15:20:28 +0100 Subject: [PATCH 1/8] Fix copypasta in the description of PSA_KEY_EXPORT_MAX_SIZE --- include/psa/crypto_sizes.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h index 1f04222c2..2ee843656 100644 --- a/include/psa/crypto_sizes.h +++ b/include/psa/crypto_sizes.h @@ -641,8 +641,8 @@ * * \return If the parameters are valid and supported, return * a buffer size in bytes that guarantees that - * psa_sign_hash() will not fail with - * #PSA_ERROR_BUFFER_TOO_SMALL. + * psa_export_key() (and psa_export_public_key() if applicable) + will not fail with #PSA_ERROR_BUFFER_TOO_SMALL. * If the parameters are a valid combination that is not supported * by the implementation, this macro shall return either a * sensible size or 0. From da79e925d2e7d2dae9a8b73b44108a9aee31336f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 10 Feb 2020 15:20:42 +0100 Subject: [PATCH 2/8] psa_get_key_attributes: state that *attributes must be valid on input This was implicitly conveyed by the general requirement of initializing attribute structure and by declaring \p attributes to be an in-out parameter, but it is better to make this explicit. --- include/psa/crypto.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 2b07b7471..cb794a7df 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -348,7 +348,9 @@ static size_t psa_get_key_bits(const psa_key_attributes_t *attributes); * you must call psa_reset_key_attributes() to free these resources. * * \param[in] handle Handle to the key to query. - * \param[in,out] attributes On success, the attributes of the key. + * \param[in,out] attributes On entry, this structure must be in a + * valid state. + * On success, the attributes of the key. * On failure, equivalent to a * freshly-initialized structure. * From 3cb715b9c4dd471ad50ff1f2277caf3152aa9fed Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 10 Feb 2020 15:24:30 +0100 Subject: [PATCH 3/8] Declare key binding functions Declare functions to wrap and unwrap a key together with its metadata, in an unspecified vendor-specific format but with an explicitly specified key. Declare a corresponding usage flag. --- include/psa/crypto.h | 129 ++++++++++++++++++++++++++++++++++++ include/psa/crypto_sizes.h | 25 +++++++ include/psa/crypto_values.h | 13 ++++ 3 files changed, 167 insertions(+) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index cb794a7df..dde47eee7 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -854,6 +854,135 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle, size_t data_size, size_t *data_length); +/** + * \brief Export a key and its metadata in wrapped form. + * + * A wrapped form of the key object preserves the confidentiality and + * authenticity of the key material and the authenticity of the key + * policy. In practical terms, the key material is encrypted, and + * the key data and metadata are authenticated together. + * + * The format of the wrapped data is implementation-dependent. It may depend + * both on the choice of wrapping key and on the type of key to wrap. + * + * The policy on the key must have the usage flag + * #PSA_KEY_USAGE_EXPORT_WRAPPED set. + * + * \param wrapping_key Handle to the key to wrap with. + * \param handle Handle to the key to export in wrapped form. + * \param[out] data Buffer where the wrapped key data is to be written. + * \param data_size Size of the \p data buffer in bytes. + * \param[out] data_length On success, the number of bytes + * that make up the wrapped key data. + * + * \retval #PSA_SUCCESS + * \retval #PSA_ERROR_INVALID_HANDLE + * One or both of \p handle and \p wrapping_key is not a valid + * handle to a key. + * \retval #PSA_ERROR_NOT_PERMITTED + * The key \p handle does not have the #PSA_KEY_USAGE_BACKUP flag. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p wrapping_key does not support wrapping keys with metadata. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p wrapping_key does not support wrapping the key designated + * by \p handle. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p data buffer is too small. You can determine a + * sufficient buffer size by calling + * #PSA_WRAP_KEY_WITH_POLICY_OUTPUT_SIZE(\c type, \c bits) + * where \c type is the key type of \p handle + * and \c bits is the key size of \p handle in bits. + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_STORAGE_FAILURE + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t psa_wrap_key_with_policy(psa_key_handle_t wrapping_key, + psa_key_handle_t handle, + uint8_t *data, + size_t data_size, + size_t *data_length); + +/** + * \brief Import a wrapped key with its metadata. + * + * This function supports any output from psa_wrap_key_with_policy(). + * For symmetric wrapping, you must unwrap with the same key that was + * used to wrap. For asymmetric wrapping where the wrapping operation uses + * a public key and the unwrapping operation uses the corresponding private + * key, you must unwrap with the corresponding unwrapping key. + * + * \param wrapping_key Handle to the key to unwrap with. + * \param[in] attributes The attributes for the new key. + * They are used as follows: + * - The key type and size may be 0. If either is + * nonzero, it must match the corresponding + * attribute of the wrapped key data. + * - The key location (the lifetime and, for + * persistent keys, the key identifier) is + * used directly. + * If the wrapped key does not have the usage + * flag #PSA_KEY_USAGE_COPY, then the location + * must match the location embedded in \p data. + * If the wrapped key has the usage + * flag #PSA_KEY_USAGE_COPY, then the location + * embedded in \p data is ignored. + * - The policy constraints (usage flags and + * algorithm policy) are combined from + * the wrapped key data and \p attributes so that + * both sets of restrictions apply. The + * policy restrictions are calculated in the + * same way as in psa_copy_key(). + * \param[in] data Buffer containing the wrapped key material. + * The expected format of this buffer depends + * on the wrapping key. + * \param data_length Size of the \p data buffer in bytes. + * \param[out] handle On success, a handle to the newly created key. + * \c 0 on failure. + * + * \retval #PSA_SUCCESS + * Success. + * If the unwrapped key is persistent, the key material and the + * key's metadata have been saved to persistent storage. + * \retval #PSA_ERROR_ALREADY_EXISTS + * This is an attempt to create a persistent key, and there is + * already a persistent key with the given identifier. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The key attributes, as a whole, are invalid. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The key data is not correctly formatted. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The size in \p attributes is nonzero and does not match the size + * of the key data. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p wrapping_key does not support unwrapping keys with metadata. + * \retval #PSA_ERROR_INVALID_SIGNATURE + * \p data is not a valid wrapped key for \p wrapping_key. + * \retval #PSA_ERROR_NOT_SUPPORTED + * Some of the metadata in either \p attributes or \p data is + * not supported. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_INSUFFICIENT_STORAGE + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_STORAGE_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t psa_unwrap_key_with_policy(psa_key_handle_t wrapping_key, + const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + psa_key_handle_t *handle); + /**@}*/ diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h index 2ee843656..c57a1aaaa 100644 --- a/include/psa/crypto_sizes.h +++ b/include/psa/crypto_sizes.h @@ -659,4 +659,29 @@ PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(key_type) ? PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits) : \ 0) +/** Sufficient output buffer size for psa_wrap_key_with_policy(). + * + * This macro returns a compile-time constant if its arguments are + * compile-time constants. + * + * \warning This function may call its arguments multiple times or + * zero times, so you should not pass arguments that contain + * side effects. + * + * \param key_type A supported key type. + * \param key_bits The size of the key in bits. + * + * \return If the parameters are valid and supported, return + * a buffer size in bytes that guarantees that + * psa_wrap_key_with_policy() will not fail with + * #PSA_ERROR_BUFFER_TOO_SMALL. + * If the parameters are a valid combination that is not supported + * by the implementation, this macro shall return either a + * sensible size or 0. + * If the parameters are not valid, the + * return value is unspecified. + */ +#define PSA_WRAP_KEY_WITH_POLICY_OUTPUT_SIZE(key_type, key_bits) \ + 0u /*not implemented yet*/ + #endif /* PSA_CRYPTO_SIZES_H */ diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h index baaabff1e..43ee8deca 100644 --- a/include/psa/crypto_values.h +++ b/include/psa/crypto_values.h @@ -1606,6 +1606,19 @@ */ #define PSA_KEY_USAGE_COPY ((psa_key_usage_t)0x00000002) +/** Whether the key object may be saved outside the device in wrapped form. + * This is also known as key binding. + * + * This flag allows the use of psa_wrap_key_with_policy() on the given key, + * with any suitable wrapping key. + * + * A wrapped form of the key object preserves the confidentiality and + * authenticity of the key material and the authenticity of the key + * policy. In practical terms, the key material is encrypted, and + * the key data and metadata are authenticated together. + */ +#define PSA_KEY_USAGE_BACKUP ((psa_key_usage_t)0x00000020) + /** Whether the key may be used to encrypt a message. * * This flag allows the key to be used for a symmetric encryption operation, From ec1b1ba210ec8568f588c0fb889100d100a62910 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 10 Feb 2020 15:27:29 +0100 Subject: [PATCH 4/8] Declare PSA_KEY_ID_WRAP_BOUND Declare a key binding key that implementations are encouraged to provide. --- include/psa/crypto.h | 4 ++++ include/psa/crypto_values.h | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index dde47eee7..aa44247b0 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -868,6 +868,10 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle, * The policy on the key must have the usage flag * #PSA_KEY_USAGE_EXPORT_WRAPPED set. * + * \note This specification does not currently provide a way to + * create a wrapping key. Many implementations provide a + * predefined wrapping key #PSA_KEY_ID_WRAP_BOUND. + * * \param wrapping_key Handle to the key to wrap with. * \param handle Handle to the key to export in wrapped form. * \param[out] data Buffer where the wrapped key data is to be written. diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h index 43ee8deca..47d27ee76 100644 --- a/include/psa/crypto_values.h +++ b/include/psa/crypto_values.h @@ -1571,6 +1571,22 @@ */ #define PSA_KEY_ID_VENDOR_MAX ((psa_app_key_id_t)0x7fffffff) +/** A key wrapping key suitable for keys managed directly by the + * PSA Cryptography implementation. + * + * Applications may use this key with psa_wrap_key_with_policy() and + * psa_unwrap_key_with_policy() to back up a key that has the + * #PSA_KEY_USAGE_BACKUP usage flag and later restore it on the same device, + * if the implementation supports it. + * + * The existence of this key is optional. Implementations that support + * key wrapping should offer a key with this identifier if having a + * single wrapping key makes sense in the scenarios where this implementation + * is used. If this key exists, it must be private to the device, i.e. it + * must not be shared with any other device or entity. + */ +#define PSA_KEY_ID_WRAP_BOUND ((psa_app_key_id_t)0x80000062) + /**@}*/ /** \defgroup policy Key policies From 341ab2c09686d2bf28f0855d96c1a7ec1f47e250 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 10 Feb 2020 15:30:20 +0100 Subject: [PATCH 5/8] Declare key material wrapping functions Declare functions to wrap and unwrap key material in standard formats. Declare an algorithm category for key wrapping. Declare a corresponding usage flag. --- include/psa/crypto.h | 109 ++++++++++++++++++++++++++++++++++++ include/psa/crypto_sizes.h | 26 +++++++++ include/psa/crypto_values.h | 35 ++++++++++++ 3 files changed, 170 insertions(+) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index aa44247b0..ad2155d81 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -987,7 +987,116 @@ psa_status_t psa_unwrap_key_with_policy(psa_key_handle_t wrapping_key, size_t data_length, psa_key_handle_t *handle); +/** + * \brief Export key material in wrapped form. + * + * A wrapped form of the key material preserves the confidentiality + * and authenticity of the key material. In practical terms, the key + * material is encrypted and authenticated. + * + * The policy on the key must have the usage flag + * #PSA_KEY_USAGE_EXPORT_WRAPPED set. + * + * \param wrapping_key Handle to the key to wrap with. + * \param alg The key wrapping algorithm to compute + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_KEY_WRAP(\p alg) is true). + * \param handle Handle to the key whose material is to be + * exported in wrapped form. + * \param[out] data Buffer where the wrapped key data is to be written. + * \param data_size Size of the \p data buffer in bytes. + * \param[out] data_length On success, the number of bytes + * that make up the wrapped key data. + * + * \retval #PSA_SUCCESS + * \retval #PSA_ERROR_INVALID_HANDLE + * One or both of \p handle and \p wrapping_key is not a valid + * handle to a key. + * \retval #PSA_ERROR_NOT_PERMITTED + * The key \p handle does not have the #PSA_KEY_USAGE_BACKUP flag. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p wrapping_key does not support wrapping key material. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p wrapping_key does not support wrapping the key designated + * by \p handle. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p data buffer is too small. You can determine a + * sufficient buffer size by calling + * #PSA_WRAP_KEY_MATERIAL_OUTPUT_SIZE(\p alg, \c type, \c bits) + * where \c type is the key type of \p handle + * and \c bits is the key size of \p handle in bits. + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_STORAGE_FAILURE + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t psa_wrap_key_material(psa_key_handle_t wrapping_key, + psa_algorithm_t alg, + psa_key_handle_t handle, + uint8_t *data, + size_t data_size, + size_t *data_length); +/** + * \brief Import wrapped key material. + * + * \param wrapping_key Handle to the key to unwrap with. + * \param alg The key unwrapping algorithm to compute + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_KEY_WRAP(\p alg) is true). + * \param[in] attributes The attributes for the new key. + * They are used in the same way as by + * psa_import_key(). + * \param[in] data Buffer containing the key data. The expected + * format of this buffer depends on the wrapping + * key and on the type declared in \p attributes. + * \param data_length Size of the \p data buffer in bytes. + * \param[out] handle On success, a handle to the newly created key. + * \c 0 on failure. + * + * \retval #PSA_SUCCESS + * Success. + * If the unwrapped key is persistent, the key material and the + * key's metadata have been saved to persistent storage. + * \retval #PSA_ERROR_ALREADY_EXISTS + * This is an attempt to create a persistent key, and there is + * already a persistent key with the given identifier. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The key attributes, as a whole, are invalid. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The key data is not correctly formatted. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The size in \p attributes is nonzero and does not match the size + * of the key data. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p wrapping_key does not support unwrapping keys with metadata. + * \retval #PSA_ERROR_INVALID_SIGNATURE + * \p data is not a valid wrapped key for \p wrapping_key. + * \retval #PSA_ERROR_NOT_SUPPORTED + * The key type or key size is not supported, either by the + * implementation in general or in this particular persistent location. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_INSUFFICIENT_STORAGE + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_STORAGE_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t psa_unwrap_key_material(psa_key_handle_t wrapping_key, + psa_algorithm_t alg, + const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + psa_key_handle_t *handle); /**@}*/ diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h index c57a1aaaa..989ae66c6 100644 --- a/include/psa/crypto_sizes.h +++ b/include/psa/crypto_sizes.h @@ -684,4 +684,30 @@ #define PSA_WRAP_KEY_WITH_POLICY_OUTPUT_SIZE(key_type, key_bits) \ 0u /*not implemented yet*/ +/** Sufficient output buffer size for psa_wrap_key_material(). + * + * This macro returns a compile-time constant if its arguments are + * compile-time constants. + * + * \warning This function may call its arguments multiple times or + * zero times, so you should not pass arguments that contain + * side effects. + * + * \param alg The key wrapping algorithm. + * \param key_type A supported key type. + * \param key_bits The size of the key in bits. + * + * \return If the parameters are valid and supported, return + * a buffer size in bytes that guarantees that + * psa_wrap_key_material() will not fail with + * #PSA_ERROR_BUFFER_TOO_SMALL. + * If the parameters are a valid combination that is not supported + * by the implementation, this macro shall return either a + * sensible size or 0. + * If the parameters are not valid, the + * return value is unspecified. + */ +#define PSA_WRAP_KEY_MATERIAL_OUTPUT_SIZE(alg, key_type, key_bits) \ + 0u /*not implemented yet*/ + #endif /* PSA_CRYPTO_SIZES_H */ diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h index 47d27ee76..d530b279c 100644 --- a/include/psa/crypto_values.h +++ b/include/psa/crypto_values.h @@ -615,6 +615,7 @@ #define PSA_ALG_CATEGORY_MAC ((psa_algorithm_t)0x02000000) #define PSA_ALG_CATEGORY_CIPHER ((psa_algorithm_t)0x04000000) #define PSA_ALG_CATEGORY_AEAD ((psa_algorithm_t)0x06000000) +#define PSA_ALG_CATEGORY_WRAP ((psa_algorithm_t)0x0e000000) #define PSA_ALG_CATEGORY_SIGN ((psa_algorithm_t)0x10000000) #define PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION ((psa_algorithm_t)0x12000000) #define PSA_ALG_CATEGORY_KEY_DERIVATION ((psa_algorithm_t)0x20000000) @@ -672,6 +673,17 @@ #define PSA_ALG_IS_AEAD(alg) \ (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_AEAD) +/** Whether the specified algorithm is a key wrapping algorithm. + * + * \param alg An algorithm identifier (value of type #psa_algorithm_t). + * + * \return 1 if \p alg is a key wrapping algorithm, 0 otherwise. + * This macro may return either 0 or 1 if \p alg is not a supported + * algorithm identifier. + */ +#define PSA_ALG_IS_KEY_WRAP(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_WRAP) + /** Whether the specified algorithm is a public-key signature algorithm. * * \param alg An algorithm identifier (value of type #psa_algorithm_t). @@ -1622,6 +1634,29 @@ */ #define PSA_KEY_USAGE_COPY ((psa_key_usage_t)0x00000002) +/** Whether the key material may be exported in wrapped form. + * + * This flag allows the use of psa_wrap_key_material() on the given key, + * with any suitable wrapping key. + * + * A wrapped form of the key material preserves the confidentiality + * and authenticity of the key material. In practical terms, the key + * material is encrypted and authenticated. + * + * A wrapped form does not preserve the key metadata in general, so it is up + * to the application to ensure that the key is unwrapped with the correct + * type and policy. + * + * \note Given that a wrapped key can be unwrapped with a different policy, + * which may include #PSA_KEY_USAGE_EXPORT, there is often no + * security advantage to allowing the key usage + * #PSA_KEY_USAGE_EXPORT_WRAPPED but not #PSA_KEY_USAGE_EXPORT. + * However implementations may impose restrictions on keys that + * are created through unwrapping with a particular key, in which + * case unwrapping could preserve the non-extractibility of a key. + */ +#define PSA_KEY_USAGE_EXPORT_WRAPPED ((psa_key_usage_t)0x00000010) + /** Whether the key object may be saved outside the device in wrapped form. * This is also known as key binding. * From d29bc2d53612869917a09cd4dd0bc0cd19c899b4 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 10 Feb 2020 15:31:11 +0100 Subject: [PATCH 6/8] Declare NIST KW and KWP as examples of key wrapping algorithms --- include/psa/crypto_values.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h index d530b279c..e6a06a2be 100644 --- a/include/psa/crypto_values.h +++ b/include/psa/crypto_values.h @@ -1094,6 +1094,24 @@ PSA_ALG_AEAD_WITH_TAG_LENGTH(ref, 0) ? \ ref : +/** The KW algorithm from NIST SP 800-38F, also described in RFC 3394. + * + * This algorithm may be used with any key type for a block cipher with + * a 128-bit block size, not just AES. The calculations are the same as + * described in SP 800-38F, but replacing uses of AES with the 128-bit + * block cipher that the key is for. + */ +#define PSA_ALG_NIST_KW ((psa_algorithm_t)0x0e401003) + +/** The KWP algorithm from NIST SP 800-38F. + * + * This algorithm may be used with any key type for a block cipher with + * a 128-bit block size, not just AES. The calculations are the same as + * described in SP 800-38F, but replacing uses of AES with the 128-bit + * block cipher that the key is for. + */ +#define PSA_ALG_NIST_KWP ((psa_algorithm_t)0x0e401005) + #define PSA_ALG_RSA_PKCS1V15_SIGN_BASE ((psa_algorithm_t)0x10020000) /** RSA PKCS#1 v1.5 signature with hashing. * From fa0b197595440aa3a9d553faac7df92c1c7e0949 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 12 Feb 2020 19:11:50 +0100 Subject: [PATCH 7/8] Key unwrap with metadata: separate function to unwrap to volatile Using attributes with psa_key_unwrap_with_policy() is inconvenient. When unwrapping a key to its original location (a straightforward restore from backup), there's no reason to specify any attributes. When unwrapping a key in a different location and possibly restricting its policy, the new attributes are generally a refinement of the old ones. Remove the attributes argument from psa_key_unwrap_with_policy() and provide another function to unwrap to a volatile location. The application can then use existing functions to manipulate the key, including psa_get_key_attributes() and psa_copy_key(). --- include/psa/crypto.h | 116 +++++++++++++++++++++++++++--------- include/psa/crypto_values.h | 8 ++- 2 files changed, 95 insertions(+), 29 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index ad2155d81..29f70d571 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -921,27 +921,12 @@ psa_status_t psa_wrap_key_with_policy(psa_key_handle_t wrapping_key, * a public key and the unwrapping operation uses the corresponding private * key, you must unwrap with the corresponding unwrapping key. * + * The resulting key object has the same attributes as the original key: + * same lifetime, same identifier if persistent, same usage policy. + * To restore a key to a different location or with a different policy, + * use psa_unwrap_key_to_alternate_lifetime(). + * * \param wrapping_key Handle to the key to unwrap with. - * \param[in] attributes The attributes for the new key. - * They are used as follows: - * - The key type and size may be 0. If either is - * nonzero, it must match the corresponding - * attribute of the wrapped key data. - * - The key location (the lifetime and, for - * persistent keys, the key identifier) is - * used directly. - * If the wrapped key does not have the usage - * flag #PSA_KEY_USAGE_COPY, then the location - * must match the location embedded in \p data. - * If the wrapped key has the usage - * flag #PSA_KEY_USAGE_COPY, then the location - * embedded in \p data is ignored. - * - The policy constraints (usage flags and - * algorithm policy) are combined from - * the wrapped key data and \p attributes so that - * both sets of restrictions apply. The - * policy restrictions are calculated in the - * same way as in psa_copy_key(). * \param[in] data Buffer containing the wrapped key material. * The expected format of this buffer depends * on the wrapping key. @@ -957,19 +942,16 @@ psa_status_t psa_wrap_key_with_policy(psa_key_handle_t wrapping_key, * This is an attempt to create a persistent key, and there is * already a persistent key with the given identifier. * \retval #PSA_ERROR_INVALID_ARGUMENT - * The key attributes, as a whole, are invalid. - * \retval #PSA_ERROR_INVALID_ARGUMENT * The key data is not correctly formatted. * \retval #PSA_ERROR_INVALID_ARGUMENT - * The size in \p attributes is nonzero and does not match the size - * of the key data. - * \retval #PSA_ERROR_INVALID_ARGUMENT * \p wrapping_key does not support unwrapping keys with metadata. * \retval #PSA_ERROR_INVALID_SIGNATURE * \p data is not a valid wrapped key for \p wrapping_key. * \retval #PSA_ERROR_NOT_SUPPORTED - * Some of the metadata in either \p attributes or \p data is - * not supported. + * Some of the metadata encoded in \p data is not supported. + * This can only happen when attempting to unwrap a key that + * was wrapped under a different implementation or a + * differently-configured implementation. * \retval #PSA_ERROR_INSUFFICIENT_MEMORY * \retval #PSA_ERROR_INSUFFICIENT_STORAGE * \retval #PSA_ERROR_COMMUNICATION_FAILURE @@ -982,11 +964,89 @@ psa_status_t psa_wrap_key_with_policy(psa_key_handle_t wrapping_key, * results in this error code. */ psa_status_t psa_unwrap_key_with_policy(psa_key_handle_t wrapping_key, - const psa_key_attributes_t *attributes, const uint8_t *data, size_t data_length, psa_key_handle_t *handle); +/** + * \brief Import a wrapped key with its metadata to volatile memory. + * + * This function supports any output from psa_wrap_key_with_policy() + * where the wrapped key has the usage flag #PSA_KEY_USAGE_COPY set. + * For symmetric wrapping, you must unwrap with the same key that was + * used to wrap. For asymmetric wrapping where the wrapping operation uses + * a public key and the unwrapping operation uses the corresponding private + * key, you must unwrap with the corresponding unwrapping key. + * + * The resulting key object has the same attributes as the original key + * apart from its lifetime, in particular it has the same usage policy. + * To unwrap a key and give it a more restrictive policy or place it + * in a different location: + * -# Call psa_unwrap_key_to_alternate_lifetime() to unwrap the key to a + * volatile location. + * -# If desired, call psa_get_key_attributes() to retrieve the + * attributes of the key, then modify them as desired for the + * subsequent copy. + * -# Call psa_copy_key() to copy the key to its desired location + * (volatile or persistent) and with the desired policy. + * -# Call psa_destroy_key() to destroy the intermediate volatile key. + * + * The resulting key does not have a persistent identifier, therefore + * the target lifetime must be volatile. + * + * \param wrapping_key Handle to the key to unwrap with. + * \param lifetime The lifetime to unwrap to. + * This must be a volatile lifetime. + * The wrapping key may constrain which lifetimes + * are permitted; such constraints are + * implementation-defined. As a guideline, + * implementations should allow unwrapping a key + * to a lifetime that is in the same location + * as the original key. + * \param[in] data Buffer containing the wrapped key material. + * The expected format of this buffer depends + * on the wrapping key. + * \param data_length Size of the \p data buffer in bytes. + * \param[out] handle On success, a handle to the newly created key. + * \c 0 on failure. + * + * \retval #PSA_SUCCESS + * Success. + * If the unwrapped key is persistent, the key material and the + * key's metadata have been saved to persistent storage. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p lifetime is not a volatile lifetime. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The key data is not correctly formatted. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p wrapping_key does not support unwrapping keys with metadata. + * \retval #PSA_ERROR_INVALID_SIGNATURE + * \p data is not a valid wrapped key for \p wrapping_key. + * \retval #PSA_ERROR_NOT_SUPPORTED + * Some of the metadata encoded in \p data is not supported. + * This can only happen when attempting to unwrap a key that + * was wrapped under a different implementation or a + * differently-configured implementation. + * \retval #PSA_ERROR_NOT_PERMITTED + * The wrapped key does not have the #PSA_KEY_USAGE_COPY flag. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_INSUFFICIENT_STORAGE + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_STORAGE_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_CORRUPTION_DETECTED + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t psa_unwrap_key_to_alternate_lifetime( + psa_key_handle_t wrapping_key, + psa_key_lifetime_t lifetime, + const uint8_t *data, + size_t data_length, + psa_key_handle_t *handle); + /** * \brief Export key material in wrapped form. * diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h index e6a06a2be..f20460135 100644 --- a/include/psa/crypto_values.h +++ b/include/psa/crypto_values.h @@ -1649,6 +1649,9 @@ * For keys with the lifetime #PSA_KEY_LIFETIME_VOLATILE or * #PSA_KEY_LIFETIME_PERSISTENT, the usage flag #PSA_KEY_USAGE_COPY * is sufficient to permit the copy. + * + * When combined with #PSA_KEY_USAGE_BACKUP, this flag allows the use + * of psa_unwrap_key_to_alternate_lifetime() on a wrapped key data. */ #define PSA_KEY_USAGE_COPY ((psa_key_usage_t)0x00000002) @@ -1679,7 +1682,10 @@ * This is also known as key binding. * * This flag allows the use of psa_wrap_key_with_policy() on the given key, - * with any suitable wrapping key. + * with any suitable wrapping key, and the subsequent use of + * psa_unwrap_key_with_policy() on the resulting data. + * When combined with #PSA_KEY_USAGE_COPY, this flag also allows the use + * of psa_unwrap_key_to_alternate_lifetime() to unwrap the resulting data. * * A wrapped form of the key object preserves the confidentiality and * authenticity of the key material and the authenticity of the key From c3177d4396aa2b416f9948bc318eef0bd4669621 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 12 Feb 2020 19:22:40 +0100 Subject: [PATCH 8/8] Add usage flags for wrapping keys --- include/psa/crypto.h | 13 ++++++++++++- include/psa/crypto_values.h | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 29f70d571..2c1378fb8 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -1054,8 +1054,10 @@ psa_status_t psa_unwrap_key_to_alternate_lifetime( * and authenticity of the key material. In practical terms, the key * material is encrypted and authenticated. * - * The policy on the key must have the usage flag + * The policy on the key to wrap must have the usage flag * #PSA_KEY_USAGE_EXPORT_WRAPPED set. + * The policy on the wrapping key must have the usage flag + * #PSA_KEY_USAGE_WRAP_OTHER_KEY set. * * \param wrapping_key Handle to the key to wrap with. * \param alg The key wrapping algorithm to compute @@ -1074,6 +1076,9 @@ psa_status_t psa_unwrap_key_to_alternate_lifetime( * handle to a key. * \retval #PSA_ERROR_NOT_PERMITTED * The key \p handle does not have the #PSA_KEY_USAGE_BACKUP flag. + * \retval #PSA_ERROR_NOT_PERMITTED + * The key \p wrapping_key does not have the + * #PSA_KEY_USAGE_WRAP_OTHER_KEY flag. * \retval #PSA_ERROR_INVALID_ARGUMENT * \p wrapping_key does not support wrapping key material. * \retval #PSA_ERROR_NOT_SUPPORTED @@ -1105,6 +1110,9 @@ psa_status_t psa_wrap_key_material(psa_key_handle_t wrapping_key, /** * \brief Import wrapped key material. * + * The policy on the wrapping key must have the usage flag + * #PSA_KEY_USAGE_UNWRAP_OTHER_KEY set. + * * \param wrapping_key Handle to the key to unwrap with. * \param alg The key unwrapping algorithm to compute * (\c PSA_ALG_XXX value such that @@ -1126,6 +1134,9 @@ psa_status_t psa_wrap_key_material(psa_key_handle_t wrapping_key, * \retval #PSA_ERROR_ALREADY_EXISTS * This is an attempt to create a persistent key, and there is * already a persistent key with the given identifier. + * \retval #PSA_ERROR_NOT_PERMITTED + * The key \p wrapping_key does not have the + * #PSA_KEY_USAGE_UNWRAP_OTHER_KEY flag. * \retval #PSA_ERROR_INVALID_ARGUMENT * The key attributes, as a whole, are invalid. * \retval #PSA_ERROR_INVALID_ARGUMENT diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h index f20460135..1980662b0 100644 --- a/include/psa/crypto_values.h +++ b/include/psa/crypto_values.h @@ -1694,6 +1694,24 @@ */ #define PSA_KEY_USAGE_BACKUP ((psa_key_usage_t)0x00000020) +/** Whether the key may be used to wrap another key. + * + * This flag allows the key to be used as a wrapping key with + * psa_wrap_key_material(). + * + * For a key pair, this concerns the public key. + */ +#define PSA_KEY_USAGE_WRAP_OTHER_KEY ((psa_key_usage_t)0x00000040) + +/** Whether the key may be used to unwrap another key. + * + * This flag allows the key to be used as a wrapping key with + * psa_unwrap_key_material(). + * + * For a key pair, this concerns the private key. + */ +#define PSA_KEY_USAGE_UNWRAP_OTHER_KEY ((psa_key_usage_t)0x00000080) + /** Whether the key may be used to encrypt a message. * * This flag allows the key to be used for a symmetric encryption operation,