From 8cb22c8d875fd52fa336db35d1d59d6ac8fc533d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 22 Sep 2021 16:15:05 +0200 Subject: [PATCH] Untangle PSA_ALG_IS_HASH_AND_SIGN and PSA_ALG_IS_SIGN_HASH The current definition of PSA_ALG_IS_HASH_AND_SIGN includes PSA_ALG_RSA_PKCS1V15_SIGN_RAW and PSA_ALG_ECDSA_ANY, which don't strictly follow the hash-and-sign paradigm: the algorithm does not encode a hash algorithm that is applied prior to the signature step. The definition in fact encompasses what can be used with psa_sign_hash/psa_verify_hash, so it's the correct definition for PSA_ALG_IS_SIGN_HASH. Therefore this commit moves definition of PSA_ALG_IS_HASH_AND_SIGN to PSA_ALG_IS_SIGN_HASH, and replace the definition of PSA_ALG_IS_HASH_AND_SIGN by a correct one (based on PSA_ALG_IS_SIGN_HASH, excluding the algorithms where the pre-signature step isn't to apply the hash encoded in the algorithm). In the definition of PSA_ALG_SIGN_GET_HASH, keep the condition for a nonzero output to be PSA_ALG_IS_HASH_AND_SIGN. Everywhere else in the code base (definition of PSA_ALG_IS_SIGN_MESSAGE, and every use of PSA_ALG_IS_HASH_AND_SIGN outside of crypto_values.h), we meant PSA_ALG_IS_SIGN_HASH where we wrote PSA_ALG_IS_HASH_AND_SIGN, so do a global replacement. ``` git grep -l IS_HASH_AND_SIGN ':!include/psa/crypto_values.h' | xargs perl -i -pe 's/ALG_IS_HASH_AND_SIGN/ALG_IS_SIGN_HASH/g' ``` Signed-off-by: Gilles Peskine --- include/psa/crypto_values.h | 34 ++++++++++++++----- library/psa_crypto.c | 12 +++---- tests/src/psa_exercise_key.c | 4 +-- tests/suites/test_suite_psa_crypto.function | 2 +- .../test_suite_psa_crypto_metadata.data | 18 +++++----- .../test_suite_psa_crypto_metadata.function | 6 ++-- 6 files changed, 47 insertions(+), 29 deletions(-) diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h index 524e2dc7a..a29beb565 100644 --- a/include/psa/crypto_values.h +++ b/include/psa/crypto_values.h @@ -1545,7 +1545,20 @@ * Hash-and-sign algorithms are asymmetric (public-key) signature algorithms * structured in two parts: first the calculation of a hash in a way that * does not depend on the key, then the calculation of a signature from the - * hash value and the key. + * hash value and the key. Hash-and-sign algorithms encode the hash + * used for the hashing step, and you can call #PSA_ALG_SIGN_GET_HASH + * to extract this algorithm. + * + * Thus, for a hash-and-sign algorithm, + * `psa_sign_message(key, alg, input, ...)` is equivalent to + * ``` + * psa_hash_compute(PSA_ALG_SIGN_GET_HASH(alg), input, ..., hash, ...); + * psa_sign_hash(key, alg, hash, ..., signature, ...); + * ``` + * Most usefully, separating the hash from the signature allows the hash + * to be calculated in multiple steps with psa_hash_setup(), psa_hash_update() + * and psa_hash_finish(). Likewise psa_verify_message() is equivalent to + * calculating the hash and then calling psa_verify_hash(). * * \param alg An algorithm identifier (value of type #psa_algorithm_t). * @@ -1554,9 +1567,8 @@ * algorithm identifier. */ #define PSA_ALG_IS_HASH_AND_SIGN(alg) \ - (PSA_ALG_IS_RSA_PSS(alg) || PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) || \ - PSA_ALG_IS_ECDSA(alg) || PSA_ALG_IS_HASH_EDDSA(alg) || \ - PSA_ALG_IS_VENDOR_HASH_AND_SIGN(alg)) + (PSA_ALG_IS_SIGN_HASH(alg) && \ + ((alg) & PSA_ALG_HASH_MASK) != 0) /** Whether the specified algorithm is a signature algorithm that can be used * with psa_sign_message() and psa_verify_message(). @@ -1570,11 +1582,17 @@ * supported algorithm identifier. */ #define PSA_ALG_IS_SIGN_MESSAGE(alg) \ - (PSA_ALG_IS_HASH_AND_SIGN(alg) || (alg) == PSA_ALG_PURE_EDDSA ) + (PSA_ALG_IS_SIGN_HASH(alg) || (alg) == PSA_ALG_PURE_EDDSA ) /** Whether the specified algorithm is a signature algorithm that can be used * with psa_sign_hash() and psa_verify_hash(). * + * This encompasses all strict hash-and-sign algorithms categorized by + * PSA_ALG_IS_HASH_AND_SIGN(), as well as algorithms that follow the + * paradigm more loosely: + * - #PSA_ALG_RSA_PKCS1V15_SIGN_RAW (expects its input to be an encoded hash) + * - #PSA_ALG_ECDSA_ANY (doesn't specify what kind of hash the input is) + * * \param alg An algorithm identifier (value of type psa_algorithm_t). * * \return 1 if alg is a signature algorithm that can be used to sign a @@ -1584,8 +1602,9 @@ * supported algorithm identifier. */ #define PSA_ALG_IS_SIGN_HASH(alg) \ - (PSA_ALG_IS_HASH_AND_SIGN(alg) || (alg) == PSA_ALG_ED25519PH || \ - (alg) == PSA_ALG_ED448PH) + (PSA_ALG_IS_RSA_PSS(alg) || PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) || \ + PSA_ALG_IS_ECDSA(alg) || PSA_ALG_IS_HASH_EDDSA(alg) || \ + PSA_ALG_IS_VENDOR_HASH_AND_SIGN(alg)) /** Get the hash used by a hash-and-sign signature algorithm. * @@ -1607,7 +1626,6 @@ */ #define PSA_ALG_SIGN_GET_HASH(alg) \ (PSA_ALG_IS_HASH_AND_SIGN(alg) ? \ - ((alg) & PSA_ALG_HASH_MASK) == 0 ? /*"raw" algorithm*/ 0 : \ ((alg) & PSA_ALG_HASH_MASK) | PSA_ALG_CATEGORY_HASH : \ 0) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index a8e41a217..406e6c4cf 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -705,8 +705,8 @@ static psa_algorithm_t psa_key_policy_algorithm_intersection( return( alg1 ); /* If the policies are from the same hash-and-sign family, check * if one is a wildcard. If so the other has the specific algorithm. */ - if( PSA_ALG_IS_HASH_AND_SIGN( alg1 ) && - PSA_ALG_IS_HASH_AND_SIGN( alg2 ) && + if( PSA_ALG_IS_SIGN_HASH( alg1 ) && + PSA_ALG_IS_SIGN_HASH( alg2 ) && ( alg1 & ~PSA_ALG_HASH_MASK ) == ( alg2 & ~PSA_ALG_HASH_MASK ) ) { if( PSA_ALG_SIGN_GET_HASH( alg1 ) == PSA_ALG_ANY_HASH ) @@ -808,7 +808,7 @@ static int psa_key_algorithm_permits( psa_key_type_t key_type, /* If policy_alg is a hash-and-sign with a wildcard for the hash, * and requested_alg is the same hash-and-sign family with any hash, * then requested_alg is compliant with policy_alg. */ - if( PSA_ALG_IS_HASH_AND_SIGN( requested_alg ) && + if( PSA_ALG_IS_SIGN_HASH( requested_alg ) && PSA_ALG_SIGN_GET_HASH( policy_alg ) == PSA_ALG_ANY_HASH ) { return( ( policy_alg & ~PSA_ALG_HASH_MASK ) == @@ -2698,7 +2698,7 @@ static psa_status_t psa_sign_verify_check_alg( int input_is_message, if( ! PSA_ALG_IS_SIGN_MESSAGE( alg ) ) return( PSA_ERROR_INVALID_ARGUMENT ); - if ( PSA_ALG_IS_HASH_AND_SIGN( alg ) ) + if ( PSA_ALG_IS_SIGN_HASH( alg ) ) { if( ! PSA_ALG_IS_HASH( PSA_ALG_SIGN_GET_HASH( alg ) ) ) return( PSA_ERROR_INVALID_ARGUMENT ); @@ -2856,7 +2856,7 @@ psa_status_t psa_sign_message_builtin( { psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; - if ( PSA_ALG_IS_HASH_AND_SIGN( alg ) ) + if ( PSA_ALG_IS_SIGN_HASH( alg ) ) { size_t hash_length; uint8_t hash[PSA_HASH_MAX_SIZE]; @@ -2903,7 +2903,7 @@ psa_status_t psa_verify_message_builtin( { psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; - if ( PSA_ALG_IS_HASH_AND_SIGN( alg ) ) + if ( PSA_ALG_IS_SIGN_HASH( alg ) ) { size_t hash_length; uint8_t hash[PSA_HASH_MAX_SIZE]; diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c index 923d2c136..91bac678e 100644 --- a/tests/src/psa_exercise_key.c +++ b/tests/src/psa_exercise_key.c @@ -306,7 +306,7 @@ static int exercise_signature_key( mbedtls_svc_key_id_t key, psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH( alg ); /* If the policy allows signing with any hash, just pick one. */ - if( PSA_ALG_IS_HASH_AND_SIGN( alg ) && hash_alg == PSA_ALG_ANY_HASH ) + if( PSA_ALG_IS_SIGN_HASH( alg ) && hash_alg == PSA_ALG_ANY_HASH ) { #if defined(KNOWN_SUPPORTED_HASH_ALG) hash_alg = KNOWN_SUPPORTED_HASH_ALG; @@ -925,7 +925,7 @@ psa_key_usage_t mbedtls_test_psa_usage_to_exercise( psa_key_type_t type, { if( PSA_ALG_IS_MAC( alg ) || PSA_ALG_IS_SIGN( alg ) ) { - if( PSA_ALG_IS_HASH_AND_SIGN( alg ) ) + if( PSA_ALG_IS_SIGN_HASH( alg ) ) { if( PSA_ALG_SIGN_GET_HASH( alg ) ) return( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ? diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 5fa45d8e7..2eab8e50a 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -1159,7 +1159,7 @@ void asymmetric_signature_key_policy( int policy_usage_arg, else TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED ); - if( PSA_ALG_IS_HASH_AND_SIGN( exercise_alg ) && + if( PSA_ALG_IS_SIGN_HASH( exercise_alg ) && PSA_ALG_IS_HASH( PSA_ALG_SIGN_GET_HASH( exercise_alg ) ) ) { status = psa_sign_message( key, exercise_alg, diff --git a/tests/suites/test_suite_psa_crypto_metadata.data b/tests/suites/test_suite_psa_crypto_metadata.data index 1ea8e6332..89705e8fb 100644 --- a/tests/suites/test_suite_psa_crypto_metadata.data +++ b/tests/suites/test_suite_psa_crypto_metadata.data @@ -212,31 +212,31 @@ aead_algorithm:PSA_ALG_CHACHA20_POLY1305:0:16:PSA_KEY_TYPE_CHACHA20:256 Asymmetric signature: RSA PKCS#1 v1.5 raw depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN -asymmetric_signature_algorithm:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:ALG_IS_RSA_PKCS1V15_SIGN | ALG_IS_HASH_AND_SIGN +asymmetric_signature_algorithm:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:ALG_IS_RSA_PKCS1V15_SIGN | ALG_IS_SIGN_HASH Asymmetric signature: RSA PKCS#1 v1.5 SHA-256 depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_ALG_SHA_256 -asymmetric_signature_algorithm:PSA_ALG_RSA_PKCS1V15_SIGN( PSA_ALG_SHA_256 ):ALG_IS_RSA_PKCS1V15_SIGN | ALG_IS_HASH_AND_SIGN +asymmetric_signature_algorithm:PSA_ALG_RSA_PKCS1V15_SIGN( PSA_ALG_SHA_256 ):ALG_IS_RSA_PKCS1V15_SIGN | ALG_IS_SIGN_HASH Asymmetric signature: RSA PSS SHA-256 depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256 -asymmetric_signature_algorithm:PSA_ALG_RSA_PSS( PSA_ALG_SHA_256 ):ALG_IS_RSA_PSS | ALG_IS_RSA_PSS_STANDARD_SALT | ALG_IS_HASH_AND_SIGN +asymmetric_signature_algorithm:PSA_ALG_RSA_PSS( PSA_ALG_SHA_256 ):ALG_IS_RSA_PSS | ALG_IS_RSA_PSS_STANDARD_SALT | ALG_IS_SIGN_HASH Asymmetric signature: RSA PSS-any-salt SHA-256 depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256 -asymmetric_signature_algorithm:PSA_ALG_RSA_PSS_ANY_SALT( PSA_ALG_SHA_256 ):ALG_IS_RSA_PSS | ALG_IS_RSA_PSS_ANY_SALT | ALG_IS_HASH_AND_SIGN +asymmetric_signature_algorithm:PSA_ALG_RSA_PSS_ANY_SALT( PSA_ALG_SHA_256 ):ALG_IS_RSA_PSS | ALG_IS_RSA_PSS_ANY_SALT | ALG_IS_SIGN_HASH Asymmetric signature: randomized ECDSA (no hashing) depends_on:PSA_WANT_ALG_ECDSA -asymmetric_signature_algorithm:PSA_ALG_ECDSA_ANY:ALG_IS_ECDSA | ALG_IS_RANDOMIZED_ECDSA | ALG_IS_HASH_AND_SIGN +asymmetric_signature_algorithm:PSA_ALG_ECDSA_ANY:ALG_IS_ECDSA | ALG_IS_RANDOMIZED_ECDSA | ALG_IS_SIGN_HASH Asymmetric signature: SHA-256 + randomized ECDSA depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_256 -asymmetric_signature_algorithm:PSA_ALG_ECDSA( PSA_ALG_SHA_256 ):ALG_IS_ECDSA | ALG_IS_RANDOMIZED_ECDSA | ALG_IS_HASH_AND_SIGN +asymmetric_signature_algorithm:PSA_ALG_ECDSA( PSA_ALG_SHA_256 ):ALG_IS_ECDSA | ALG_IS_RANDOMIZED_ECDSA | ALG_IS_SIGN_HASH Asymmetric signature: SHA-256 + deterministic ECDSA using SHA-256 depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256 -asymmetric_signature_algorithm:PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):ALG_IS_ECDSA | ALG_IS_DETERMINISTIC_ECDSA | ALG_ECDSA_IS_DETERMINISTIC | ALG_IS_HASH_AND_SIGN +asymmetric_signature_algorithm:PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):ALG_IS_ECDSA | ALG_IS_DETERMINISTIC_ECDSA | ALG_ECDSA_IS_DETERMINISTIC | ALG_IS_SIGN_HASH Asymmetric signature: pure EdDSA depends_on:PSA_WANT_ALG_EDDSA @@ -244,11 +244,11 @@ asymmetric_signature_algorithm:PSA_ALG_PURE_EDDSA:0 Asymmetric signature: Ed25519ph depends_on:PSA_WANT_ALG_EDDSA -asymmetric_signature_algorithm:PSA_ALG_ED25519PH:ALG_IS_HASH_EDDSA | ALG_IS_HASH_AND_SIGN +asymmetric_signature_algorithm:PSA_ALG_ED25519PH:ALG_IS_HASH_EDDSA | ALG_IS_SIGN_HASH Asymmetric signature: Ed448ph depends_on:PSA_WANT_ALG_EDDSA -asymmetric_signature_algorithm:PSA_ALG_ED448PH:ALG_IS_HASH_EDDSA | ALG_IS_HASH_AND_SIGN +asymmetric_signature_algorithm:PSA_ALG_ED448PH:ALG_IS_HASH_EDDSA | ALG_IS_SIGN_HASH Asymmetric signature: RSA PKCS#1 v1.5 with wildcard hash depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN diff --git a/tests/suites/test_suite_psa_crypto_metadata.function b/tests/suites/test_suite_psa_crypto_metadata.function index 827ad1b36..e6d2127be 100644 --- a/tests/suites/test_suite_psa_crypto_metadata.function +++ b/tests/suites/test_suite_psa_crypto_metadata.function @@ -33,7 +33,7 @@ #define ALG_IS_DETERMINISTIC_ECDSA ( 1u << 14 ) #define ALG_IS_RANDOMIZED_ECDSA ( 1u << 15 ) #define ALG_IS_HASH_EDDSA ( 1u << 16 ) -#define ALG_IS_HASH_AND_SIGN ( 1u << 17 ) +#define ALG_IS_SIGN_HASH ( 1u << 17 ) #define ALG_IS_RSA_OAEP ( 1u << 18 ) #define ALG_IS_HKDF ( 1u << 19 ) #define ALG_IS_FFDH ( 1u << 20 ) @@ -114,7 +114,7 @@ void algorithm_classification( psa_algorithm_t alg, unsigned flags ) TEST_CLASSIFICATION_MACRO( ALG_IS_DETERMINISTIC_ECDSA, alg, flags ); TEST_CLASSIFICATION_MACRO( ALG_IS_RANDOMIZED_ECDSA, alg, flags ); TEST_CLASSIFICATION_MACRO( ALG_IS_HASH_EDDSA, alg, flags ); - TEST_CLASSIFICATION_MACRO( ALG_IS_HASH_AND_SIGN, alg, flags ); + TEST_CLASSIFICATION_MACRO( ALG_IS_SIGN_HASH, alg, flags ); TEST_CLASSIFICATION_MACRO( ALG_IS_RSA_OAEP, alg, flags ); TEST_CLASSIFICATION_MACRO( ALG_IS_HKDF, alg, flags ); TEST_CLASSIFICATION_MACRO( ALG_IS_WILDCARD, alg, flags ); @@ -485,7 +485,7 @@ void asymmetric_signature_algorithm( int alg_arg, int classification_flags ) /* BEGIN_CASE */ void asymmetric_signature_wildcard( int alg_arg, int classification_flags ) { - classification_flags |= ALG_IS_HASH_AND_SIGN | ALG_IS_WILDCARD; + classification_flags |= ALG_IS_SIGN_HASH | ALG_IS_WILDCARD; test_asymmetric_signature_algorithm( alg_arg, classification_flags ); /* Any failure of this test function comes from * asymmetric_signature_algorithm. Pacify -Werror=unused-label. */