From eecadde6adb6b1d1c5662a449081823ab85a1047 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 7 Aug 2019 21:05:24 +0200 Subject: [PATCH] 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( );