/* BEGIN_HEADER */ #include #if defined(MBEDTLS_PSA_CRYPTO_SPM) #include "spm/psa_defs.h" #endif #include "psa/crypto.h" #include "psa_crypto_storage.h" #define PSA_ASSERT( expr ) TEST_ASSERT( ( expr ) == PSA_SUCCESS ) typedef enum { CLOSE_BY_CLOSE, CLOSE_BY_DESTROY, CLOSE_BY_SHUTDOWN, } close_method_t; typedef enum { KEEP_OPEN, CLOSE_BEFORE, CLOSE_AFTER, } reopen_policy_t; /* All test functions that create persistent keys must call * `TEST_MAX_KEY_ID( key_id )` before creating a persistent key with this * identifier, and must call psa_purge_key_storage() in their cleanup * code. */ #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) /* There is no API to purge all keys. For this test suite, require that * all key IDs be less than a certain maximum, or a well-known value * which corresponds to a file that does not contain a key. */ #define MAX_KEY_ID_FOR_TEST 32 #define KEY_ID_IS_WELL_KNOWN( key_id ) \ ( ( key_id ) == PSA_CRYPTO_ITS_RANDOM_SEED_UID ) #define TEST_MAX_KEY_ID( key_id ) \ TEST_ASSERT( ( key_id ) <= MAX_KEY_ID_FOR_TEST || \ KEY_ID_IS_WELL_KNOWN( key_id ) ) void psa_purge_key_storage( void ) { psa_key_id_t i; /* The tests may have potentially created key ids from 1 to * MAX_KEY_ID_FOR_TEST. In addition, run the destroy function on key id * 0, which file-based storage uses as a temporary file. */ for( i = 0; i <= MAX_KEY_ID_FOR_TEST; i++ ) psa_destroy_persistent_key( i ); } #else #define TEST_MAX_KEY_ID( key_id ) ( (void) ( key_id ) ) #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */ static int psa_key_policy_equal( psa_key_policy_t *p1, psa_key_policy_t *p2 ) { return( psa_key_policy_get_usage( p1 ) == psa_key_policy_get_usage( p2 ) && psa_key_policy_get_algorithm( p1 ) == psa_key_policy_get_algorithm( p2 ) ); } /* END_HEADER */ /* BEGIN_DEPENDENCIES * depends_on:MBEDTLS_PSA_CRYPTO_C * END_DEPENDENCIES */ /* BEGIN_CASE */ void transient_slot_lifecycle( int type_arg, int max_bits_arg, int alg_arg, int usage_arg, data_t *key_data, int close_method_arg ) { psa_key_type_t type = type_arg; size_t max_bits = max_bits_arg; psa_algorithm_t alg = alg_arg; psa_key_usage_t usage_flags = usage_arg; close_method_t close_method = close_method_arg; psa_key_type_t read_type; psa_key_handle_t handle = 0; psa_key_policy_t policy; PSA_ASSERT( psa_crypto_init( ) ); /* Get a handle and import a key. */ PSA_ASSERT( psa_allocate_key( type, max_bits, &handle ) ); TEST_ASSERT( handle != 0 ); psa_key_policy_init( &policy ); psa_key_policy_set_usage( &policy, usage_flags, alg ); PSA_ASSERT( psa_set_key_policy( handle, &policy ) ); PSA_ASSERT( psa_import_key( handle, type, key_data->x, key_data->len ) ); PSA_ASSERT( psa_get_key_information( handle, &read_type, NULL ) ); TEST_ASSERT( read_type == type ); /* Do something that invalidates the handle. */ switch( close_method ) { case CLOSE_BY_CLOSE: PSA_ASSERT( psa_close_key( handle ) ); break; case CLOSE_BY_DESTROY: PSA_ASSERT( psa_destroy_key( handle ) ); break; case CLOSE_BY_SHUTDOWN: mbedtls_psa_crypto_free( ); PSA_ASSERT( psa_crypto_init( ) ); break; } /* Test that the handle is now invalid. */ TEST_ASSERT( psa_get_key_information( handle, &read_type, NULL ) == PSA_ERROR_INVALID_HANDLE ); TEST_ASSERT( psa_close_key( handle ) == PSA_ERROR_INVALID_HANDLE ); exit: mbedtls_psa_crypto_free( ); } /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C */ void persistent_slot_lifecycle( int lifetime_arg, int id_arg, int type_arg, int max_bits_arg, int alg_arg, int usage_arg, data_t *key_data, int close_method_arg ) { psa_key_lifetime_t lifetime = lifetime_arg; psa_key_id_t id = id_arg; psa_key_type_t type = type_arg; size_t max_bits = max_bits_arg; psa_algorithm_t alg = alg_arg; psa_key_usage_t usage_flags = usage_arg; close_method_t close_method = close_method_arg; psa_key_type_t read_type; psa_key_handle_t handle = 0; psa_key_policy_t policy; TEST_MAX_KEY_ID( id ); PSA_ASSERT( psa_crypto_init( ) ); /* Get a handle and import a key. */ PSA_ASSERT( psa_create_key( lifetime, id, type, max_bits, &handle ) ); TEST_ASSERT( handle != 0 ); psa_key_policy_init( &policy ); psa_key_policy_set_usage( &policy, usage_flags, alg ); PSA_ASSERT( psa_set_key_policy( handle, &policy ) ); PSA_ASSERT( psa_import_key( handle, type, key_data->x, key_data->len ) ); PSA_ASSERT( psa_get_key_information( handle, &read_type, NULL ) ); TEST_ASSERT( read_type == type ); /* Close the key and reopen it. */ PSA_ASSERT( psa_close_key( handle ) ); PSA_ASSERT( psa_open_key( lifetime, id, &handle ) ); PSA_ASSERT( psa_get_key_information( handle, &read_type, NULL ) ); TEST_ASSERT( read_type == type ); /* Do something that invalidates the handle. */ switch( close_method ) { case CLOSE_BY_CLOSE: PSA_ASSERT( psa_close_key( handle ) ); break; case CLOSE_BY_DESTROY: PSA_ASSERT( psa_destroy_key( handle ) ); break; case CLOSE_BY_SHUTDOWN: mbedtls_psa_crypto_free( ); PSA_ASSERT( psa_crypto_init( ) ); break; } /* Test that the handle is now invalid. */ TEST_ASSERT( psa_get_key_information( handle, &read_type, NULL ) == PSA_ERROR_INVALID_HANDLE ); TEST_ASSERT( psa_close_key( handle ) == PSA_ERROR_INVALID_HANDLE ); /* Try to reopen the key. If we destroyed it, check that it doesn't * exist, otherwise check that it still exists. */ switch( close_method ) { case CLOSE_BY_CLOSE: case CLOSE_BY_SHUTDOWN: PSA_ASSERT( psa_open_key( lifetime, id, &handle ) ); PSA_ASSERT( psa_get_key_information( handle, &read_type, NULL ) ); TEST_ASSERT( read_type == type ); break; case CLOSE_BY_DESTROY: TEST_ASSERT( psa_open_key( lifetime, id, &handle ) == PSA_ERROR_EMPTY_SLOT ); break; } exit: mbedtls_psa_crypto_free( ); psa_purge_key_storage( ); } /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C */ void create_existent( int lifetime_arg, int id_arg, int new_type_arg, int reopen_policy_arg ) { psa_key_lifetime_t lifetime = lifetime_arg; psa_key_id_t id = id_arg; psa_key_handle_t handle1 = 0, handle2 = 0; psa_key_policy_t policy1, read_policy; psa_key_type_t type1 = PSA_KEY_TYPE_RAW_DATA; psa_key_type_t type2 = new_type_arg; psa_key_type_t read_type; const uint8_t material1[16] = "test material #1"; size_t bits1 = PSA_BYTES_TO_BITS( sizeof( material1 ) ); size_t read_bits; uint8_t reexported[sizeof( material1 )]; size_t reexported_length; reopen_policy_t reopen_policy = reopen_policy_arg; TEST_MAX_KEY_ID( id ); PSA_ASSERT( psa_crypto_init( ) ); /* Create a key. */ PSA_ASSERT( psa_create_key( lifetime, id, type1, bits1, &handle1 ) ); TEST_ASSERT( handle1 != 0 ); psa_key_policy_init( &policy1 ); psa_key_policy_set_usage( &policy1, PSA_KEY_USAGE_EXPORT, 0 ); PSA_ASSERT( psa_set_key_policy( handle1, &policy1 ) ); PSA_ASSERT( psa_import_key( handle1, type1, material1, sizeof( material1 ) ) ); if( reopen_policy == CLOSE_BEFORE ) PSA_ASSERT( psa_close_key( handle1 ) ); /* Attempt to create a new key in the same slot. */ TEST_ASSERT( psa_create_key( lifetime, id, type2, bits1, &handle2 ) == PSA_ERROR_OCCUPIED_SLOT ); TEST_ASSERT( handle2 == 0 ); if( reopen_policy == CLOSE_AFTER ) PSA_ASSERT( psa_close_key( handle1 ) ); if( reopen_policy == CLOSE_BEFORE || reopen_policy == CLOSE_AFTER ) PSA_ASSERT( psa_open_key( lifetime, id, &handle1 ) ); /* Check that the original key hasn't changed. */ PSA_ASSERT( psa_get_key_policy( handle1, &read_policy ) ); TEST_ASSERT( psa_key_policy_equal( &read_policy, &policy1 ) ); PSA_ASSERT( psa_get_key_information( handle1, &read_type, &read_bits ) ); TEST_ASSERT( read_type == type1 ); TEST_ASSERT( read_bits == bits1 ); PSA_ASSERT( psa_export_key( handle1, reexported, sizeof( reexported ), &reexported_length ) ); ASSERT_COMPARE( material1, sizeof( material1 ), reexported, reexported_length ); exit: mbedtls_psa_crypto_free( ); psa_purge_key_storage( ); } /* END_CASE */ /* BEGIN_CASE */ void open_fail( int lifetime_arg, int id_arg, int expected_status_arg ) { psa_key_lifetime_t lifetime = lifetime_arg; psa_key_id_t id = id_arg; psa_status_t expected_status = expected_status_arg; psa_key_handle_t handle = 0xdead; PSA_ASSERT( psa_crypto_init( ) ); TEST_ASSERT( psa_open_key( lifetime, id, &handle ) == expected_status ); TEST_ASSERT( handle == 0 ); exit: mbedtls_psa_crypto_free( ); } /* END_CASE */ /* BEGIN_CASE */ void create_fail( int lifetime_arg, int id_arg, int type_arg, int max_bits_arg, int expected_status_arg ) { psa_key_lifetime_t lifetime = lifetime_arg; psa_key_id_t id = id_arg; psa_key_type_t type = type_arg; size_t max_bits = max_bits_arg; psa_status_t expected_status = expected_status_arg; psa_key_handle_t handle = 0xdead; TEST_MAX_KEY_ID( id ); PSA_ASSERT( psa_crypto_init( ) ); TEST_ASSERT( psa_create_key( lifetime, id, type, max_bits, &handle ) == expected_status ); TEST_ASSERT( handle == 0 ); exit: mbedtls_psa_crypto_free( ); #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) psa_purge_key_storage( ); #endif } /* END_CASE */ /* BEGIN_CASE */ void invalid_handle( ) { psa_key_handle_t handle1 = 0; psa_key_policy_t policy; psa_key_type_t read_type; size_t read_bits; uint8_t material[1] = "a"; PSA_ASSERT( psa_crypto_init( ) ); /* Allocate a handle and store a key in it. */ PSA_ASSERT( psa_allocate_key( PSA_KEY_TYPE_RAW_DATA, 1, &handle1 ) ); TEST_ASSERT( handle1 != 0 ); psa_key_policy_init( &policy ); psa_key_policy_set_usage( &policy, 0, 0 ); PSA_ASSERT( psa_set_key_policy( handle1, &policy ) ); PSA_ASSERT( psa_import_key( handle1, PSA_KEY_TYPE_RAW_DATA, material, sizeof( material ) ) ); /* Attempt to close and destroy some invalid handles. */ TEST_ASSERT( psa_close_key( 0 ) == PSA_ERROR_INVALID_HANDLE ); TEST_ASSERT( psa_close_key( handle1 - 1 ) == PSA_ERROR_INVALID_HANDLE ); TEST_ASSERT( psa_close_key( handle1 + 1 ) == PSA_ERROR_INVALID_HANDLE ); TEST_ASSERT( psa_destroy_key( 0 ) == PSA_ERROR_INVALID_HANDLE ); TEST_ASSERT( psa_destroy_key( handle1 - 1 ) == PSA_ERROR_INVALID_HANDLE ); TEST_ASSERT( psa_destroy_key( handle1 + 1 ) == PSA_ERROR_INVALID_HANDLE ); /* After all this, check that the original handle is intact. */ PSA_ASSERT( psa_get_key_information( handle1, &read_type, &read_bits ) ); TEST_ASSERT( read_type == PSA_KEY_TYPE_RAW_DATA ); TEST_ASSERT( read_bits == PSA_BYTES_TO_BITS( sizeof( material ) ) ); PSA_ASSERT( psa_close_key( handle1 ) ); exit: mbedtls_psa_crypto_free( ); } /* END_CASE */ /* BEGIN_CASE */ void many_transient_handles( int max_handles_arg ) { psa_key_handle_t *handles = NULL; size_t max_handles = max_handles_arg; size_t i, j; psa_status_t status; psa_key_policy_t policy; uint8_t exported[sizeof( size_t )]; size_t exported_length; size_t max_bits = PSA_BITS_TO_BYTES( sizeof( exported ) ); ASSERT_ALLOC( handles, max_handles ); PSA_ASSERT( psa_crypto_init( ) ); psa_key_policy_init( &policy ); psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_EXPORT, 0 ); for( i = 0; i < max_handles; i++ ) { status = psa_allocate_key( PSA_KEY_TYPE_RAW_DATA, max_bits, &handles[i] ); if( status == PSA_ERROR_INSUFFICIENT_MEMORY ) break; TEST_ASSERT( status == PSA_SUCCESS ); TEST_ASSERT( handles[i] != 0 ); for( j = 0; j < i; j++ ) TEST_ASSERT( handles[i] != handles[j] ); PSA_ASSERT( psa_set_key_policy( handles[i], &policy ) ); PSA_ASSERT( psa_import_key( handles[i], PSA_KEY_TYPE_RAW_DATA, (uint8_t *) &i, sizeof( i ) ) ); } max_handles = i; for( i = 1; i < max_handles; i++ ) { PSA_ASSERT( psa_close_key( handles[i - 1] ) ); PSA_ASSERT( psa_export_key( handles[i], exported, sizeof( exported ), &exported_length ) ); ASSERT_COMPARE( exported, exported_length, (uint8_t *) &i, sizeof( i ) ); } PSA_ASSERT( psa_close_key( handles[i - 1] ) ); exit: mbedtls_psa_crypto_free( ); mbedtls_free( handles ); } /* END_CASE */