From 65eb8588fec079d476d701e9106ba86fcb077153 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 19 Apr 2018 08:28:58 +0200 Subject: [PATCH 1/4] Expand the description of error codes --- include/psa/crypto.h | 221 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 200 insertions(+), 21 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index f5db4d26b..a463cc05a 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -54,43 +54,206 @@ typedef enum { /** The action was completed successfully. */ PSA_SUCCESS = 0, /** The requested operation or a parameter is not supported - by this implementation. */ + * by this implementation. + * + * Implementations should return this error code when an enumeration + * parameter such as a key type, algorithm, etc. is not recognized. + * If a combination of parameters is recognized and identified as + * not valid, return #PSA_ERROR_INVALID_ARGUMENT instead. */ PSA_ERROR_NOT_SUPPORTED, - /** The requested action is denied by a policy. */ + /** The requested action is denied by a policy. + * + * Implementations should return this error code when the parameters + * are recognized as valid and supported, and a policy explicitly + * denies the requested operation. + * + * If a subset of the parameters of a function call identify a + * forbidden operation, and another subset of the parameters are + * not valid or not supported, it is unspecified whether the function + * returns #PSA_ERROR_NOT_PERMITTED, #PSA_ERROR_NOT_SUPPORTED or + * #PSA_ERROR_INVALID_ARGUMENT. */ PSA_ERROR_NOT_PERMITTED, - /** An output buffer is too small. */ + /** An output buffer is too small. + * + * Applications can call the `PSA_xxx_SIZE` macro listed in the function + * description to determine a sufficient buffer size. + * + * Implementations should preferably return this error code only + * in cases when performing the operation with a larger output + * buffer would succeed. However implementations may return this + * error if a function has invalid or unsupported parameters in addition + * to the parameters that determine the necessary output buffer size. */ PSA_ERROR_BUFFER_TOO_SMALL, /** A slot is occupied, but must be empty to carry out the - requested action. */ + * requested action. + * + * If the slot number is invalid (i.e. the requested action could + * not be performed even after erasing the slot's content), + * implementations shall return #PSA_ERROR_INVALID_ARGUMENT instead. */ PSA_ERROR_OCCUPIED_SLOT, /** A slot is empty, but must be occupied to carry out the - requested action. */ + * requested action. + * + * If the slot number is invalid (i.e. the requested action could + * not be performed even after creating appropriate content in the slot), + * implementations shall return #PSA_ERROR_INVALID_ARGUMENT instead. */ PSA_ERROR_EMPTY_SLOT, - /** The requested action cannot be performed in the current state. */ + /** The requested action cannot be performed in the current state. + * + * Multipart operations return this error when one of the + * functions is called out of sequence. Refer to the function + * descriptions for permitted sequencing of functions. + * + * Implementations shall not return this error code to indicate + * that a key slot is occupied when it needs to be free or vice versa, + * but shall return #PSA_ERROR_OCCUPIED_SLOT or #PSA_ERROR_EMPTY_SLOT + * as applicable. */ PSA_ERROR_BAD_STATE, - /** The parameters passed to the function are invalid. */ + /** The parameters passed to the function are invalid. + * + * Implementations may return this error any time a parameter or + * combination of parameters are recognized as invalid. + * + * Implementations shall not return this error code to indicate + * that a key slot is occupied when it needs to be free or vice versa, + * but shall return #PSA_ERROR_OCCUPIED_SLOT or #PSA_ERROR_EMPTY_SLOT + * as applicable. */ PSA_ERROR_INVALID_ARGUMENT, - /** There is not enough runtime memory. */ + /** There is not enough runtime memory. + * + * If the action is carried out across multiple security realms, this + * error can refer to available memory in any of the security realms. */ PSA_ERROR_INSUFFICIENT_MEMORY, - /** There is not enough persistent storage. */ + /** There is not enough persistent storage. + * + * Functions that modify the key storage return this error code if + * there is insufficient storage space on the host media. In addition, + * many functions that do not otherwise access storage may return this + * error code if the implementation requires a mandatory log entry for + * the requested action and the log storage space is full. */ PSA_ERROR_INSUFFICIENT_STORAGE, - /** There was a communication failure inside the implementation. */ + /** There was a communication failure inside the implementation. + * + * This can indicate a communication failure between the application + * and an external cryptoprocessor or between the cryptoprocessor and + * an external volatile or persistent memory. A communication failure + * may be transient or permanent depending on the cause. + * + * \warning If a function returns this error, it is undetermined + * whether the requested action has completed or not. Implementations + * should return #PSA_SUCCESS on successful completion whenver + * possible, however functions may return #PSA_ERROR_COMMUNICATION_FAILURE + * if the requested action was completed successfully in an external + * cryptoprocessor but there was a breakdown of communication before + * the cryptoprocessor could report the status to the application. + */ PSA_ERROR_COMMUNICATION_FAILURE, - /** There was a storage failure that may have led to data loss. */ + /** There was a storage failure that may have led to data loss. + * + * This error indicates that some persistent storage is corrupted. + * It should not be used for a corruption of volatile memory + * (use #PSA_ERROR_TAMPERING_DETECTED), for a communication error + * between the cryptoprocessor and its external storage (use + * #PSA_ERROR_COMMUNICATION_FAILURE), or when the storage is + * in a valid state but is full (use #PSA_ERROR_INSUFFICIENT_STORAGE). + * + * Note that a storage failure does not indicate that any data that was + * previously read is invalid. However this previously read data may no + * longer be readable from storage. + * + * When a storage failure occurs, it is no longer possible to ensure + * the global integrity of the keystore. Depending on the global + * integrity guarantees offered by the implementation, access to other + * data may or may not fail even if the data is still readable but + * its integrity canont be guaranteed. + * + * Implementations should only use this error code to report a + * permanent storage corruption. However application writers should + * keep in mind that transient errors while reading the storage may be + * reported using this error code. */ PSA_ERROR_STORAGE_FAILURE, - /** A hardware failure was detected. */ + /** A hardware failure was detected. + * + * A hardware failure may be transient or permanent depending on the + * cause. */ PSA_ERROR_HARDWARE_FAILURE, - /** A tampering attempt was detected. */ + /** A tampering attempt was detected. + * + * If an application receives this error code, there is no guarantee + * that previously accessed or computed data was correct and remains + * confidential. Applications should not perform any security function + * and should enter a safe failure state. + * + * Implementations may return this error code if they detect an invalid + * state that cannot happen during normal operation and that indicates + * that the implementation's security guarantees no longer hold. Depending + * on the implementation architecture and on its security and safety goals, + * the implementation may forcibly terminate the application. + * + * This error code is intended as a last resort when a security breach + * is detected and it is unsure whether the keystore data is still + * protected. Implementations shall only return this error code + * to report an alarm from a tampering detector, to indicate that + * the confidentiality of stored data can no longer be guaranteed, + * or to indicate that the integrity of previously returned data is now + * considered compromised. Implementations shall not use this error code + * to indicate a hardware failure that merely makes it impossible to + * perform the requested operation (use #PSA_ERROR_COMMUNICATION_FAILURE, + * #PSA_ERROR_STORAGE_FAILURE, #PSA_ERROR_HARDWARE_FAILURE, + * #PSA_ERROR_INSUFFICIENT_ENTROPY or other applicable error code + * instead). + * + * This error indicates an attack against the application. Implementations + * shall not return this error code as a consequence of the behavior of + * the application itself. */ PSA_ERROR_TAMPERING_DETECTED, /** There is not enough entropy to generate random data needed - for the requested action. */ + * for the requested action. + * + * This error indicates a failure of a hardware random generator. + * Application writers should note that this error can be returned not + * only by functions whose purpose is to generate random data, such + * as key, IV or nonce generation, but also by functions that execute + * an algorithm with a randomized result, as well as functions that + * use randomization of intermediate computations as a countermeasure + * to certain attacks. + * + * Implementations should avoid returning this error after psa_crypto_init() + * has succeeded. Implementations should generate sufficient + * entropy during initialization and subsequently use a cryptographically + * secure pseudorandom generator (PRNG). However implementations may return + * this error at any time if a policy requires the PRNG to be reseeded + * during normal operation. */ PSA_ERROR_INSUFFICIENT_ENTROPY, - /** The signature, MAC or hash is incorrect. */ + /** The signature, MAC or hash is incorrect. + * + * Verification functions return this error if the verification + * calculations completed successfully, and the value to be verified + * was determined to be incorrect. + * + * If the value to verify has an invalid size, implementations may return + * either #PSA_ERROR_INVALID_ARGUMENT or #PSA_ERROR_INVALID_SIGNATURE. */ PSA_ERROR_INVALID_SIGNATURE, - /** The decrypted padding is incorrect. */ + /** The decrypted padding is incorrect. + * + * \warning In some protocols, when decrypting data, it is essential that + * the behavior of the application does not depend on whether the padding + * is correct, down to precise timing. Applications should prefer + * protocols that use authenticated encryption rather than plain + * encryption. If the application must perform a decryption of + * unauthenticated data, the application writer should take care not + * to reveal whether the padding is invalid. + * + * Implementations should strive to make valid and invalid padding + * as close as possible to indistinguishable to an external observer. + * In particular, the timing of a decryption operation should not + * depend on the validity of the padding. */ PSA_ERROR_INVALID_PADDING, /** An error occurred that does not correspond to any defined - failure cause. */ + * failure cause. + * + * Implementations may use this error code if none of the other standard + * error codes are applicable. */ PSA_ERROR_UNKNOWN_ERROR, } psa_status_t; @@ -357,13 +520,15 @@ typedef uint32_t psa_algorithm_t; * \retval PSA_SUCCESS * Success. * \retval PSA_ERROR_NOT_SUPPORTED - * The key type or key size is not supported. + * The key type or key size is not supported, either by the + * implementation in general or in this particular slot. * \retval PSA_ERROR_INVALID_ARGUMENT * The key slot is invalid, * or the key data is not correctly formatted. * \retval PSA_ERROR_OCCUPIED_SLOT - There is already a key in the specified slot. + * There is already a key in the specified slot. * \retval PSA_ERROR_INSUFFICIENT_MEMORY + * \retval PSA_ERROR_INSUFFICIENT_STORAGE * \retval PSA_ERROR_COMMUNICATION_FAILURE * \retval PSA_ERROR_HARDWARE_FAILURE * \retval PSA_ERROR_TAMPERING_DETECTED @@ -377,10 +542,24 @@ psa_status_t psa_import_key(psa_key_slot_t key, * \brief Destroy a key. * * \retval PSA_SUCCESS - * \retval PSA_ERROR_EMPTY_SLOT + * The slot's content, if any, has been erased. + * \retval PSA_ERROR_NOT_PERMITTED + * The slot holds content and cannot be erased because it is + * read-only, either due to a policy or due to physical restrictions. + * \retval PSA_ERROR_INVALID_ARGUMENT + * The specified slot number does not designate a valid slot. * \retval PSA_ERROR_COMMUNICATION_FAILURE - * \retval PSA_ERROR_HARDWARE_FAILURE + * There was an failure in communication with the cryptoprocessor. + * The key material may still be present in the cryptoprocessor. + * \retval PSA_ERROR_STORAGE_FAILURE + * The storage is corrupted. Implementations shall make a best effort + * to erase key material even in this stage, however applications + * should be aware that it may be impossible to guarantee that the + * key material is not recoverable in such cases. * \retval PSA_ERROR_TAMPERING_DETECTED + * An unexpected condition which is not a storage corruption or + * a communication failure occurred. The cryptoprocessor may have + * been compromised. */ psa_status_t psa_destroy_key(psa_key_slot_t key); From 71bb7b77f05fd3e8f07c99249f9e645326fbd96a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 19 Apr 2018 08:29:59 +0200 Subject: [PATCH 2/4] Switch PSA_HASH_FINAL_SIZE to PSA_HASH_SIZE Make this macro work on derived algorithms as well (HMAC, hash-and-sign, etc.). --- include/psa/crypto.h | 40 ++++++++++++++++++++-------------------- library/psa_crypto.c | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index a463cc05a..c880586fe 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -814,23 +814,23 @@ typedef struct psa_hash_operation_s psa_hash_operation_t; * An implementation may return either 0 or the correct size * for a hash algorithm that it recognizes, but does not support. */ -#define PSA_HASH_FINAL_SIZE(alg) \ - ( \ - (alg) == PSA_ALG_MD2 ? 16 : \ - (alg) == PSA_ALG_MD4 ? 16 : \ - (alg) == PSA_ALG_MD5 ? 16 : \ - (alg) == PSA_ALG_RIPEMD160 ? 20 : \ - (alg) == PSA_ALG_SHA_1 ? 20 : \ - (alg) == PSA_ALG_SHA_224 ? 28 : \ - (alg) == PSA_ALG_SHA_256 ? 32 : \ - (alg) == PSA_ALG_SHA_384 ? 48 : \ - (alg) == PSA_ALG_SHA_512 ? 64 : \ - (alg) == PSA_ALG_SHA_512_224 ? 28 : \ - (alg) == PSA_ALG_SHA_512_256 ? 32 : \ - (alg) == PSA_ALG_SHA3_224 ? 28 : \ - (alg) == PSA_ALG_SHA3_256 ? 32 : \ - (alg) == PSA_ALG_SHA3_384 ? 48 : \ - (alg) == PSA_ALG_SHA3_512 ? 64 : \ +#define PSA_HASH_SIZE(alg) \ + ( \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_MD2 ? 16 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_MD4 ? 16 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_MD5 ? 16 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_RIPEMD160 ? 20 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_SHA_1 ? 20 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_SHA_224 ? 28 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_SHA_256 ? 32 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_SHA_384 ? 48 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_SHA_512 ? 64 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_SHA_512_224 ? 28 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_SHA_512_256 ? 32 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_SHA3_224 ? 28 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_SHA3_256 ? 32 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_SHA3_384 ? 48 : \ + PSA_ALG_RSA_GET_HASH(alg) == PSA_ALG_SHA3_512 ? 64 : \ 0) /** Start a multipart hash operation. @@ -915,7 +915,7 @@ psa_status_t psa_hash_update(psa_hash_operation_t *operation, * \param hash_size Size of the \c hash buffer in bytes. * \param hash_length On success, the number of bytes * that make up the hash value. This is always - * #PSA_HASH_FINAL_SIZE(alg) where \c alg is the + * #PSA_HASH_SIZE(alg) where \c alg is the * hash algorithm that is calculated. * * \retval PSA_SUCCESS @@ -924,7 +924,7 @@ psa_status_t psa_hash_update(psa_hash_operation_t *operation, * The operation state is not valid (not started, or already completed). * \retval PSA_ERROR_BUFFER_TOO_SMALL * The size of the \c hash buffer is too small. You can determine a - * sufficient buffer size by calling #PSA_HASH_FINAL_SIZE(alg) + * sufficient buffer size by calling #PSA_HASH_SIZE(alg) * where \c alg is the hash algorithm that is calculated. * \retval PSA_ERROR_INSUFFICIENT_MEMORY * \retval PSA_ERROR_COMMUNICATION_FAILURE @@ -1020,7 +1020,7 @@ typedef struct psa_mac_operation_s psa_mac_operation_t; * for a MAC algorithm that it recognizes, but does not support. */ #define PSA_MAC_FINAL_SIZE(key_type, key_bits, alg) \ - (PSA_ALG_IS_HMAC(alg) ? PSA_HASH_FINAL_SIZE(PSA_ALG_HMAC_HASH(alg)) : \ + (PSA_ALG_IS_HMAC(alg) ? PSA_HASH_SIZE(PSA_ALG_HMAC_HASH(alg)) : \ PSA_ALG_IS_BLOCK_CIPHER_MAC(alg) ? PSA_BLOCK_CIPHER_BLOCK_SIZE(key_type) : \ 0) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 3ea87f642..b66862c50 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -774,7 +774,7 @@ psa_status_t psa_hash_finish( psa_hash_operation_t *operation, size_t *hash_length ) { int ret; - size_t actual_hash_length = PSA_HASH_FINAL_SIZE( operation->alg ); + size_t actual_hash_length = PSA_HASH_SIZE( operation->alg ); /* Fill the output buffer with something that isn't a valid hash * (barring an attack on the hash and deliberately-crafted input), From 154bd95131470b5d58efc60829dbb8d371b8cd63 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 19 Apr 2018 08:38:16 +0200 Subject: [PATCH 3/4] psa_destroy_key: return SUCCESS on an empty slot Do wipe the slot even if it doesn't contain a key, to erase any metadata. --- include/psa/crypto.h | 12 +++++++++++- library/psa_crypto.c | 8 +++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index c880586fe..982cca701 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -539,7 +539,17 @@ psa_status_t psa_import_key(psa_key_slot_t key, size_t data_length); /** - * \brief Destroy a key. + * \brief Destroy a key and restore the slot to its default state. + * + * This function destroys the content of the key slot from both volatile + * memory and, if applicable, non-volatile storage. Implementations shall + * make a best effort to ensure that any previous content of the slot is + * unrecoverable. + * + * This function also erases any metadata such as policies. It returns the + * specified slot to its default state. + * + * \param key The key slot to erase. * * \retval PSA_SUCCESS * The slot's content, if any, has been erased. diff --git a/library/psa_crypto.c b/library/psa_crypto.c index b66862c50..deeffa3b8 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -373,9 +373,11 @@ psa_status_t psa_destroy_key(psa_key_slot_t key) return( PSA_ERROR_INVALID_ARGUMENT ); slot = &global_data.key_slots[key]; if( slot->type == PSA_KEY_TYPE_NONE ) - return( PSA_ERROR_EMPTY_SLOT ); - - if( PSA_KEY_TYPE_IS_RAW_BYTES( slot->type ) ) + { + /* No key material to clean, but do zeroize the slot below to wipe + * metadata such as policies. */ + } + else if( PSA_KEY_TYPE_IS_RAW_BYTES( slot->type ) ) { mbedtls_free( slot->data.raw.data ); } From 3585596aecb48e79d33ade6bccd34d316c203547 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 19 Apr 2018 08:39:16 +0200 Subject: [PATCH 4/4] Document a few more macros --- include/psa/crypto.h | 58 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 982cca701..a2ce15665 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -304,15 +304,47 @@ typedef uint32_t psa_key_type_t; #define PSA_KEY_TYPE_VENDOR_FLAG ((psa_key_type_t)0x80000000) #define PSA_KEY_TYPE_CATEGORY_MASK ((psa_key_type_t)0x7e000000) +/** Raw data. + * + * A "key" of this type cannot be used for any cryptographic operation. + * Applications may use this type to store arbitrary data in the keystore. */ #define PSA_KEY_TYPE_RAW_DATA ((psa_key_type_t)0x02000000) #define PSA_KEY_TYPE_CATEGORY_SYMMETRIC ((psa_key_type_t)0x04000000) #define PSA_KEY_TYPE_CATEGORY_ASYMMETRIC ((psa_key_type_t)0x06000000) #define PSA_KEY_TYPE_PAIR_FLAG ((psa_key_type_t)0x01000000) +/** HMAC key. + * + * The key policy determines which underlying hash algorithm the key can be + * used for. + * + * HMAC keys should generally have the same size as the underlying hash. + * This size can be calculated with `PSA_HASH_SIZE(alg)` where + * `alg` is the HMAC algorithm or the underlying hash algorithm. */ #define PSA_KEY_TYPE_HMAC ((psa_key_type_t)0x02000001) +/** Key for an cipher, AEAD or MAC algorithm based on the AES block cipher. + * + * The size of the key can be 16 bytes (AES-128), 24 bytes (AES-192) or + * 32 bytes (AES-256). + */ #define PSA_KEY_TYPE_AES ((psa_key_type_t)0x04000001) +/** Key for a cipher or MAC algorithm based on DES or 3DES (Triple-DES). + * + * The size of the key can be 8 bytes (single DES), 16 bytes (2-key 3DES) or + * 24 bytes (3-key 3DES). + * + * Note that single DES and 2-key 3DES are weak and strongly + * deprecated and should only be used to decrypt legacy data. 3-key 3DES + * is weak and deprecated and should only be used in legacy protocols. + */ #define PSA_KEY_TYPE_DES ((psa_key_type_t)0x04000002) +/** Key for an cipher, AEAD or MAC algorithm based on the + * Camellia block cipher. */ #define PSA_KEY_TYPE_CAMELLIA ((psa_key_type_t)0x04000003) +/** Key for the RC4 stream cipher. + * + * Note that RC4 is weak and deprecated and should only be used in + * legacy protocols. */ #define PSA_KEY_TYPE_ARC4 ((psa_key_type_t)0x04000004) /** RSA public key. */ @@ -369,8 +401,14 @@ typedef uint32_t psa_key_type_t; * \param type A cipher key type (value of type #psa_key_type_t). * * \return The block size for a block cipher, or 1 for a stream cipher. - * The return value is undefined if \c type does not identify - * a cipher algorithm. + * The return value is undefined if \c type is not a supported + * cipher key type. + * + * \note It is possible to build stream cipher algorithms on top of a block + * cipher, for example CTR mode (#PSA_ALG_CTR). + * This macro only takes the key type into account, so it cannot be + * used to determine the size of the data that #psa_cipher_update() + * might buffer for future processing in general. * * \note This macro returns a compile-time constant if its argument is one. * @@ -451,7 +489,17 @@ typedef uint32_t psa_algorithm_t; #define PSA_ALG_MAC_SUBCATEGORY_MASK ((psa_algorithm_t)0x00c00000) #define PSA_ALG_HMAC_BASE ((psa_algorithm_t)0x02800000) -#define PSA_ALG_HMAC(hash_alg) \ +/** Macro to build an HMAC algorithm. + * + * For example, `PSA_ALG_HMAC(PSA_ALG_SHA256)` is HMAC-SHA-256. + * + * \param alg A hash algorithm (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_HASH(alg) is true). + * + * \return The corresponding HMAC algorithm. + * \return Unspecified if \p alg is not a hash algorithm. + */ +#define PSA_ALG_HMAC(hash_alg) \ (PSA_ALG_HMAC_BASE | ((hash_alg) & PSA_ALG_HASH_MASK)) #define PSA_ALG_HMAC_HASH(hmac_alg) \ (PSA_ALG_CATEGORY_HASH | ((hmac_alg) & PSA_ALG_HASH_MASK)) @@ -817,7 +865,9 @@ typedef struct psa_hash_operation_s psa_hash_operation_t; * This is also the hash size that psa_hash_verify() expects. * * \param alg A hash algorithm (\c PSA_ALG_XXX value such that - * #PSA_ALG_IS_HASH(alg) is true). + * #PSA_ALG_IS_HASH(alg) is true), or an HMAC algorithm + * (`PSA_ALG_HMAC(hash_alg)` where `hash_alg` is a + * hash algorithm). * * \return The hash size for the specified hash algorithm. * If the hash algorithm is not recognized, return 0.