From 01d718cee89bfd057af43d4ff95e80e3acf9b372 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 18 Sep 2018 12:01:02 +0200 Subject: [PATCH] New API function: psa_key_agreement Set up a generator from a key agreement. --- include/psa/crypto.h | 40 ++++++ library/psa_crypto.c | 60 +++++++++ tests/suites/test_suite_psa_crypto.data | 20 +++ tests/suites/test_suite_psa_crypto.function | 136 ++++++++++++++++++++ 4 files changed, 256 insertions(+) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 8059ab9e2..8fb641fdc 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -3191,6 +3191,46 @@ psa_status_t psa_key_derivation(psa_crypto_generator_t *generator, size_t label_length, size_t capacity); +/** Set up a key agreement operation. + * + * A key agreement algorithm takes two inputs: a private key \p private_key + * a public key \p peer_key. + * The result of this function is a byte generator which can + * be used to produce keys and other cryptographic material. + * + * \param[in,out] generator The generator object to set up. It must + * have been initialized to all-bits-zero, + * a logical zero (`{0}`), + * \c PSA_CRYPTO_GENERATOR_INIT or + * psa_crypto_generator_init(). + * \param private_key Slot containing the private key to use. + * \param[in] peer_key Public key of the peer. + * \param peer_key_length Size of \p peer_key in bytes. + * \param alg The key agreement algorithm to compute + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_KEY_AGREEMENT(\p alg) is true). + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_EMPTY_SLOT + * \retval #PSA_ERROR_NOT_PERMITTED + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \c private_key is not compatible with \c alg, + * or \p peer_key is not valid for \c alg or not compatible with + * \c private_key. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \c alg is not supported or is not a key derivation algorithm. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_key_agreement(psa_crypto_generator_t *generator, + psa_key_slot_t private_key, + const uint8_t *peer_key, + size_t peer_key_length, + psa_algorithm_t alg); + /**@}*/ /** \defgroup random Random generation diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 3c1cec930..6f25d8b29 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -3589,6 +3589,66 @@ psa_status_t psa_key_derivation( psa_crypto_generator_t *generator, +/****************************************************************/ +/* Key agreement */ +/****************************************************************/ + +#define PSA_KEY_AGREEMENT_MAX_SHARED_SECRET_SIZE MBEDTLS_ECP_MAX_BYTES + +static psa_status_t psa_key_agreement_internal( psa_crypto_generator_t *generator, + key_slot_t *private_key, + const uint8_t *peer_key, + size_t peer_key_length, + psa_algorithm_t alg ) +{ + psa_status_t status; + uint8_t shared_secret[PSA_KEY_AGREEMENT_MAX_SHARED_SECRET_SIZE]; + size_t shared_secret_length = 0; + + /* Step 1: run the secret agreement algorithm to generate the shared + * secret. */ + switch( PSA_ALG_KEY_AGREEMENT_GET_BASE( alg ) ) + { + default: + return( PSA_ERROR_NOT_SUPPORTED ); + } + if( status != PSA_SUCCESS ) + goto exit; + + /* Step 2: set up the key derivation to generate key material from + * the shared secret. */ + status = psa_key_derivation_internal( generator, + shared_secret, shared_secret_length, + PSA_ALG_KEY_AGREEMENT_GET_KDF( alg ), + NULL, 0, NULL, 0, + PSA_GENERATOR_UNBRIDLED_CAPACITY ); +exit: + mbedtls_zeroize( shared_secret, shared_secret_length ); + return( status ); +} + +psa_status_t psa_key_agreement( psa_crypto_generator_t *generator, + psa_key_slot_t private_key, + const uint8_t *peer_key, + size_t peer_key_length, + psa_algorithm_t alg ) +{ + key_slot_t *slot; + psa_status_t status; + if( ! PSA_ALG_IS_KEY_AGREEMENT( alg ) ) + return( PSA_ERROR_INVALID_ARGUMENT ); + status = psa_get_key_from_slot( private_key, &slot, + PSA_KEY_USAGE_DERIVE, alg ); + if( status != PSA_SUCCESS ) + return( status ); + return( psa_key_agreement_internal( generator, + slot, + peer_key, peer_key_length, + alg ) ); +} + + + /****************************************************************/ /* Random generation */ /****************************************************************/ diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index 5759a15df..d321e68ff 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -435,6 +435,18 @@ PSA key policy: derive, wrong algorithm depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C derive_key_policy:PSA_KEY_USAGE_DERIVE:PSA_ALG_HKDF(PSA_ALG_SHA_256):PSA_KEY_TYPE_DERIVE:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HKDF(PSA_ALG_SHA_224) +PSA key policy: agreement, permitted +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):"3077020101042049c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eeea00a06082a8648ce3d030107a144034200047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45":PSA_ALG_ECDH(PSA_ALG_SELECT_RAW) + +PSA key policy: agreement, not permitted +depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDH_C +agreement_key_policy:0:PSA_ALG_ECDH(PSA_ALG_SELECT_RAW):PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1):"3077020101042049c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eeea00a06082a8648ce3d030107a144034200047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45":PSA_ALG_ECDH(PSA_ALG_SELECT_RAW) + +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):"3077020101042049c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eeea00a06082a8648ce3d030107a144034200047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45":PSA_ALG_FFDH(PSA_ALG_SELECT_RAW) + PSA key lifetime: set and get volatile key_lifetime:PSA_KEY_LIFETIME_VOLATILE @@ -1525,6 +1537,14 @@ PSA key derivation: HKDF SHA-256, derive key, 1+41 depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C derive_key_export:PSA_ALG_HKDF(PSA_ALG_SHA_256):"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"000102030405060708090a0b0c":"f0f1f2f3f4f5f6f7f8f9":1:41 +PSA key agreement setup: ECDH, unknown KDF +depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDH_C +key_agreement_setup:PSA_ALG_ECDH(0):PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1):"3078020101042100c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433a00a06082a8648ce3d030107a14403420004dad0b65394221cf9b051e1feca5787d098dfe637fc90b9ef945d0c37725811805271a0461cdb8252d61f1c456fa3e59ab1f45b33accf5f58389e0577b8990bb3":"3059301306072a8648ce3d020106082a8648ce3d03010703420004d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":PSA_ERROR_NOT_SUPPORTED + +PSA key agreement setup: not a key agreement algorithm +depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDH_C +key_agreement_setup:PSA_ALG_HKDF( PSA_ALG_SHA_256 ):PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1):"3078020101042100c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433a00a06082a8648ce3d030107a14403420004dad0b65394221cf9b051e1feca5787d098dfe637fc90b9ef945d0c37725811805271a0461cdb8252d61f1c456fa3e59ab1f45b33accf5f58389e0577b8990bb3":"3059301306072a8648ce3d020106082a8648ce3d03010703420004d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":PSA_ERROR_INVALID_ARGUMENT + PSA generate random: 0 bytes generate_random:0 diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index d2875ae34..b7b7c4c5d 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -392,6 +392,51 @@ exit: return( 0 ); } +static int exercise_key_agreement_key( psa_key_slot_t key, + psa_key_usage_t usage, + psa_algorithm_t alg ) +{ + psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT; + psa_key_type_t key_type; + psa_key_type_t public_key_type; + size_t key_bits; + uint8_t *public_key = NULL; + size_t public_key_length; + unsigned char output[1]; + int ok = 0; + + if( usage & PSA_KEY_USAGE_DERIVE ) + { + /* We need two keys to exercise key agreement. Exercise the + * private key against its own public key. */ + TEST_ASSERT( psa_get_key_information( key, + &key_type, + &key_bits ) == PSA_SUCCESS ); + public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR( key_type ); + public_key_length = PSA_KEY_EXPORT_MAX_SIZE( public_key_type, + key_bits ); + public_key = mbedtls_calloc( 1, public_key_length ); + TEST_ASSERT( public_key != NULL ); + TEST_ASSERT( + psa_export_public_key( key, + public_key, public_key_length, + &public_key_length ) == PSA_SUCCESS ); + TEST_ASSERT( psa_key_agreement( &generator, + key, + public_key, public_key_length, + alg ) == PSA_SUCCESS ); + TEST_ASSERT( psa_generator_read( &generator, + output, + sizeof( output ) ) == PSA_SUCCESS ); + TEST_ASSERT( psa_generator_abort( &generator ) == PSA_SUCCESS ); + } + ok = 1; + +exit: + mbedtls_free( public_key ); + return( ok ); +} + static int is_oid_of_key_type( psa_key_type_t type, const uint8_t *oid, size_t oid_length ) { @@ -737,6 +782,8 @@ static int exercise_key( psa_key_slot_t slot, ok = exercise_asymmetric_encryption_key( slot, usage, alg ); else if( PSA_ALG_IS_KEY_DERIVATION( alg ) ) ok = exercise_key_derivation_key( slot, usage, alg ); + else if( PSA_ALG_IS_KEY_AGREEMENT( alg ) ) + ok = exercise_key_agreement_key( slot, usage, alg ); else { char message[40]; @@ -1271,6 +1318,7 @@ void import_and_exercise_key( data_t *data, PSA_KEY_USAGE_ENCRYPT : PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT ) : PSA_ALG_IS_KEY_DERIVATION( alg ) ? PSA_KEY_USAGE_DERIVE : + PSA_ALG_IS_KEY_AGREEMENT( alg ) ? PSA_KEY_USAGE_DERIVE : 0 ); psa_key_policy_t policy; psa_key_type_t got_type; @@ -1642,6 +1690,61 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void agreement_key_policy( int policy_usage, + int policy_alg, + int key_type_arg, + data_t *key_data, + int exercise_alg ) +{ + int key_slot = 1; + psa_key_policy_t policy; + psa_key_type_t key_type = key_type_arg; + psa_key_type_t public_key_type; + size_t key_bits; + uint8_t *public_key = NULL; + size_t public_key_length; + psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT; + psa_status_t status; + + TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); + + psa_key_policy_init( &policy ); + psa_key_policy_set_usage( &policy, policy_usage, policy_alg ); + TEST_ASSERT( psa_set_key_policy( key_slot, &policy ) == PSA_SUCCESS ); + + TEST_ASSERT( psa_import_key( key_slot, key_type, + key_data->x, key_data->len ) == PSA_SUCCESS ); + + /* We need two keys to exercise key agreement. Exercise the + * private key against its own public key. */ + TEST_ASSERT( psa_get_key_information( key_slot, + &key_type, + &key_bits ) == PSA_SUCCESS ); + public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR( key_type ); + public_key_length = PSA_KEY_EXPORT_MAX_SIZE( public_key_type, key_bits ); + public_key = mbedtls_calloc( 1, public_key_length ); + TEST_ASSERT( public_key != NULL ); + TEST_ASSERT( psa_export_public_key( key_slot, + public_key, public_key_length, + &public_key_length ) == PSA_SUCCESS ); + + status = psa_key_agreement( &generator, key_slot, + public_key, public_key_length, + exercise_alg ); + if( policy_alg == exercise_alg && + ( policy_usage & PSA_KEY_USAGE_DERIVE ) != 0 ) + TEST_ASSERT( status == PSA_SUCCESS ); + else + TEST_ASSERT( status == PSA_ERROR_NOT_PERMITTED ); + +exit: + psa_generator_abort( &generator ); + psa_destroy_key( key_slot ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void key_lifetime( int lifetime_arg ) { @@ -3655,6 +3758,39 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void key_agreement_setup( int alg_arg, + int our_key_type_arg, data_t *our_key_data, + data_t *peer_key_data, + int expected_status_arg ) +{ + psa_key_slot_t our_key = 1; + psa_algorithm_t alg = alg_arg; + psa_key_type_t our_key_type = our_key_type_arg; + psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT; + psa_key_policy_t policy; + + TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); + + psa_key_policy_init( &policy ); + psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DERIVE, alg ); + TEST_ASSERT( psa_set_key_policy( our_key, &policy ) == PSA_SUCCESS ); + TEST_ASSERT( psa_import_key( our_key, our_key_type, + our_key_data->x, + our_key_data->len ) == PSA_SUCCESS ); + + TEST_ASSERT( psa_key_agreement( &generator, + our_key, + peer_key_data->x, peer_key_data->len, + alg ) == expected_status_arg ); + +exit: + psa_generator_abort( &generator ); + psa_destroy_key( our_key ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void generate_random( int bytes_arg ) {