From f3801fff773bcf2641bf5a3aec341c2af923b892 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 6 Aug 2019 17:32:04 +0200 Subject: [PATCH 1/7] Update import_key and generate_key SE methods to the current API The methods to import and generate a key in a secure element drivers were written for an earlier version of the application-side interface. Now that there is a psa_key_attributes_t structure that combines all key metadata including its lifetime (location), type, size, policy and extra type-specific data (domain parameters), pass that to drivers instead of separate arguments for each piece of metadata. This makes the interface less cluttered. Update parameter names and descriptions to follow general conventions. Document the public-key output on key generation more precisely. Explain that it is optional in a driver, and when a driver would implement it. Declare that it is optional in the core, too (which means that a crypto core might not support drivers for secure elements that do need this feature). Update the implementation and the tests accordingly. --- include/psa/crypto_se_driver.h | 110 ++++++++++-------- library/psa_crypto.c | 5 +- ...st_suite_psa_crypto_se_driver_hal.function | 29 ++--- 3 files changed, 72 insertions(+), 72 deletions(-) diff --git a/include/psa/crypto_se_driver.h b/include/psa/crypto_se_driver.h index f04aa3468e..a43e0db48c 100644 --- a/include/psa/crypto_se_driver.h +++ b/include/psa/crypto_se_driver.h @@ -956,15 +956,21 @@ typedef psa_status_t (*psa_drv_se_validate_slot_number_t)( * documentation of psa_export_key() for the format for each key type. * * \param[in,out] drv_context The driver context structure. - * \param[in] key_slot Slot where the key will be stored + * \param key_slot Slot where the key will be stored. * This must be a valid slot for a key of the * chosen type. It must be unoccupied. - * \param[in] lifetime The required lifetime of the key storage - * \param[in] type Key type (a \c PSA_KEY_TYPE_XXX value) - * \param[in] algorithm Key algorithm (a \c PSA_ALG_XXX value) - * \param[in] usage The allowed uses of the key - * \param[in] p_data Buffer containing the key data - * \param[in] data_length Size of the `data` buffer in bytes + * \param[in] attributes The key attributes, including the lifetime, + * the key type and the usage policy. + * Drivers should not access the key size stored + * in the attributes: it may not match the + * data passed in \p data. + * Drivers can call psa_get_key_lifetime(), + * psa_get_key_type(), + * psa_get_key_usage_flags() and + * psa_get_key_algorithm() to access this + * information. + * \param[in] data Buffer containing the key data. + * \param[in] data_length Size of the \p data buffer in bytes. * \param[out] bits On success, the key size in bits. The driver * must determine this value after parsing the * key according to the key type. @@ -973,15 +979,13 @@ typedef psa_status_t (*psa_drv_se_validate_slot_number_t)( * \retval #PSA_SUCCESS * Success. */ -typedef psa_status_t (*psa_drv_se_import_key_t)(psa_drv_se_context_t *drv_context, - psa_key_slot_number_t key_slot, - psa_key_lifetime_t lifetime, - psa_key_type_t type, - psa_algorithm_t algorithm, - psa_key_usage_t usage, - const uint8_t *p_data, - size_t data_length, - size_t *bits); +typedef psa_status_t (*psa_drv_se_import_key_t)( + psa_drv_se_context_t *drv_context, + psa_key_slot_number_t key_slot, + const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + size_t *bits); /** * \brief A function that destroys a secure element key and restore the slot to @@ -1048,41 +1052,51 @@ typedef psa_status_t (*psa_drv_se_export_key_t)(psa_drv_se_context_t *drv_contex * element * * If \p type is asymmetric (#PSA_KEY_TYPE_IS_ASYMMETRIC(\p type) = 1), - * the public component of the generated key will be placed in `p_pubkey_out`. - * The format of the public key information will match the format specified for - * the psa_export_key() function for the key type. + * the driver may export the public key at the time of generation, + * in the format documented for psa_export_public_key() by writing it + * to the \p pubkey buffer. + * This is optional, intended for secure elements that output the + * public key at generation time and that cannot export the public key + * later. Drivers that do not need this feature should leave + * \p *pubkey_length set to 0 and should + * implement the psa_drv_key_management_t::p_export_public function. + * Some implementations do not support this feature, in which case + * \p pubkey is \c NULL and \p pubkey_size is 0. * * \param[in,out] drv_context The driver context structure. - * \param[in] key_slot Slot where the generated key will be placed - * \param[in] type The type of the key to be generated - * \param[in] usage The prescribed usage of the generated key - * Note: Not all Secure Elements support the same - * restrictions that PSA Crypto does (and vice - * versa). - * Driver developers should endeavor to match the - * usages as close as possible. - * \param[in] bits The size in bits of the key to be generated. - * \param[in] extra Extra parameters for key generation. The - * interpretation of this parameter should match - * the interpretation in the `extra` parameter is - * the `psa_generate_key` function - * \param[in] extra_size The size in bytes of the \p extra buffer - * \param[out] p_pubkey_out The buffer where the public key information will - * be placed - * \param[in] pubkey_out_size The size in bytes of the `p_pubkey_out` buffer - * \param[out] p_pubkey_length Upon successful completion, will contain the - * size of the data placed in `p_pubkey_out`. + * \param key_slot Slot where the key will be stored. + * This must be a valid slot for a key of the + * chosen type. It must be unoccupied. + * \param[in] attributes The key attributes, including the lifetime, + * the key type and size, and the usage policy. + * Drivers can call psa_get_key_lifetime(), + * psa_get_key_type(), psa_get_key_bits(), + * psa_get_key_usage_flags() and + * psa_get_key_algorithm() to access this + * information. + * \param[out] pubkey A buffer where the driver can write the + * public key, when generating an asymmetric + * key pair. + * This is \c NULL when generating a symmetric + * key or if the core does not support + * exporting the public key at generation time. + * \param pubkey_size The size of the `pubkey` buffer in bytes. + * This is 0 when generating a symmetric + * key or if the core does not support + * exporting the public key at generation time. + * \param[out] pubkey_length On entry, this is always 0. + * On success, the number of bytes written to + * \p pubkey. If this is 0 or unchanged on return, + * the core will not read the \p pubkey buffer, + * and will instead call the driver's + * psa_drv_key_management_t::p_export_public + * function to export the public key when needed. */ -typedef psa_status_t (*psa_drv_se_generate_key_t)(psa_drv_se_context_t *drv_context, - psa_key_slot_number_t key_slot, - psa_key_type_t type, - psa_key_usage_t usage, - size_t bits, - const void *extra, - size_t extra_size, - uint8_t *p_pubkey_out, - size_t pubkey_out_size, - size_t *p_pubkey_length); +typedef psa_status_t (*psa_drv_se_generate_key_t)( + psa_drv_se_context_t *drv_context, + psa_key_slot_number_t key_slot, + const psa_key_attributes_t *attributes, + uint8_t *pubkey, size_t pubkey_size, size_t *pubkey_length); /** * \brief A struct containing all of the function pointers needed to for secure diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 87ac037b60..f64487b854 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -1827,10 +1827,7 @@ psa_status_t psa_import_key( const psa_key_attributes_t *attributes, } status = drv->key_management->p_import( psa_get_se_driver_context( driver ), - slot->data.se.slot_number, - slot->attr.lifetime, slot->attr.type, - slot->attr.policy.alg, slot->attr.policy.usage, - data, data_length, + slot->data.se.slot_number, attributes, data, data_length, &bits ); if( status != PSA_SUCCESS ) goto exit; diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.function b/tests/suites/test_suite_psa_crypto_se_driver_hal.function index 4673835d5c..6c308512cb 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function @@ -81,21 +81,15 @@ static psa_status_t counter_allocate( psa_drv_se_context_t *context, /* Null import: do nothing, but pretend it worked. */ static psa_status_t null_import( psa_drv_se_context_t *context, psa_key_slot_number_t slot_number, - psa_key_lifetime_t lifetime, - psa_key_type_t type, - psa_algorithm_t algorithm, - psa_key_usage_t usage, - const uint8_t *p_data, + const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, size_t *bits ) { (void) context; (void) slot_number; - (void) lifetime; - (void) type; - (void) algorithm; - (void) usage; - (void) p_data; + (void) attributes; + (void) data; /* We're supposed to return a key size. Return one that's correct for * plain data keys. */ *bits = PSA_BYTES_TO_BITS( data_length ); @@ -132,11 +126,8 @@ static void ram_slots_reset( void ) static psa_status_t ram_import( psa_drv_se_context_t *context, psa_key_slot_number_t slot_number, - psa_key_lifetime_t lifetime, - psa_key_type_t type, - psa_algorithm_t algorithm, - psa_key_usage_t usage, - const uint8_t *p_data, + const psa_key_attributes_t *attributes, + const uint8_t *data, size_t data_length, size_t *bits ) { @@ -144,13 +135,11 @@ static psa_status_t ram_import( psa_drv_se_context_t *context, DRIVER_ASSERT( slot_number < ARRAY_LENGTH( ram_slots ) ); if( data_length > sizeof( ram_slots[slot_number].content ) ) return( PSA_ERROR_INSUFFICIENT_STORAGE ); - ram_slots[slot_number].lifetime = lifetime; - ram_slots[slot_number].type = type; + ram_slots[slot_number].lifetime = psa_get_key_lifetime( attributes ); + ram_slots[slot_number].type = psa_get_key_type( attributes ); ram_slots[slot_number].bits = PSA_BYTES_TO_BITS( data_length ); *bits = PSA_BYTES_TO_BITS( data_length ); - (void) algorithm; - (void) usage; - memcpy( ram_slots[slot_number].content, p_data, data_length ); + memcpy( ram_slots[slot_number].content, data, data_length ); return( PSA_SUCCESS ); } From 11792086cc475a6a362752de82447f38f936b638 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 6 Aug 2019 18:36:36 +0200 Subject: [PATCH 2/7] SE keys: implement and smoke-test p_generate --- library/psa_crypto.c | 22 ++++- .../test_suite_psa_crypto_se_driver_hal.data | 81 ++++++++++-------- ...st_suite_psa_crypto_se_driver_hal.function | 85 ++++++++++++++++++- 3 files changed, 147 insertions(+), 41 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index f64487b854..35c03dde3b 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -5944,21 +5944,37 @@ psa_status_t psa_generate_key( const psa_key_attributes_t *attributes, psa_status_t status; psa_key_slot_t *slot = NULL; psa_se_drv_table_entry_t *driver = NULL; + status = psa_start_key_creation( PSA_KEY_CREATION_GENERATE, attributes, handle, &slot, &driver ); + if( status != PSA_SUCCESS ) + goto exit; + #if defined(MBEDTLS_PSA_CRYPTO_SE_C) if( driver != NULL ) { - /* Generating a key in a secure element is not implemented yet. */ - status = PSA_ERROR_NOT_SUPPORTED; + const psa_drv_se_t *drv = psa_get_se_driver_methods( driver ); + size_t pubkey_length = 0; /* We don't support this feature yet */ + if( drv->key_management == NULL || + drv->key_management->p_generate == NULL ) + { + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + status = drv->key_management->p_generate( + psa_get_se_driver_context( driver ), + slot->data.se.slot_number, attributes, + NULL, 0, &pubkey_length ); } + else #endif /* MBEDTLS_PSA_CRYPTO_SE_C */ - if( status == PSA_SUCCESS ) { status = psa_generate_key_internal( slot, attributes->core.bits, attributes->domain_parameters, attributes->domain_parameters_size ); } + +exit: if( status == PSA_SUCCESS ) status = psa_finish_key_creation( slot, driver ); if( status != PSA_SUCCESS ) diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.data b/tests/suites/test_suite_psa_crypto_se_driver_hal.data index 267c7b88b7..0bec8419cd 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.data +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.data @@ -54,63 +54,72 @@ key_creation_in_chosen_slot:ARRAY_LENGTH( ram_slots ) - 1:1:PSA_SUCCESS Key creation in a specific slot (too large) key_creation_in_chosen_slot:ARRAY_LENGTH( ram_slots ):0:PSA_ERROR_INVALID_ARGUMENT -Key creation smoke test: AES-CTR -key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CTR:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: AES-CTR +import_key_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CTR:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: AES-CBC -key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CBC_NO_PADDING:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: AES-CBC +import_key_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CBC_NO_PADDING:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: AES-CMAC -key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: AES-CMAC +import_key_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: AES-CCM -key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: AES-CCM +import_key_smoke:PSA_KEY_TYPE_AES:PSA_ALG_CCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: AES-GCM -key_creation_smoke:PSA_KEY_TYPE_AES:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: AES-GCM +import_key_smoke:PSA_KEY_TYPE_AES:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: CAMELLIA-CTR -key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CTR:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: CAMELLIA-CTR +import_key_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CTR:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: CAMELLIA-CBC -key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CBC_NO_PADDING:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: CAMELLIA-CBC +import_key_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CBC_NO_PADDING:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: CAMELLIA-CMAC -key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: CAMELLIA-CMAC +import_key_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_CMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: CAMELLIA-CCM -key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: CAMELLIA-CCM +import_key_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: CAMELLIA-CCM -key_creation_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: CAMELLIA-CCM +import_key_smoke:PSA_KEY_TYPE_CAMELLIA:PSA_ALG_GCM:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: HMAC-SHA-256 -key_creation_smoke:PSA_KEY_TYPE_HMAC:PSA_ALG_HMAC( PSA_ALG_SHA_256 ):"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: HMAC-SHA-256 +import_key_smoke:PSA_KEY_TYPE_HMAC:PSA_ALG_HMAC( PSA_ALG_SHA_256 ):"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: HKDF-SHA-256 -key_creation_smoke:PSA_KEY_TYPE_DERIVE:PSA_ALG_HKDF( PSA_ALG_SHA_256 ):"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +Key import smoke test: HKDF-SHA-256 +import_key_smoke:PSA_KEY_TYPE_DERIVE:PSA_ALG_HKDF( PSA_ALG_SHA_256 ):"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -Key creation smoke test: RSA PKCS#1v1.5 signature -key_creation_smoke:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001" +Key import smoke test: RSA PKCS#1v1.5 signature +import_key_smoke:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001" -Key creation smoke test: RSA PKCS#1v1.5 encryption -key_creation_smoke:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_ALG_RSA_PKCS1V15_CRYPT:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001" +Key import smoke test: RSA PKCS#1v1.5 encryption +import_key_smoke:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_ALG_RSA_PKCS1V15_CRYPT:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001" -Key creation smoke test: RSA OAEP encryption -key_creation_smoke:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_ALG_RSA_OAEP( PSA_ALG_SHA_256 ):"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001" +Key import smoke test: RSA OAEP encryption +import_key_smoke:PSA_KEY_TYPE_RSA_KEY_PAIR:PSA_ALG_RSA_OAEP( PSA_ALG_SHA_256 ):"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001" -Key creation smoke test: ECDSA secp256r1 -key_creation_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee" +Key import smoke test: ECDSA secp256r1 +import_key_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee" -Key creation smoke test: ECDH secp256r1 -key_creation_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDH:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee" +Key import smoke test: ECDH secp256r1 +import_key_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDH:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee" -Key creation smoke test: ECDH secp256r1 with HKDF -key_creation_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_KEY_AGREEMENT( PSA_ALG_ECDH, PSA_ALG_HKDF( PSA_ALG_SHA_256 ) ):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee" +Key import smoke test: ECDH secp256r1 with HKDF +import_key_smoke:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_KEY_AGREEMENT( PSA_ALG_ECDH, PSA_ALG_HKDF( PSA_ALG_SHA_256 ) ):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee" Generate key: not supported generate_key_not_supported:PSA_KEY_TYPE_AES:128 +Key generation smoke test: AES-128-CTR +generate_key_smoke:PSA_KEY_TYPE_AES:128:PSA_ALG_CTR + +Key generation smoke test: AES-256-CTR +generate_key_smoke:PSA_KEY_TYPE_AES:128:PSA_ALG_CTR + +Key generation smoke test: HMAC-SHA-256 +generate_key_smoke:PSA_KEY_TYPE_HMAC:256:PSA_ALG_HMAC( PSA_ALG_SHA_256 ) + Key registration: smoke test register_key_smoke_test:MIN_DRIVER_LIFETIME:-1:PSA_SUCCESS diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.function b/tests/suites/test_suite_psa_crypto_se_driver_hal.function index 6c308512cb..d13e2f2481 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function @@ -96,6 +96,28 @@ static psa_status_t null_import( psa_drv_se_context_t *context, return( PSA_SUCCESS ); } +/* Null generate: do nothing, but pretend it worked. */ +static psa_status_t null_generate( psa_drv_se_context_t *context, + psa_key_slot_number_t slot_number, + const psa_key_attributes_t *attributes, + uint8_t *pubkey, + size_t pubkey_size, + size_t *pubkey_length ) +{ + (void) context; + (void) slot_number; + (void) attributes; + + DRIVER_ASSERT( *pubkey_length == 0 ); + if( ! PSA_KEY_TYPE_IS_KEY_PAIR( psa_get_key_type( attributes ) ) ) + { + DRIVER_ASSERT( pubkey == NULL ); + DRIVER_ASSERT( pubkey_size == 0 ); + } + + return( PSA_SUCCESS ); +} + /****************************************************************/ @@ -634,8 +656,8 @@ exit: /* END_CASE */ /* BEGIN_CASE */ -void key_creation_smoke( int type_arg, int alg_arg, - data_t *key_material ) +void import_key_smoke( int type_arg, int alg_arg, + data_t *key_material ) { psa_key_type_t type = type_arg; psa_algorithm_t alg = alg_arg; @@ -710,6 +732,7 @@ void generate_key_not_supported( int type_arg, int bits_arg ) driver.key_management = &key_management; driver.persistent_data_size = sizeof( psa_key_slot_number_t ); key_management.p_allocate = counter_allocate; + /* No p_generate method */ PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); PSA_ASSERT( psa_crypto_init( ) ); @@ -728,6 +751,64 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void generate_key_smoke( int type_arg, int bits_arg, int alg_arg ) +{ + psa_key_type_t type = type_arg; + psa_key_bits_t bits = bits_arg; + psa_algorithm_t alg = alg_arg; + psa_drv_se_t driver; + psa_drv_se_key_management_t key_management; + psa_key_lifetime_t lifetime = 2; + psa_key_id_t id = 1; + psa_key_handle_t handle = 0; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + + memset( &driver, 0, sizeof( driver ) ); + memset( &key_management, 0, sizeof( key_management ) ); + driver.hal_version = PSA_DRV_SE_HAL_VERSION; + driver.key_management = &key_management; + driver.persistent_data_size = sizeof( psa_key_slot_number_t ); + key_management.p_allocate = counter_allocate; + key_management.p_generate = null_generate; + + PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); + PSA_ASSERT( psa_crypto_init( ) ); + + /* Create a key. */ + psa_set_key_id( &attributes, id ); + psa_set_key_lifetime( &attributes, lifetime ); + psa_set_key_usage_flags( &attributes, + PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY | + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT | + PSA_KEY_USAGE_EXPORT ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_type( &attributes, type ); + psa_set_key_bits( &attributes, bits ); + PSA_ASSERT( psa_generate_key( &attributes, &handle ) ); + + /* Do stuff with the key. */ + if( ! smoke_test_key( handle ) ) + goto exit; + + /* Restart and try again. */ + mbedtls_psa_crypto_free( ); + PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); + PSA_ASSERT( psa_crypto_init( ) ); + PSA_ASSERT( psa_open_key( id, &handle ) ); + if( ! smoke_test_key( handle ) ) + goto exit; + + /* We're done. */ + PSA_ASSERT( psa_destroy_key( handle ) ); + +exit: + PSA_DONE( ); + ram_slots_reset( ); + psa_purge_storage( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void register_key_smoke_test( int lifetime_arg, int validate, From edc6424d7760f30879638eb4ecc9f8c798c1ee01 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Aug 2019 21:05:07 +0200 Subject: [PATCH 3/7] SE driver support: Implement sign and verify hooks --- library/psa_crypto.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 35c03dde3b..3a78f5653d 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -3331,10 +3331,14 @@ psa_status_t psa_asymmetric_sign( psa_key_handle_t handle, { psa_key_slot_t *slot; psa_status_t status; +#if defined(MBEDTLS_PSA_CRYPTO_SE_C) + const psa_drv_se_t *drv; + psa_drv_se_context_t *drv_context; +#endif /* MBEDTLS_PSA_CRYPTO_SE_C */ *signature_length = signature_size; - status = psa_get_transparent_key( handle, &slot, PSA_KEY_USAGE_SIGN, alg ); + status = psa_get_key_from_slot( handle, &slot, PSA_KEY_USAGE_SIGN, alg ); if( status != PSA_SUCCESS ) goto exit; if( ! PSA_KEY_TYPE_IS_KEY_PAIR( slot->attr.type ) ) @@ -3343,6 +3347,24 @@ psa_status_t psa_asymmetric_sign( psa_key_handle_t handle, goto exit; } +#if defined(MBEDTLS_PSA_CRYPTO_SE_C) + if( psa_get_se_driver( slot->attr.lifetime, &drv, &drv_context ) ) + { + if( drv->asymmetric == NULL || + drv->asymmetric->p_sign == NULL ) + { + status = PSA_ERROR_NOT_SUPPORTED; + goto exit; + } + status = drv->asymmetric->p_sign( drv_context, + slot->data.se.slot_number, + alg, + hash, hash_length, + signature, signature_size, + signature_length ); + } + else +#endif /* MBEDTLS_PSA_CRYPTO_SE_C */ #if defined(MBEDTLS_RSA_C) if( slot->attr.type == PSA_KEY_TYPE_RSA_KEY_PAIR ) { @@ -3406,11 +3428,29 @@ psa_status_t psa_asymmetric_verify( psa_key_handle_t handle, { psa_key_slot_t *slot; psa_status_t status; +#if defined(MBEDTLS_PSA_CRYPTO_SE_C) + const psa_drv_se_t *drv; + psa_drv_se_context_t *drv_context; +#endif /* MBEDTLS_PSA_CRYPTO_SE_C */ - status = psa_get_transparent_key( handle, &slot, PSA_KEY_USAGE_VERIFY, alg ); + status = psa_get_key_from_slot( handle, &slot, PSA_KEY_USAGE_VERIFY, alg ); if( status != PSA_SUCCESS ) return( status ); +#if defined(MBEDTLS_PSA_CRYPTO_SE_C) + if( psa_get_se_driver( slot->attr.lifetime, &drv, &drv_context ) ) + { + if( drv->asymmetric == NULL || + drv->asymmetric->p_verify == NULL ) + return( PSA_ERROR_NOT_SUPPORTED ); + return( drv->asymmetric->p_verify( drv_context, + slot->data.se.slot_number, + alg, + hash, hash_length, + signature, signature_length ) ); + } + else +#endif /* MBEDTLS_PSA_CRYPTO_SE_C */ #if defined(MBEDTLS_RSA_C) if( PSA_KEY_TYPE_IS_RSA( slot->attr.type ) ) { From eecadde6adb6b1d1c5662a449081823ab85a1047 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Aug 2019 21:05:24 +0200 Subject: [PATCH 4/7] SE support: Test sign and verify hooks with a passthrough driver --- .../test_suite_psa_crypto_se_driver_hal.data | 16 + ...st_suite_psa_crypto_se_driver_hal.function | 296 +++++++++++++++++- 2 files changed, 298 insertions(+), 14 deletions(-) diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.data b/tests/suites/test_suite_psa_crypto_se_driver_hal.data index 0bec8419cd..bdd5703b0c 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.data +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.data @@ -137,3 +137,19 @@ register_key_smoke_test:MIN_DRIVER_LIFETIME:1:PSA_SUCCESS Key registration: with driver validation (rejected) register_key_smoke_test:MIN_DRIVER_LIFETIME:0:PSA_ERROR_NOT_PERMITTED + +Import-sign-verify: sign in driver, ECDSA +depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED +sign_verify:1:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:0:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" + +Import-sign-verify: sign in software, ECDSA +depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED +sign_verify:0:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:0:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" + +Generate-sign-verify: sign in driver, ECDSA +depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED +sign_verify:1:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:256:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" + +Generate-sign-verify: sign in software, ECDSA +depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED +sign_verify:0:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:256:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.function b/tests/suites/test_suite_psa_crypto_se_driver_hal.function index d13e2f2481..e14fa5838c 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function @@ -18,7 +18,25 @@ * This is probably a bug in the library. */ #define PSA_ERROR_DETECTED_BY_DRIVER ((psa_status_t)( -500 )) -/** Like #TEST_ASSERT for use in a driver method. +/** Like #TEST_ASSERT for use in a driver method, with no cleanup. + * + * If an error happens, this macro returns from the calling function. + * + * Use this macro to assert on guarantees provided by the core. + */ +#define DRIVER_ASSERT_RETURN( TEST ) \ + do { \ + if( ! (TEST) ) \ + { \ + test_fail( #TEST, __LINE__, __FILE__ ); \ + return( PSA_ERROR_DETECTED_BY_DRIVER ); \ + } \ + } while( 0 ) + +/** Like #TEST_ASSERT for use in a driver method, with cleanup. + * + * In case of error, this macro sets `status` and jumps to the + * label `exit`. * * Use this macro to assert on guarantees provided by the core. */ @@ -27,10 +45,34 @@ if( ! (TEST) ) \ { \ test_fail( #TEST, __LINE__, __FILE__ ); \ - return( PSA_ERROR_DETECTED_BY_DRIVER ); \ + status = PSA_ERROR_DETECTED_BY_DRIVER; \ + goto exit; \ } \ } while( 0 ) +/** Like #PSA_ASSERT for a PSA API call that calls a driver underneath. + * + * Run the code \p expr. If this returns \p expected_status, + * do nothing. If this returns #PSA_ERROR_DETECTED_BY_DRIVER, + * jump directly to the `exit` label. If this returns any other + * status, call test_fail() then jump to `exit`. + * + * The special case for #PSA_ERROR_DETECTED_BY_DRIVER is because in this + * case, the test driver code is expected to have called test_fail() + * already, so we make sure not to overwrite the failure information. + */ +#define PSA_ASSERT_VIA_DRIVER( expr, expected_status ) \ + do { \ + psa_status_t PSA_ASSERT_VIA_DRIVER_status = ( expr ); \ + if( PSA_ASSERT_VIA_DRIVER_status == PSA_ERROR_DETECTED_BY_DRIVER ) \ + goto exit; \ + if( PSA_ASSERT_VIA_DRIVER_status != ( expected_status ) ) \ + { \ + test_fail( #expr, __LINE__, __FILE__ ); \ + goto exit; \ + } \ + } while( 0 ) + /****************************************************************/ @@ -54,8 +96,10 @@ static psa_status_t validate_slot_number_as_directed( { (void) context; (void) attributes; - DRIVER_ASSERT( slot_number == validate_slot_number_directions.slot_number ); - DRIVER_ASSERT( method == validate_slot_number_directions.method ); + DRIVER_ASSERT_RETURN( slot_number == + validate_slot_number_directions.slot_number ); + DRIVER_ASSERT_RETURN( method == + validate_slot_number_directions.method ); return( validate_slot_number_directions.status ); } @@ -108,11 +152,11 @@ static psa_status_t null_generate( psa_drv_se_context_t *context, (void) slot_number; (void) attributes; - DRIVER_ASSERT( *pubkey_length == 0 ); + DRIVER_ASSERT_RETURN( *pubkey_length == 0 ); if( ! PSA_KEY_TYPE_IS_KEY_PAIR( psa_get_key_type( attributes ) ) ) { - DRIVER_ASSERT( pubkey == NULL ); - DRIVER_ASSERT( pubkey_size == 0 ); + DRIVER_ASSERT_RETURN( pubkey == NULL ); + DRIVER_ASSERT_RETURN( pubkey_size == 0 ); } return( PSA_SUCCESS ); @@ -146,6 +190,42 @@ static void ram_slots_reset( void ) ram_min_slot = 0; } +/* This function does everything except actually generating key material. + * After calling it, you must copy the desired key material to + * ram_slots[slot_number].content. */ +static psa_status_t ram_fake_generate( psa_drv_se_context_t *context, + psa_key_slot_number_t slot_number, + const psa_key_attributes_t *attributes, + uint8_t *pubkey, + size_t pubkey_size, + size_t *pubkey_length ) +{ + (void) context; + + DRIVER_ASSERT_RETURN( *pubkey_length == 0 ); + if( ! PSA_KEY_TYPE_IS_KEY_PAIR( psa_get_key_type( attributes ) ) ) + { + DRIVER_ASSERT_RETURN( pubkey == NULL ); + DRIVER_ASSERT_RETURN( pubkey_size == 0 ); + } + + { + /* Check that the key can be stored in the memory slot. + * This check only works for key in a "raw" representation: + * symmetric keys or ECC are ok, but not RSA or FFDH. */ + size_t required_storage = + PSA_BITS_TO_BYTES( psa_get_key_bits( attributes ) ); + size_t available_storage = sizeof( ram_slots[slot_number].content ); + if( required_storage > available_storage ) + return( PSA_ERROR_INSUFFICIENT_STORAGE ); + } + + ram_slots[slot_number].lifetime = psa_get_key_lifetime( attributes ); + ram_slots[slot_number].type = psa_get_key_type( attributes ); + ram_slots[slot_number].bits = psa_get_key_bits( attributes ); + return( PSA_SUCCESS ); +} + static psa_status_t ram_import( psa_drv_se_context_t *context, psa_key_slot_number_t slot_number, const psa_key_attributes_t *attributes, @@ -154,7 +234,7 @@ static psa_status_t ram_import( psa_drv_se_context_t *context, size_t *bits ) { (void) context; - DRIVER_ASSERT( slot_number < ARRAY_LENGTH( ram_slots ) ); + DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); if( data_length > sizeof( ram_slots[slot_number].content ) ) return( PSA_ERROR_INSUFFICIENT_STORAGE ); ram_slots[slot_number].lifetime = psa_get_key_lifetime( attributes ); @@ -173,7 +253,7 @@ static psa_status_t ram_export( psa_drv_se_context_t *context, { size_t actual_size; (void) context; - DRIVER_ASSERT( slot_number < ARRAY_LENGTH( ram_slots ) ); + DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); actual_size = PSA_BITS_TO_BYTES( ram_slots[slot_number].bits ); if( actual_size > data_size ) return( PSA_ERROR_BUFFER_TOO_SMALL ); @@ -187,8 +267,8 @@ static psa_status_t ram_destroy( psa_drv_se_context_t *context, psa_key_slot_number_t slot_number ) { ram_slot_usage_t *slot_usage = persistent_data; - DRIVER_ASSERT( context->persistent_data_size == sizeof( ram_slot_usage_t ) ); - DRIVER_ASSERT( slot_number < ARRAY_LENGTH( ram_slots ) ); + DRIVER_ASSERT_RETURN( context->persistent_data_size == sizeof( ram_slot_usage_t ) ); + DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); memset( &ram_slots[slot_number], 0, sizeof( ram_slots[slot_number] ) ); *slot_usage &= ~(ram_slot_usage_t)( 1 << slot_number ); return( PSA_SUCCESS ); @@ -203,7 +283,7 @@ static psa_status_t ram_allocate( psa_drv_se_context_t *context, ram_slot_usage_t *slot_usage = persistent_data; (void) attributes; (void) method; - DRIVER_ASSERT( context->persistent_data_size == sizeof( ram_slot_usage_t ) ); + DRIVER_ASSERT_RETURN( context->persistent_data_size == sizeof( ram_slot_usage_t ) ); for( *slot_number = ram_min_slot; *slot_number < ARRAY_LENGTH( ram_slots ); ++( *slot_number ) ) @@ -228,6 +308,76 @@ static psa_status_t ram_validate_slot_number( return( PSA_SUCCESS ); } +static psa_status_t ram_sign( psa_drv_se_context_t *context, + psa_key_slot_number_t slot_number, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length ) +{ + ram_slot_t *slot; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_handle_t handle = 0; + psa_status_t status = PSA_ERROR_GENERIC_ERROR; + + (void) context; + DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); + slot = &ram_slots[slot_number]; + + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_type( &attributes, slot->type ); + DRIVER_ASSERT( psa_import_key( &attributes, + slot->content, + PSA_BITS_TO_BYTES( slot->bits ), + &handle ) == PSA_SUCCESS ); + status = psa_asymmetric_sign( handle, alg, + hash, hash_length, + signature, signature_size, + signature_length ); + +exit: + psa_destroy_key( handle ); + return( status ); +} + +static psa_status_t ram_verify( psa_drv_se_context_t *context, + psa_key_slot_number_t slot_number, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_length ) +{ + ram_slot_t *slot; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_handle_t handle = 0; + psa_status_t status = PSA_ERROR_GENERIC_ERROR; + + (void) context; + DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); + slot = &ram_slots[slot_number]; + + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_type( &attributes, slot->type ); + DRIVER_ASSERT( psa_import_key( &attributes, + slot->content, + PSA_BITS_TO_BYTES( slot->bits ), + &handle ) == + PSA_SUCCESS ); + status = psa_asymmetric_verify( handle, alg, + hash, hash_length, + signature, signature_length ); + +exit: + psa_destroy_key( handle ); + return( status ); +} + + /****************************************************************/ @@ -709,7 +859,6 @@ void import_key_smoke( int type_arg, int alg_arg, exit: PSA_DONE( ); - ram_slots_reset( ); psa_purge_storage( ); } /* END_CASE */ @@ -746,7 +895,6 @@ void generate_key_not_supported( int type_arg, int bits_arg ) exit: PSA_DONE( ); - ram_slots_reset( ); psa_purge_storage( ); } /* END_CASE */ @@ -803,6 +951,126 @@ void generate_key_smoke( int type_arg, int bits_arg, int alg_arg ) PSA_ASSERT( psa_destroy_key( handle ) ); exit: + PSA_DONE( ); + psa_purge_storage( ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void sign_verify( int sign_in_driver, + int type_arg, int alg_arg, + int bits_arg, data_t *key_material, + data_t *input ) +{ + psa_key_type_t type = type_arg; + psa_algorithm_t alg = alg_arg; + size_t bits = bits_arg; + /* Pass bits=0 to import, bits>0 to fake-generate */ + int generating = ( bits != 0 ); + + psa_drv_se_t driver; + psa_drv_se_key_management_t key_management; + psa_drv_se_asymmetric_t asymmetric; + + psa_key_lifetime_t lifetime = 2; + psa_key_id_t id = 1; + psa_key_handle_t drv_handle = 0; /* key managed by the driver */ + psa_key_handle_t sw_handle = 0; /* transparent key */ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + uint8_t signature[PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE]; + size_t signature_length; + + memset( &driver, 0, sizeof( driver ) ); + memset( &key_management, 0, sizeof( key_management ) ); + driver.hal_version = PSA_DRV_SE_HAL_VERSION; + driver.key_management = &key_management; + driver.asymmetric = &asymmetric; + driver.persistent_data_size = sizeof( psa_key_slot_number_t ); + driver.persistent_data_size = sizeof( ram_slot_usage_t ); + key_management.p_allocate = ram_allocate; + key_management.p_destroy = ram_destroy; + if( generating ) + key_management.p_generate = ram_fake_generate; + else + key_management.p_import = ram_import; + if( sign_in_driver ) + asymmetric.p_sign = ram_sign; + asymmetric.p_verify = ram_verify; + + PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); + PSA_ASSERT( psa_crypto_init( ) ); + + /* Create two keys with the same key material: a transparent key, + * and one that goes through the driver. */ + psa_set_key_usage_flags( &attributes, + PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_type( &attributes, type ); + PSA_ASSERT( psa_import_key( &attributes, + key_material->x, key_material->len, + &sw_handle ) ); + psa_set_key_id( &attributes, id ); + psa_set_key_lifetime( &attributes, lifetime ); + if( generating ) + { + psa_set_key_bits( &attributes, bits ); + PSA_ASSERT( psa_generate_key( &attributes, &drv_handle ) ); + /* Since we called a generate method that does not actually + * generate material, store the desired result of generation in + * the mock secure element storage. */ + PSA_ASSERT( psa_get_key_attributes( drv_handle, &attributes ) ); + TEST_ASSERT( key_material->len == PSA_BITS_TO_BYTES( bits ) ); + memcpy( ram_slots[ram_min_slot].content, key_material->x, + key_material->len ); + } + else + { + PSA_ASSERT( psa_import_key( &attributes, + key_material->x, key_material->len, + &drv_handle ) ); + } + + /* Sign with the chosen key. */ + if( sign_in_driver ) + PSA_ASSERT_VIA_DRIVER( + psa_asymmetric_sign( drv_handle, + alg, + input->x, input->len, + signature, sizeof( signature ), + &signature_length ), + PSA_SUCCESS ); + else + PSA_ASSERT( psa_asymmetric_sign( sw_handle, + alg, + input->x, input->len, + signature, sizeof( signature ), + &signature_length ) ); + + /* Verify with both keys. */ + PSA_ASSERT( psa_asymmetric_verify( sw_handle, alg, + input->x, input->len, + signature, signature_length ) ); + PSA_ASSERT_VIA_DRIVER( + psa_asymmetric_verify( drv_handle, alg, + input->x, input->len, + signature, signature_length ), + PSA_SUCCESS ); + + /* Change the signature and verify again. */ + signature[0] ^= 1; + TEST_EQUAL( psa_asymmetric_verify( sw_handle, alg, + input->x, input->len, + signature, signature_length ), + PSA_ERROR_INVALID_SIGNATURE ); + PSA_ASSERT_VIA_DRIVER( + psa_asymmetric_verify( drv_handle, alg, + input->x, input->len, + signature, signature_length ), + PSA_ERROR_INVALID_SIGNATURE ); + +exit: + psa_destroy_key( drv_handle ); + psa_destroy_key( sw_handle ); PSA_DONE( ); ram_slots_reset( ); psa_purge_storage( ); From c068ded0155e76ed951c5eb57c07a69aa13d7470 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 9 Aug 2019 12:49:06 +0200 Subject: [PATCH 5/7] RAM test driver: improve key creation Factor common code of ram_import and ram_fake_generate into a common auxiliary function. Reject key types that aren't supported by this test code. Report the bit size correctly for EC key pairs. --- ...st_suite_psa_crypto_se_driver_hal.function | 85 +++++++++++++------ 1 file changed, 59 insertions(+), 26 deletions(-) diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.function b/tests/suites/test_suite_psa_crypto_se_driver_hal.function index e14fa5838c..4cba693c2b 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function @@ -190,6 +190,35 @@ static void ram_slots_reset( void ) ram_min_slot = 0; } +/* Common parts of key creation. + * + * In case of error, zero out ram_slots[slot_number]. But don't + * do that if the error is PSA_ERROR_DETECTED_BY_DRIVER: in this case + * you don't need to clean up (ram_slot_reset() will take care of it + * in the test case function's cleanup code) and it might be wrong + * (if slot_number is invalid). + */ +static psa_status_t ram_create_common( psa_drv_se_context_t *context, + psa_key_slot_number_t slot_number, + const psa_key_attributes_t *attributes, + size_t required_storage ) +{ + (void) context; + DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); + + ram_slots[slot_number].lifetime = psa_get_key_lifetime( attributes ); + ram_slots[slot_number].type = psa_get_key_type( attributes ); + ram_slots[slot_number].bits = psa_get_key_bits( attributes ); + + if( required_storage > sizeof( ram_slots[slot_number].content ) ) + { + memset( &ram_slots[slot_number], 0, sizeof( ram_slots[slot_number] ) ); + return( PSA_ERROR_INSUFFICIENT_STORAGE ); + } + + return( PSA_SUCCESS ); +} + /* This function does everything except actually generating key material. * After calling it, you must copy the desired key material to * ram_slots[slot_number].content. */ @@ -200,7 +229,10 @@ static psa_status_t ram_fake_generate( psa_drv_se_context_t *context, size_t pubkey_size, size_t *pubkey_length ) { - (void) context; + psa_status_t status; + size_t required_storage = + PSA_KEY_EXPORT_MAX_SIZE( psa_get_key_type( attributes ), + psa_get_key_bits( attributes ) ); DRIVER_ASSERT_RETURN( *pubkey_length == 0 ); if( ! PSA_KEY_TYPE_IS_KEY_PAIR( psa_get_key_type( attributes ) ) ) @@ -209,21 +241,9 @@ static psa_status_t ram_fake_generate( psa_drv_se_context_t *context, DRIVER_ASSERT_RETURN( pubkey_size == 0 ); } - { - /* Check that the key can be stored in the memory slot. - * This check only works for key in a "raw" representation: - * symmetric keys or ECC are ok, but not RSA or FFDH. */ - size_t required_storage = - PSA_BITS_TO_BYTES( psa_get_key_bits( attributes ) ); - size_t available_storage = sizeof( ram_slots[slot_number].content ); - if( required_storage > available_storage ) - return( PSA_ERROR_INSUFFICIENT_STORAGE ); - } - - ram_slots[slot_number].lifetime = psa_get_key_lifetime( attributes ); - ram_slots[slot_number].type = psa_get_key_type( attributes ); - ram_slots[slot_number].bits = psa_get_key_bits( attributes ); - return( PSA_SUCCESS ); + status = ram_create_common( context, slot_number, attributes, + required_storage ); + return( status ); } static psa_status_t ram_import( psa_drv_se_context_t *context, @@ -233,23 +253,36 @@ static psa_status_t ram_import( psa_drv_se_context_t *context, size_t data_length, size_t *bits ) { - (void) context; - DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); - if( data_length > sizeof( ram_slots[slot_number].content ) ) - return( PSA_ERROR_INSUFFICIENT_STORAGE ); - ram_slots[slot_number].lifetime = psa_get_key_lifetime( attributes ); - ram_slots[slot_number].type = psa_get_key_type( attributes ); - ram_slots[slot_number].bits = PSA_BYTES_TO_BITS( data_length ); - *bits = PSA_BYTES_TO_BITS( data_length ); + psa_key_type_t type = psa_get_key_type( attributes ); + psa_status_t status = ram_create_common( context, slot_number, attributes, + data_length ); + if( status != PSA_SUCCESS ) + return( status ); + + /* The RAM driver only works for certain key types: raw keys, + * and ECC key pairs. This is true in particular of the bit-size + * calculation here. */ + if( PSA_KEY_TYPE_IS_UNSTRUCTURED( type ) ) + *bits = PSA_BYTES_TO_BITS( data_length ); + else if ( PSA_KEY_TYPE_IS_ECC_KEY_PAIR( type ) ) + *bits = PSA_ECC_CURVE_BITS( PSA_KEY_TYPE_GET_CURVE( type ) ); + else + { + memset( &ram_slots[slot_number], 0, sizeof( ram_slots[slot_number] ) ); + return( PSA_ERROR_NOT_SUPPORTED ); + } + + ram_slots[slot_number].bits = *bits; memcpy( ram_slots[slot_number].content, data, data_length ); + return( PSA_SUCCESS ); } static psa_status_t ram_export( psa_drv_se_context_t *context, psa_key_slot_number_t slot_number, - uint8_t *p_data, + uint8_t *data, size_t data_size, - size_t *p_data_length ) + size_t *data_length ) { size_t actual_size; (void) context; From af906f852cf20f24cd49a90ae303bee71a098536 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 9 Aug 2019 12:50:18 +0200 Subject: [PATCH 6/7] RAM test driver: implement export_public --- ...st_suite_psa_crypto_se_driver_hal.function | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.function b/tests/suites/test_suite_psa_crypto_se_driver_hal.function index 4cba693c2b..4757f6c0ce 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function @@ -290,8 +290,35 @@ static psa_status_t ram_export( psa_drv_se_context_t *context, actual_size = PSA_BITS_TO_BYTES( ram_slots[slot_number].bits ); if( actual_size > data_size ) return( PSA_ERROR_BUFFER_TOO_SMALL ); - *p_data_length = actual_size; - memcpy( p_data, ram_slots[slot_number].content, actual_size ); + *data_length = actual_size; + memcpy( data, ram_slots[slot_number].content, actual_size ); + return( PSA_SUCCESS ); +} + +static psa_status_t ram_export_public( psa_drv_se_context_t *context, + psa_key_slot_number_t slot_number, + uint8_t *data, + size_t data_size, + size_t *data_length ) +{ + psa_status_t status; + psa_key_handle_t handle; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + + (void) context; + DRIVER_ASSERT_RETURN( slot_number < ARRAY_LENGTH( ram_slots ) ); + DRIVER_ASSERT_RETURN( + PSA_KEY_TYPE_IS_KEY_PAIR( ram_slots[slot_number].type ) ); + + psa_set_key_type( &attributes, ram_slots[slot_number].type ); + status = psa_import_key( &attributes, + ram_slots[slot_number].content, + PSA_BITS_TO_BYTES( ram_slots[slot_number].bits ), + &handle ); + if( status != PSA_SUCCESS ) + return( status ); + status = psa_export_public_key( handle, data, data_size, data_length ); + psa_destroy_key( handle ); return( PSA_SUCCESS ); } From 8df72f271f593116810795cad52b02693fd52ae5 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 9 Aug 2019 12:50:39 +0200 Subject: [PATCH 7/7] SE generate/sign/verify tests: also test export_public Add a flow where the key is imported or fake-generated in the secure element, then call psa_export_public_key and do the software verification with the public key. --- .../test_suite_psa_crypto_se_driver_hal.data | 16 ++- ...st_suite_psa_crypto_se_driver_hal.function | 119 +++++++++++++----- 2 files changed, 98 insertions(+), 37 deletions(-) diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.data b/tests/suites/test_suite_psa_crypto_se_driver_hal.data index bdd5703b0c..5819f785b3 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.data +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.data @@ -140,16 +140,24 @@ register_key_smoke_test:MIN_DRIVER_LIFETIME:0:PSA_ERROR_NOT_PERMITTED Import-sign-verify: sign in driver, ECDSA depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED -sign_verify:1:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:0:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" +sign_verify:SIGN_IN_DRIVER_AND_PARALLEL_CREATION:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:0:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" + +Import-sign-verify: sign in driver then export_public, ECDSA +depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED +sign_verify:SIGN_IN_DRIVER_THEN_EXPORT_PUBLIC:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:0:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" Import-sign-verify: sign in software, ECDSA depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED -sign_verify:0:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:0:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" +sign_verify:SIGN_IN_SOFTWARE_AND_PARALLEL_CREATION:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:0:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" Generate-sign-verify: sign in driver, ECDSA depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED -sign_verify:1:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:256:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" +sign_verify:SIGN_IN_DRIVER_AND_PARALLEL_CREATION:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:256:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" + +Generate-sign-verify: sign in driver then export_public, ECDSA +depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED +sign_verify:SIGN_IN_DRIVER_THEN_EXPORT_PUBLIC:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:256:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" Generate-sign-verify: sign in software, ECDSA depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED -sign_verify:0:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:256:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" +sign_verify:SIGN_IN_SOFTWARE_AND_PARALLEL_CREATION:PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_CURVE_SECP256R1 ):PSA_ALG_ECDSA_ANY:256:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":"54686973206973206e6f74206120686173682e" diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.function b/tests/suites/test_suite_psa_crypto_se_driver_hal.function index 4757f6c0ce..202f18c6de 100644 --- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function +++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function @@ -444,6 +444,13 @@ exit: /* Other test helper functions */ /****************************************************************/ +typedef enum +{ + SIGN_IN_SOFTWARE_AND_PARALLEL_CREATION, + SIGN_IN_DRIVER_AND_PARALLEL_CREATION, + SIGN_IN_DRIVER_THEN_EXPORT_PUBLIC, +} sign_verify_method_t; + /* Check that the attributes of a key reported by psa_get_key_attributes() * are consistent with the attributes used when creating the key. */ static int check_key_attributes( @@ -1017,7 +1024,7 @@ exit: /* END_CASE */ /* BEGIN_CASE */ -void sign_verify( int sign_in_driver, +void sign_verify( int flow, int type_arg, int alg_arg, int bits_arg, data_t *key_material, data_t *input ) @@ -1036,16 +1043,17 @@ void sign_verify( int sign_in_driver, psa_key_id_t id = 1; psa_key_handle_t drv_handle = 0; /* key managed by the driver */ psa_key_handle_t sw_handle = 0; /* transparent key */ - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_attributes_t sw_attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_attributes_t drv_attributes; uint8_t signature[PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE]; size_t signature_length; memset( &driver, 0, sizeof( driver ) ); memset( &key_management, 0, sizeof( key_management ) ); + memset( &asymmetric, 0, sizeof( asymmetric ) ); driver.hal_version = PSA_DRV_SE_HAL_VERSION; driver.key_management = &key_management; driver.asymmetric = &asymmetric; - driver.persistent_data_size = sizeof( psa_key_slot_number_t ); driver.persistent_data_size = sizeof( ram_slot_usage_t ); key_management.p_allocate = ram_allocate; key_management.p_destroy = ram_destroy; @@ -1053,58 +1061,103 @@ void sign_verify( int sign_in_driver, key_management.p_generate = ram_fake_generate; else key_management.p_import = ram_import; - if( sign_in_driver ) - asymmetric.p_sign = ram_sign; + switch( flow ) + { + case SIGN_IN_SOFTWARE_AND_PARALLEL_CREATION: + break; + case SIGN_IN_DRIVER_AND_PARALLEL_CREATION: + asymmetric.p_sign = ram_sign; + break; + case SIGN_IN_DRIVER_THEN_EXPORT_PUBLIC: + asymmetric.p_sign = ram_sign; + key_management.p_export_public = ram_export_public; + break; + default: + TEST_ASSERT( ! "unsupported flow (should be SIGN_IN_xxx)" ); + break; + } asymmetric.p_verify = ram_verify; PSA_ASSERT( psa_register_se_driver( lifetime, &driver ) ); PSA_ASSERT( psa_crypto_init( ) ); - /* Create two keys with the same key material: a transparent key, - * and one that goes through the driver. */ - psa_set_key_usage_flags( &attributes, + /* Prepare to create two keys with the same key material: a transparent + * key, and one that goes through the driver. */ + psa_set_key_usage_flags( &sw_attributes, PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY ); - psa_set_key_algorithm( &attributes, alg ); - psa_set_key_type( &attributes, type ); - PSA_ASSERT( psa_import_key( &attributes, - key_material->x, key_material->len, - &sw_handle ) ); - psa_set_key_id( &attributes, id ); - psa_set_key_lifetime( &attributes, lifetime ); + psa_set_key_algorithm( &sw_attributes, alg ); + psa_set_key_type( &sw_attributes, type ); + drv_attributes = sw_attributes; + psa_set_key_id( &drv_attributes, id ); + psa_set_key_lifetime( &drv_attributes, lifetime ); + + /* Create the key in the driver. */ if( generating ) { - psa_set_key_bits( &attributes, bits ); - PSA_ASSERT( psa_generate_key( &attributes, &drv_handle ) ); + psa_set_key_bits( &drv_attributes, bits ); + PSA_ASSERT( psa_generate_key( &drv_attributes, &drv_handle ) ); /* Since we called a generate method that does not actually * generate material, store the desired result of generation in * the mock secure element storage. */ - PSA_ASSERT( psa_get_key_attributes( drv_handle, &attributes ) ); + PSA_ASSERT( psa_get_key_attributes( drv_handle, &drv_attributes ) ); TEST_ASSERT( key_material->len == PSA_BITS_TO_BYTES( bits ) ); memcpy( ram_slots[ram_min_slot].content, key_material->x, key_material->len ); } else { - PSA_ASSERT( psa_import_key( &attributes, + PSA_ASSERT( psa_import_key( &drv_attributes, key_material->x, key_material->len, &drv_handle ) ); } + /* Either import the same key in software, or export the driver's + * public key and import that. */ + switch( flow ) + { + case SIGN_IN_SOFTWARE_AND_PARALLEL_CREATION: + case SIGN_IN_DRIVER_AND_PARALLEL_CREATION: + PSA_ASSERT( psa_import_key( &sw_attributes, + key_material->x, key_material->len, + &sw_handle ) ); + break; + case SIGN_IN_DRIVER_THEN_EXPORT_PUBLIC: + { + uint8_t public_key[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE( PSA_VENDOR_ECC_MAX_CURVE_BITS )]; + size_t public_key_length; + PSA_ASSERT( psa_export_public_key( drv_handle, + public_key, sizeof( public_key ), + &public_key_length ) ); + psa_set_key_type( &sw_attributes, + PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR( type ) ); + PSA_ASSERT( psa_import_key( &sw_attributes, + public_key, public_key_length, + &sw_handle ) ); + break; + } + } + /* Sign with the chosen key. */ - if( sign_in_driver ) - PSA_ASSERT_VIA_DRIVER( - psa_asymmetric_sign( drv_handle, - alg, - input->x, input->len, - signature, sizeof( signature ), - &signature_length ), - PSA_SUCCESS ); - else - PSA_ASSERT( psa_asymmetric_sign( sw_handle, - alg, - input->x, input->len, - signature, sizeof( signature ), - &signature_length ) ); + switch( flow ) + { + case SIGN_IN_DRIVER_AND_PARALLEL_CREATION: + case SIGN_IN_DRIVER_THEN_EXPORT_PUBLIC: + PSA_ASSERT_VIA_DRIVER( + psa_asymmetric_sign( drv_handle, + alg, + input->x, input->len, + signature, sizeof( signature ), + &signature_length ), + PSA_SUCCESS ); + break; + case SIGN_IN_SOFTWARE_AND_PARALLEL_CREATION: + PSA_ASSERT( psa_asymmetric_sign( sw_handle, + alg, + input->x, input->len, + signature, sizeof( signature ), + &signature_length ) ); + break; + } /* Verify with both keys. */ PSA_ASSERT( psa_asymmetric_verify( sw_handle, alg,