From d6f371b1baca09d51ea6e1a914be921c76fa8bf8 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 | 39 ++++++++++++++++ include/psa/crypto_struct.h | 3 +- library/psa_crypto.c | 52 +++++++++++++++------ tests/suites/test_suite_psa_crypto.data | 8 ++++ tests/suites/test_suite_psa_crypto.function | 37 +++++++++++++++ 5 files changed, 124 insertions(+), 15 deletions(-) diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index c89c55df3..a1a658971 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -62,6 +62,45 @@ extern "C" { MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( PSA_ERROR_INSUFFICIENT_DATA ) #endif +/** \addtogroup policy + * @{ + */ + +/** \brief Set the enrollment algorithm in a key policy. + * + * An operation on a key may indifferently use the algorithm set with + * psa_key_policy_set_usage() or with this function. + * + * \param[in,out] policy The key policy to modify. It must have been + * initialized as per the documentation for + * #psa_key_policy_t. + * \param alg2 A second algorithm that the key may be used for, + * in addition to the algorithm set with + * psa_key_policy_set_usage(). + * + * \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. + */ +void psa_key_policy_set_enrollment_algorithm(psa_key_policy_t *policy, + psa_algorithm_t alg2); + +/** \brief Retrieve the enrollment algorithm field of a policy structure. + * + * \param[in] policy The policy object to query. + * + * \return The enrollment algorithm for a key with this policy. + */ +psa_algorithm_t psa_key_policy_get_enrollment_algorithm( + const psa_key_policy_t *policy); + +/**@}*/ + /** * \brief Library deinitialization. * diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index ee3ecd776..88503572f 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -228,9 +228,10 @@ struct psa_key_policy_s { psa_key_usage_t usage; psa_algorithm_t alg; + psa_algorithm_t alg2; }; -#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; diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 3b9c78ffc..17f2c2293 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -763,6 +763,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. @@ -770,20 +789,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. @@ -804,10 +811,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 ); } @@ -3218,6 +3230,18 @@ psa_algorithm_t psa_key_policy_get_algorithm( const psa_key_policy_t *policy ) { return( policy->alg ); } + +void psa_key_policy_set_enrollment_algorithm( psa_key_policy_t *policy, + psa_algorithm_t alg2 ) +{ + policy->alg2 = alg2; +} + +psa_algorithm_t psa_key_policy_get_enrollment_algorithm( + const psa_key_policy_t *policy ) +{ + return( policy->alg2 ); +} #endif /* !defined(MBEDTLS_PSA_CRYPTO_SPM) */ psa_status_t psa_set_key_policy( psa_key_handle_t handle, diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index 65ac6d7fb..e93bc15e2 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -492,6 +492,14 @@ PSA key policy: agreement, wrong algorithm depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDH_C agreement_key_policy:PSA_KEY_USAGE_DERIVE:PSA_ALG_ECDH(PSA_ALG_SELECT_RAW):PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_ALG_FFDH(PSA_ALG_SELECT_RAW) +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_KEYPAIR(PSA_ECC_CURVE_SECP256R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_ECDH(PSA_ALG_SELECT_RAW):PSA_ALG_ECDSA_ANY + Copy key: raw, 0 bytes copy_key_policy:0:0:PSA_KEY_TYPE_RAW_DATA:"":0:0:-1:-1:0:0 diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 4cec11881..a79b73834 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -1932,6 +1932,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_policy_t policy = PSA_KEY_POLICY_INIT; + psa_key_policy_t got_policy = PSA_KEY_POLICY_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_ASSERT( psa_allocate_key( &handle ) ); + psa_key_policy_set_usage( &policy, usage, alg ); + psa_key_policy_set_enrollment_algorithm( &policy, alg2 ); + PSA_ASSERT( psa_set_key_policy( handle, &policy ) ); + PSA_ASSERT( psa_import_key( handle, key_type, + key_data->x, key_data->len ) ); + + PSA_ASSERT( psa_get_key_policy( handle, &got_policy ) ); + TEST_EQUAL( psa_key_policy_get_usage( &got_policy ), usage ); + TEST_EQUAL( psa_key_policy_get_algorithm( &got_policy ), alg ); + TEST_EQUAL( psa_key_policy_get_enrollment_algorithm( &got_policy ), 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 copy_key_policy( int source_usage_arg, int source_alg_arg, int type_arg, data_t *material,