From 96f0b3b1d35708607faa91531540e1b65d35e82a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 10 May 2019 19:33:38 +0200 Subject: [PATCH] Keys may allow a second algorithm Add a second permitted algorithm to key policies. This commit includes smoke tests that do not cover psa_copy_key. --- include/psa/crypto_extra.h | 44 +++++++++++++++++++++ include/psa/crypto_struct.h | 5 ++- library/psa_crypto.c | 40 ++++++++++++------- tests/suites/test_suite_psa_crypto.data | 8 ++++ tests/suites/test_suite_psa_crypto.function | 37 +++++++++++++++++ 5 files changed, 118 insertions(+), 16 deletions(-) diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index 497fd752a..0de4e1f0f 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -62,6 +62,50 @@ extern "C" { MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( PSA_ERROR_INSUFFICIENT_DATA ) #endif +/** \addtogroup attributes + * @{ + */ + +/** \brief Declare the enrollment algorithm for a key. + * + * An operation on a key may indifferently use the algorithm set with + * psa_set_key_algorithm() or with this function. + * + * \param[out] attributes The attribute structure to write to. + * \param alg2 A second algorithm that the key may be used + * for, in addition to the algorithm set with + * psa_set_key_algorithm(). + * + * \warning Setting an enrollment algorithm is not recommended, because + * using the same key with different algorithms can allow some + * attacks based on arithmetic relations between different + * computations made with the same key, or can escalate harmless + * side channels into exploitable ones. Use this function only + * if it is necessary to support a protocol for which is has been + * verified that the usage of the key with multiple algorithms + * is safe. + */ +static inline void psa_set_key_enrollment_algorithm( + psa_key_attributes_t *attributes, + psa_algorithm_t alg2) +{ + attributes->policy.alg2 = alg2; +} + +/** Retrieve the enrollment algorithm policy from key attributes. + * + * \param[in] attributes The key attribute structure to query. + * + * \return The enrollment algorithm stored in the attribute structure. + */ +static inline psa_algorithm_t psa_get_key_enrollment_algorithm( + const psa_key_attributes_t *attributes) +{ + return( attributes->policy.alg2 ); +} + +/**@}*/ + /** * \brief Library deinitialization. * diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index 885d90888..977b021b8 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -251,10 +251,11 @@ struct psa_key_policy_s { psa_key_usage_t usage; psa_algorithm_t alg; + psa_algorithm_t alg2; }; typedef struct psa_key_policy_s psa_key_policy_t; -#define PSA_KEY_POLICY_INIT {0, 0} +#define PSA_KEY_POLICY_INIT {0, 0, 0} static inline struct psa_key_policy_s psa_key_policy_init( void ) { const struct psa_key_policy_s v = PSA_KEY_POLICY_INIT; @@ -272,7 +273,7 @@ struct psa_key_attributes_s size_t domain_parameters_size; }; -#define PSA_KEY_ATTRIBUTES_INIT {0, 0, {0, 0}, 0, 0, NULL, 0} +#define PSA_KEY_ATTRIBUTES_INIT {0, 0, {0, 0, 0}, 0, 0, NULL, 0} static inline struct psa_key_attributes_s psa_key_attributes_init( void ) { const struct psa_key_attributes_s v = PSA_KEY_ATTRIBUTES_INIT; diff --git a/library/psa_crypto.c b/library/psa_crypto.c index c306727ed..8ed9deb5b 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -786,6 +786,25 @@ static psa_algorithm_t psa_key_policy_algorithm_intersection( return( 0 ); } +static int psa_key_algorithm_permits( psa_algorithm_t policy_alg, + psa_algorithm_t requested_alg ) +{ + /* Common case: the policy only allows alg. */ + if( requested_alg == policy_alg ) + return( 1 ); + /* If policy_alg is a hash-and-sign with a wildcard for the hash, + * and alg is the same hash-and-sign family with any hash, + * then alg is compliant with policy_alg. */ + if( PSA_ALG_IS_HASH_AND_SIGN( requested_alg ) && + PSA_ALG_SIGN_GET_HASH( policy_alg ) == PSA_ALG_ANY_HASH ) + { + return( ( policy_alg & ~PSA_ALG_HASH_MASK ) == + ( requested_alg & ~PSA_ALG_HASH_MASK ) ); + } + /* If it isn't permitted, it's forbidden. */ + return( 0 ); +} + /** Test whether a policy permits an algorithm. * * The caller must test usage flags separately. @@ -793,20 +812,8 @@ static psa_algorithm_t psa_key_policy_algorithm_intersection( static int psa_key_policy_permits( const psa_key_policy_t *policy, psa_algorithm_t alg ) { - /* Common case: the policy only allows alg. */ - if( alg == policy->alg ) - return( 1 ); - /* If policy->alg is a hash-and-sign with a wildcard for the hash, - * and alg is the same hash-and-sign family with any hash, - * then alg is compliant with policy->alg. */ - if( PSA_ALG_IS_HASH_AND_SIGN( alg ) && - PSA_ALG_SIGN_GET_HASH( policy->alg ) == PSA_ALG_ANY_HASH ) - { - return( ( policy->alg & ~PSA_ALG_HASH_MASK ) == - ( alg & ~PSA_ALG_HASH_MASK ) ); - } - /* If it isn't permitted, it's forbidden. */ - return( 0 ); + return( psa_key_algorithm_permits( policy->alg, alg ) || + psa_key_algorithm_permits( policy->alg2, alg ) ); } /** Restrict a key policy based on a constraint. @@ -827,10 +834,15 @@ static psa_status_t psa_restrict_key_policy( { psa_algorithm_t intersection_alg = psa_key_policy_algorithm_intersection( policy->alg, constraint->alg ); + psa_algorithm_t intersection_alg2 = + psa_key_policy_algorithm_intersection( policy->alg2, constraint->alg2 ); if( intersection_alg == 0 && policy->alg != 0 && constraint->alg != 0 ) return( PSA_ERROR_INVALID_ARGUMENT ); + if( intersection_alg2 == 0 && policy->alg2 != 0 && constraint->alg2 != 0 ) + return( PSA_ERROR_INVALID_ARGUMENT ); policy->usage &= constraint->usage; policy->alg = intersection_alg; + policy->alg2 = intersection_alg2; return( PSA_SUCCESS ); } diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index b454cec9e..e81aba76f 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -516,6 +516,14 @@ PSA key policy: raw agreement, key only permits a KDF depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDH_C raw_agreement_key_policy:PSA_KEY_USAGE_DERIVE:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)) +PSA key policy algorithm2: CTR, CBC +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR:MBEDTLS_CIPHER_MODE_CBC_NOPAD +key_policy_alg2:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_KEY_USAGE_ENCRYPT:PSA_ALG_CTR:PSA_ALG_CBC_NO_PADDING + +PSA key policy algorithm2: ECDH, ECDSA +depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDH_C:MBEDTLS_ECDSA_C +key_policy_alg2:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_ECDH:PSA_ALG_ECDSA_ANY + Copy key: raw, 0 bytes copy_success:PSA_KEY_USAGE_COPY:0:PSA_KEY_TYPE_RAW_DATA:"":1:-1:-1:PSA_KEY_USAGE_COPY:0 diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index e351603d0..8cf30c8cb 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -1912,6 +1912,43 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void key_policy_alg2( int key_type_arg, data_t *key_data, + int usage_arg, int alg_arg, int alg2_arg ) +{ + psa_key_handle_t handle = 0; + psa_key_type_t key_type = key_type_arg; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_attributes_t got_attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_usage_t usage = usage_arg; + psa_algorithm_t alg = alg_arg; + psa_algorithm_t alg2 = alg2_arg; + + PSA_ASSERT( psa_crypto_init( ) ); + + psa_set_key_usage_flags( &attributes, usage ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_enrollment_algorithm( &attributes, alg2 ); + psa_set_key_type( &attributes, key_type ); + PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len, + &handle ) ); + + PSA_ASSERT( psa_get_key_attributes( handle, &got_attributes ) ); + TEST_EQUAL( psa_get_key_usage_flags( &got_attributes ), usage ); + TEST_EQUAL( psa_get_key_algorithm( &got_attributes ), alg ); + TEST_EQUAL( psa_get_key_enrollment_algorithm( &got_attributes ), alg2 ); + + if( ! exercise_key( handle, usage, alg ) ) + goto exit; + if( ! exercise_key( handle, usage, alg2 ) ) + goto exit; + +exit: + psa_destroy_key( handle ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void raw_agreement_key_policy( int policy_usage, int policy_alg,