From ea0fb4975c3be493773b9be7d57400ef9d99a107 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 12 Jul 2018 17:17:20 +0200 Subject: [PATCH] Add framework for simple key derivation New key type PSA_KEY_TYPE_DERIVE. New usage flag PSA_KEY_USAGE_DERIVE. New function psa_key_derivation. No key derivation algorithm is implemented yet. The code may not compile with -Wunused. Write some unit test code for psa_key_derivation. Most of it cannot be used yet due to the lack of a key derivation algorithm. --- include/psa/crypto.h | 62 +++++++++++ library/psa_crypto.c | 49 ++++++++- tests/suites/test_suite_psa_crypto.data | 4 + tests/suites/test_suite_psa_crypto.function | 111 ++++++++++++++++++++ 4 files changed, 224 insertions(+), 2 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 4dbbdedcd..9165463f5 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -366,6 +366,13 @@ typedef uint32_t psa_key_type_t; * \c alg is the HMAC algorithm or the underlying hash algorithm. */ #define PSA_KEY_TYPE_HMAC ((psa_key_type_t)0x02000001) +/** A secret for key derivation. + * + * The key policy determines which key derivation algorithm the key + * can be used for. + */ +#define PSA_KEY_TYPE_DERIVE ((psa_key_type_t)0x02000101) + /** 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 @@ -1194,6 +1201,10 @@ typedef uint32_t psa_key_usage_t; */ #define PSA_KEY_USAGE_VERIFY ((psa_key_usage_t)0x00000800) +/** Whether the key may be used to derive other keys. + */ +#define PSA_KEY_USAGE_DERIVE ((psa_key_usage_t)0x00001000) + /** The type of the key policy data structure. * * This is an implementation-defined \c struct. Applications should not @@ -2615,6 +2626,57 @@ psa_status_t psa_generator_abort(psa_crypto_generator_t *generator); /**@}*/ +/** \defgroup derivation Key derivation + * @{ + */ + +/** Set up a key derivation operation. + * + * A key derivation algorithm takes three inputs: a secret input \p key and + * two non-secret inputs \p label and p salt. + * The result of this function is a byte generator which can + * be used to produce keys and other cryptographic material. + * + * The role of \p label and \p salt is as follows: + * + * \param[in,out] generator The generator object to set up. It must + * have been initialized to . + * \param key Slot containing the secret key to use. + * \param alg The key derivation algorithm to compute + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_KEY_DERIVATION(\p alg) is true). + * \param[in] salt Salt to use. + * \param salt_length Size of the \p salt buffer in bytes. + * \param[in] label Label to use. + * \param label_length Size of the \p label buffer in bytes. + * \param capacity The maximum number of bytes that the + * generator will be able to provide. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_EMPTY_SLOT + * \retval #PSA_ERROR_NOT_PERMITTED + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \c key is not compatible with \c alg, + * or \p capacity is too large for the specified algorithm and 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_derivation(psa_crypto_generator_t *generator, + psa_key_type_t key, + psa_algorithm_t alg, + const uint8_t *salt, + size_t salt_length, + const uint8_t *label, + size_t label_length, + size_t capacity); + +/**@}*/ + /** \defgroup generation Key generation * @{ */ diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 6cc42c6ba..cc59ca800 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -498,8 +498,9 @@ static psa_status_t prepare_raw_data_slot( psa_key_type_t type, break; #if defined(MBEDTLS_MD_C) case PSA_KEY_TYPE_HMAC: - break; #endif + case PSA_KEY_TYPE_DERIVE: + break; #if defined(MBEDTLS_AES_C) case PSA_KEY_TYPE_AES: if( bits != 128 && bits != 192 && bits != 256 ) @@ -2651,7 +2652,8 @@ psa_status_t psa_set_key_policy( psa_key_slot_t key, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_SIGN | - PSA_KEY_USAGE_VERIFY ) ) != 0 ) + PSA_KEY_USAGE_VERIFY | + PSA_KEY_USAGE_DERIVE ) ) != 0 ) return( PSA_ERROR_INVALID_ARGUMENT ); slot->policy = *policy; @@ -3085,6 +3087,49 @@ exit: +/****************************************************************/ +/* Key derivation */ +/****************************************************************/ + +psa_status_t psa_key_derivation( psa_crypto_generator_t *generator, + psa_key_type_t key, + psa_algorithm_t alg, + const uint8_t *salt, + size_t salt_length, + const uint8_t *label, + size_t label_length, + size_t capacity ) +{ + key_slot_t *slot; + psa_status_t status; + + if( generator->alg != 0 ) + return( PSA_ERROR_BAD_STATE ); + + status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_DERIVE, alg ); + if( status != PSA_SUCCESS ) + return( status ); + if( slot->type != PSA_KEY_TYPE_DERIVE ) + return( PSA_ERROR_INVALID_ARGUMENT ); + + if( ! PSA_ALG_IS_KEY_DERIVATION( alg ) ) + return( PSA_ERROR_INVALID_ARGUMENT ); + + { + return( PSA_ERROR_NOT_SUPPORTED ); + } + + /* Set generator->alg even on failure so that abort knows what to do. */ + generator->alg = alg; + if( status == PSA_SUCCESS ) + generator->capacity = capacity; + else + psa_generator_abort( generator ); + return( status ); +} + + + /****************************************************************/ /* Random generation */ /****************************************************************/ diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index b44c347e2..1113eec81 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -745,6 +745,10 @@ PSA decrypt: RSA PKCS#1 v1.5, input too large depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15 asymmetric_decrypt_fail:PSA_KEY_TYPE_RSA_KEYPAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15_CRYPT:"0099ffde2fcc00c9cc01972ebfa7779b298dbbaf7f50707a7405296dd2783456fc792002f462e760500e02afa25a859ace8701cb5d3b0262116431c43af8eb08f5a88301057cf1c156a2a5193c143e7a5b03fac132b7e89e6dcd8f4c82c9b28452329c260d30bc39b3816b7c46b41b37b4850d2ae74e729f99c6621fbbe2e46872":PSA_ERROR_INVALID_ARGUMENT + +PSA key derivation: not a key derivation algorithm +depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C +derive_setup:PSA_KEY_TYPE_DERIVE:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_HMAC(PSA_ALG_SHA_256):"":"":42: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 37d6aca3f..278554f75 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -357,6 +357,36 @@ exit: return( 0 ); } +static int exercise_key_derivation_key( psa_key_slot_t key, + psa_key_usage_t usage, + psa_algorithm_t alg ) +{ + psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT; + unsigned char label[16] = "This is a label."; + size_t label_length = sizeof( label ); + unsigned char seed[16] = "abcdefghijklmnop"; + size_t seed_length = sizeof( seed ); + unsigned char output[1]; + + if( usage & PSA_KEY_USAGE_DERIVE ) + { + TEST_ASSERT( psa_key_derivation( &generator, + key, alg, + label, label_length, + seed, seed_length, + sizeof( output ) ) == PSA_SUCCESS ); + TEST_ASSERT( psa_generator_read( &generator, + output, + sizeof( output ) ) == PSA_SUCCESS ); + TEST_ASSERT( psa_generator_abort( &generator ) == PSA_SUCCESS ); + } + + return( 1 ); + +exit: + return( 0 ); +} + static int exercise_key( psa_key_slot_t slot, psa_key_usage_t usage, psa_algorithm_t alg ) @@ -374,6 +404,8 @@ static int exercise_key( psa_key_slot_t slot, ok = exercise_signature_key( slot, usage, alg ); else if( PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) ) 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 { char message[40]; @@ -657,6 +689,7 @@ void import_and_exercise_key( data_t *data, ( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ? PSA_KEY_USAGE_ENCRYPT : PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT ) : + PSA_ALG_IS_KEY_DERIVATION( alg ) ? PSA_KEY_USAGE_DERIVE : 0 ); psa_key_policy_t policy; psa_key_type_t got_type; @@ -991,6 +1024,45 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void derive_key_policy( int policy_usage, + int policy_alg, + int key_type, + data_t *key_data, + int exercise_alg ) +{ + int key_slot = 1; + psa_key_policy_t policy; + 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 ); + + status = psa_key_derivation( &generator, key_slot, + exercise_alg, + NULL, 0, + NULL, 0, + 1 ); + 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 ) { @@ -2372,6 +2444,45 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void derive_setup( int key_type_arg, + data_t *key_data, + int alg_arg, + data_t *salt, + data_t *label, + int requested_capacity_arg, + int expected_status_arg ) +{ + psa_key_slot_t slot = 1; + size_t key_type = key_type_arg; + psa_algorithm_t alg = alg_arg; + size_t requested_capacity = requested_capacity_arg; + psa_status_t expected_status = expected_status_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( slot, &policy ) == PSA_SUCCESS ); + + TEST_ASSERT( psa_import_key( slot, key_type, + key_data->x, + key_data->len ) == PSA_SUCCESS ); + + TEST_ASSERT( psa_key_derivation( &generator, slot, alg, + salt->x, salt->len, + label->x, label->len, + requested_capacity ) == expected_status ); + +exit: + psa_generator_abort( &generator ); + psa_destroy_key( slot ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void generate_random( int bytes_arg ) {