diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 2b07b7471..2c1378fb8 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. * @@ -852,7 +854,320 @@ 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. + * + * \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. + * \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. + * + * 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] 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 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_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 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. + * + * 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 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 + * (\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_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 + * \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. + * + * 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 + * #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_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 + * 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 1f04222c2..989ae66c6 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. @@ -659,4 +659,55 @@ 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*/ + +/** 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 baaabff1e..1980662b0 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). @@ -1082,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. * @@ -1571,6 +1601,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 @@ -1603,9 +1649,69 @@ * 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) +/** 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. + * + * This flag allows the use of psa_wrap_key_with_policy() on the given 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 + * 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 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,