| /* BEGIN_HEADER */ |
| #include "psa/crypto_se_driver.h" |
| |
| #include "psa_crypto_se.h" |
| #include "psa_crypto_slot_management.h" |
| #include "psa_crypto_storage.h" |
| |
| /* Invasive peeking: check the persistent data */ |
| #if defined(MBEDTLS_PSA_ITS_FILE_C) |
| #include "psa_crypto_its.h" |
| #else /* Native ITS implementation */ |
| #include "psa/error.h" |
| #include "psa/internal_trusted_storage.h" |
| #endif |
| |
| |
| /****************************************************************/ |
| /* Test driver helpers */ |
| /****************************************************************/ |
| |
| /** The minimum valid location value for a secure element driver. */ |
| #define MIN_DRIVER_LOCATION 1 |
| |
| /** The location and lifetime used for tests that use a single driver. */ |
| #define TEST_DRIVER_LOCATION 1 |
| #define TEST_SE_PERSISTENT_LIFETIME \ |
| (PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( \ |
| PSA_KEY_PERSISTENCE_DEFAULT, TEST_DRIVER_LOCATION)) |
| |
| #define TEST_SE_VOLATILE_LIFETIME \ |
| (PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( \ |
| PSA_KEY_PERSISTENCE_VOLATILE, TEST_DRIVER_LOCATION)) |
| |
| /** The driver detected a condition that shouldn't happen. |
| * 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, 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)) \ |
| { \ |
| mbedtls_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. |
| */ |
| #define DRIVER_ASSERT(TEST) \ |
| do { \ |
| if (!(TEST)) \ |
| { \ |
| mbedtls_test_fail( #TEST, __LINE__, __FILE__); \ |
| 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 mbedtls_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 mbedtls_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)) \ |
| { \ |
| mbedtls_test_fail( #expr, __LINE__, __FILE__); \ |
| goto exit; \ |
| } \ |
| } while (0) |
| |
| |
| |
| /****************************************************************/ |
| /* Domain support functions */ |
| /****************************************************************/ |
| |
| /* Return the exact bit size given a curve family and a byte length. */ |
| static size_t ecc_curve_bits(psa_ecc_family_t curve, size_t data_length) |
| { |
| switch (curve) { |
| case PSA_ECC_FAMILY_SECP_R1: |
| if (data_length == PSA_BYTES_TO_BITS(521)) { |
| return 521; |
| } |
| break; |
| case PSA_ECC_FAMILY_MONTGOMERY: |
| if (data_length == PSA_BYTES_TO_BITS(255)) { |
| return 255; |
| } |
| } |
| /* If not listed above, assume a multiple of 8 bits. */ |
| return PSA_BYTES_TO_BITS(data_length); |
| } |
| |
| |
| /****************************************************************/ |
| /* Miscellaneous driver methods */ |
| /****************************************************************/ |
| |
| typedef struct { |
| psa_key_slot_number_t slot_number; |
| psa_key_creation_method_t method; |
| psa_status_t status; |
| } validate_slot_number_directions_t; |
| static validate_slot_number_directions_t validate_slot_number_directions; |
| |
| /* Validate a choice of slot number as directed. */ |
| static psa_status_t validate_slot_number_as_directed( |
| psa_drv_se_context_t *context, |
| void *persistent_data, |
| const psa_key_attributes_t *attributes, |
| psa_key_creation_method_t method, |
| psa_key_slot_number_t slot_number) |
| { |
| (void) context; |
| (void) persistent_data; |
| (void) attributes; |
| 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; |
| } |
| |
| /* Allocate slot numbers with a monotonic counter. */ |
| static psa_key_slot_number_t shadow_counter; |
| static void counter_reset(void) |
| { |
| shadow_counter = 0; |
| } |
| static psa_status_t counter_allocate(psa_drv_se_context_t *context, |
| void *persistent_data, |
| const psa_key_attributes_t *attributes, |
| psa_key_creation_method_t method, |
| psa_key_slot_number_t *slot_number) |
| { |
| psa_key_slot_number_t *p_counter = persistent_data; |
| (void) attributes; |
| (void) method; |
| if (context->persistent_data_size != sizeof(psa_key_slot_number_t)) { |
| return PSA_ERROR_DETECTED_BY_DRIVER; |
| } |
| ++*p_counter; |
| if (*p_counter == 0) { |
| return PSA_ERROR_INSUFFICIENT_STORAGE; |
| } |
| shadow_counter = *p_counter; |
| *slot_number = *p_counter; |
| return PSA_SUCCESS; |
| } |
| |
| /* Null import: do nothing, but pretend it worked. */ |
| #if defined(AT_LEAST_ONE_BUILTIN_KDF) |
| static psa_status_t null_import(psa_drv_se_context_t *context, |
| psa_key_slot_number_t slot_number, |
| const psa_key_attributes_t *attributes, |
| const uint8_t *data, |
| size_t data_length, |
| size_t *bits) |
| { |
| (void) context; |
| (void) slot_number; |
| (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); |
| return PSA_SUCCESS; |
| } |
| #endif /* AT_LEAST_ONE_BUILTIN_KDF */ |
| |
| /* Null generate: do nothing, but pretend it worked. */ |
| #if defined(AT_LEAST_ONE_BUILTIN_KDF) |
| 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_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); |
| } |
| |
| return PSA_SUCCESS; |
| } |
| #endif /* AT_LEAST_ONE_BUILTIN_KDF */ |
| |
| /* Null destroy: do nothing, but pretend it worked. */ |
| static psa_status_t null_destroy(psa_drv_se_context_t *context, |
| void *persistent_data, |
| psa_key_slot_number_t slot_number) |
| { |
| (void) context; |
| (void) persistent_data; |
| (void) slot_number; |
| return PSA_SUCCESS; |
| } |
| |
| |
| |
| /****************************************************************/ |
| /* RAM-based test driver */ |
| /****************************************************************/ |
| |
| #define RAM_MAX_KEY_SIZE 64 |
| typedef struct { |
| psa_key_lifetime_t lifetime; |
| psa_key_type_t type; |
| size_t bits; |
| uint8_t content[RAM_MAX_KEY_SIZE]; |
| } ram_slot_t; |
| static ram_slot_t ram_slots[16]; |
| |
| /* A type with at least ARRAY_LENGTH(ram_slots) bits, containing a |
| * bit vector indicating which slots are in use. */ |
| typedef uint16_t ram_slot_usage_t; |
| |
| static ram_slot_usage_t ram_shadow_slot_usage; |
| |
| static uint8_t ram_min_slot = 0; |
| |
| static void ram_slots_reset(void) |
| { |
| memset(ram_slots, 0, sizeof(ram_slots)); |
| ram_min_slot = 0; |
| ram_shadow_slot_usage = 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. */ |
| 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) |
| { |
| psa_status_t status; |
| size_t required_storage = |
| PSA_EXPORT_KEY_OUTPUT_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))) { |
| DRIVER_ASSERT_RETURN(pubkey == NULL); |
| DRIVER_ASSERT_RETURN(pubkey_size == 0); |
| } |
| |
| status = ram_create_common(context, slot_number, attributes, |
| required_storage); |
| return status; |
| } |
| |
| 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, |
| const uint8_t *data, |
| size_t data_length, |
| size_t *bits) |
| { |
| 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 = ecc_curve_bits(PSA_KEY_TYPE_ECC_GET_FAMILY(type), data_length); |
| if (*bits == 0) { |
| return PSA_ERROR_DETECTED_BY_DRIVER; |
| } |
| } 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 *data, |
| size_t data_size, |
| size_t *data_length) |
| { |
| size_t actual_size; |
| (void) context; |
| 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; |
| } |
| *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; |
| mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT; |
| 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), |
| &key); |
| if (status != PSA_SUCCESS) { |
| return status; |
| } |
| status = psa_export_public_key(key, data, data_size, data_length); |
| psa_destroy_key(key); |
| return PSA_SUCCESS; |
| } |
| |
| static psa_status_t ram_destroy(psa_drv_se_context_t *context, |
| void *persistent_data, |
| psa_key_slot_number_t slot_number) |
| { |
| ram_slot_usage_t *slot_usage = persistent_data; |
| 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); |
| ram_shadow_slot_usage = *slot_usage; |
| return PSA_SUCCESS; |
| } |
| |
| static psa_status_t ram_allocate(psa_drv_se_context_t *context, |
| void *persistent_data, |
| const psa_key_attributes_t *attributes, |
| psa_key_creation_method_t method, |
| psa_key_slot_number_t *slot_number) |
| { |
| ram_slot_usage_t *slot_usage = persistent_data; |
| (void) attributes; |
| (void) method; |
| 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)) { |
| if (!(*slot_usage & 1 << *slot_number)) { |
| ram_shadow_slot_usage = *slot_usage; |
| return PSA_SUCCESS; |
| } |
| } |
| return PSA_ERROR_INSUFFICIENT_STORAGE; |
| } |
| |
| static psa_status_t ram_validate_slot_number( |
| psa_drv_se_context_t *context, |
| void *persistent_data, |
| const psa_key_attributes_t *attributes, |
| psa_key_creation_method_t method, |
| psa_key_slot_number_t slot_number) |
| { |
| (void) context; |
| (void) persistent_data; |
| (void) attributes; |
| (void) method; |
| if (slot_number >= ARRAY_LENGTH(ram_slots)) { |
| return PSA_ERROR_INVALID_ARGUMENT; |
| } |
| 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; |
| mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT; |
| 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_HASH); |
| 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), |
| &key) == PSA_SUCCESS); |
| status = psa_sign_hash(key, alg, |
| hash, hash_length, |
| signature, signature_size, signature_length); |
| |
| exit: |
| psa_destroy_key(key); |
| 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; |
| mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT; |
| 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_HASH); |
| 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), |
| &key) == |
| PSA_SUCCESS); |
| status = psa_verify_hash(key, alg, |
| hash, hash_length, |
| signature, signature_length); |
| |
| exit: |
| psa_destroy_key(key); |
| return status; |
| } |
| |
| |
| /****************************************************************/ |
| /* 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( |
| mbedtls_svc_key_id_t key, |
| const psa_key_attributes_t *reference_attributes) |
| { |
| int ok = 0; |
| psa_key_attributes_t actual_attributes = PSA_KEY_ATTRIBUTES_INIT; |
| |
| PSA_ASSERT(psa_get_key_attributes(key, &actual_attributes)); |
| |
| TEST_ASSERT(mbedtls_svc_key_id_equal( |
| psa_get_key_id(&actual_attributes), |
| psa_get_key_id(reference_attributes))); |
| TEST_EQUAL(psa_get_key_lifetime(&actual_attributes), |
| psa_get_key_lifetime(reference_attributes)); |
| TEST_EQUAL(psa_get_key_type(&actual_attributes), |
| psa_get_key_type(reference_attributes)); |
| TEST_EQUAL(psa_get_key_usage_flags(&actual_attributes), |
| psa_get_key_usage_flags(reference_attributes)); |
| TEST_EQUAL(psa_get_key_algorithm(&actual_attributes), |
| psa_get_key_algorithm(reference_attributes)); |
| TEST_EQUAL(psa_get_key_enrollment_algorithm(&actual_attributes), |
| psa_get_key_enrollment_algorithm(reference_attributes)); |
| if (psa_get_key_bits(reference_attributes) != 0) { |
| TEST_EQUAL(psa_get_key_bits(&actual_attributes), |
| psa_get_key_bits(reference_attributes)); |
| } |
| |
| { |
| psa_key_slot_number_t actual_slot_number = 0xdeadbeef; |
| psa_key_slot_number_t desired_slot_number = 0xb90cc011; |
| psa_key_lifetime_t lifetime = |
| psa_get_key_lifetime(&actual_attributes); |
| psa_status_t status = psa_get_key_slot_number(&actual_attributes, |
| &actual_slot_number); |
| if (PSA_KEY_LIFETIME_GET_LOCATION(lifetime) < MIN_DRIVER_LOCATION) { |
| /* The key is not in a secure element. */ |
| TEST_EQUAL(status, PSA_ERROR_INVALID_ARGUMENT); |
| } else { |
| /* The key is in a secure element. If it had been created |
| * in a specific slot, check that it is reported there. */ |
| PSA_ASSERT(status); |
| status = psa_get_key_slot_number(reference_attributes, |
| &desired_slot_number); |
| if (status == PSA_SUCCESS) { |
| TEST_EQUAL(desired_slot_number, actual_slot_number); |
| } |
| } |
| } |
| ok = 1; |
| |
| exit: |
| /* |
| * Actual key attributes may have been returned by psa_get_key_attributes() |
| * thus reset them as required. |
| */ |
| psa_reset_key_attributes(&actual_attributes); |
| |
| return ok; |
| } |
| |
| /* Get the file UID corresponding to the specified location. |
| * If this changes, the storage format version must change. |
| * See psa_get_se_driver_its_file_uid() in psa_crypto_se.c. |
| */ |
| psa_storage_uid_t file_uid_for_location(psa_key_location_t location) |
| { |
| if (location > PSA_MAX_SE_LOCATION) { |
| return 0; |
| } |
| return 0xfffffe00 + location; |
| } |
| |
| /* Check that the persistent data of a driver has its expected content. */ |
| static int check_persistent_data(psa_key_location_t location, |
| const void *expected_data, |
| size_t size) |
| { |
| psa_storage_uid_t uid = file_uid_for_location(location); |
| struct psa_storage_info_t info; |
| uint8_t *loaded = NULL; |
| int ok = 0; |
| |
| PSA_ASSERT(psa_its_get_info(uid, &info)); |
| TEST_CALLOC(loaded, info.size); |
| PSA_ASSERT(psa_its_get(uid, 0, info.size, loaded, NULL)); |
| TEST_MEMORY_COMPARE(expected_data, size, loaded, info.size); |
| ok = 1; |
| |
| exit: |
| mbedtls_free(loaded); |
| return ok; |
| } |
| |
| /* Check that no persistent data exists for the given location. */ |
| static int check_no_persistent_data(psa_key_location_t location) |
| { |
| psa_storage_uid_t uid = file_uid_for_location(location); |
| struct psa_storage_info_t info; |
| int ok = 0; |
| |
| TEST_EQUAL(psa_its_get_info(uid, &info), PSA_ERROR_DOES_NOT_EXIST); |
| ok = 1; |
| |
| exit: |
| return ok; |
| } |
| |
| /* Check that a function's return status is "smoke-free", i.e. that |
| * it's an acceptable error code when calling an API function that operates |
| * on a key with potentially bogus parameters. */ |
| #if defined(AT_LEAST_ONE_BUILTIN_KDF) |
| static int is_status_smoke_free(psa_status_t status) |
| { |
| switch (status) { |
| case PSA_SUCCESS: |
| case PSA_ERROR_NOT_SUPPORTED: |
| case PSA_ERROR_NOT_PERMITTED: |
| case PSA_ERROR_BUFFER_TOO_SMALL: |
| case PSA_ERROR_INVALID_ARGUMENT: |
| case PSA_ERROR_INVALID_SIGNATURE: |
| case PSA_ERROR_INVALID_PADDING: |
| return 1; |
| default: |
| return 0; |
| } |
| } |
| #endif /* AT_LEAST_ONE_BUILTIN_KDF */ |
| |
| #define SMOKE_ASSERT(expr) \ |
| TEST_ASSERT(is_status_smoke_free(expr)) |
| |
| /* Smoke test a key. There are mostly no wrong answers here since we pass |
| * mostly bogus parameters: the goal is to ensure that there is no memory |
| * corruption or crash. This test function is most useful when run under |
| * an environment with sanity checks such as ASan or MSan. */ |
| #if defined(AT_LEAST_ONE_BUILTIN_KDF) |
| static int smoke_test_key(mbedtls_svc_key_id_t key) |
| { |
| int ok = 0; |
| psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| psa_mac_operation_t mac_operation = PSA_MAC_OPERATION_INIT; |
| psa_cipher_operation_t cipher_operation = PSA_CIPHER_OPERATION_INIT; |
| psa_key_derivation_operation_t derivation_operation = |
| PSA_KEY_DERIVATION_OPERATION_INIT; |
| uint8_t buffer[80]; /* large enough for a public key for ECDH */ |
| size_t length; |
| mbedtls_svc_key_id_t key2 = MBEDTLS_SVC_KEY_ID_INIT; |
| |
| SMOKE_ASSERT(psa_get_key_attributes(key, &attributes)); |
| |
| SMOKE_ASSERT(psa_export_key(key, |
| buffer, sizeof(buffer), &length)); |
| SMOKE_ASSERT(psa_export_public_key(key, |
| buffer, sizeof(buffer), &length)); |
| |
| SMOKE_ASSERT(psa_copy_key(key, &attributes, &key2)); |
| if (!mbedtls_svc_key_id_is_null(key2)) { |
| PSA_ASSERT(psa_destroy_key(key2)); |
| } |
| |
| SMOKE_ASSERT(psa_mac_sign_setup(&mac_operation, key, PSA_ALG_CMAC)); |
| PSA_ASSERT(psa_mac_abort(&mac_operation)); |
| SMOKE_ASSERT(psa_mac_verify_setup(&mac_operation, key, |
| PSA_ALG_HMAC(PSA_ALG_SHA_256))); |
| PSA_ASSERT(psa_mac_abort(&mac_operation)); |
| |
| SMOKE_ASSERT(psa_cipher_encrypt_setup(&cipher_operation, key, |
| PSA_ALG_CTR)); |
| PSA_ASSERT(psa_cipher_abort(&cipher_operation)); |
| SMOKE_ASSERT(psa_cipher_decrypt_setup(&cipher_operation, key, |
| PSA_ALG_CTR)); |
| PSA_ASSERT(psa_cipher_abort(&cipher_operation)); |
| |
| SMOKE_ASSERT(psa_aead_encrypt(key, PSA_ALG_CCM, |
| buffer, sizeof(buffer), |
| NULL, 0, |
| buffer, sizeof(buffer), |
| buffer, sizeof(buffer), &length)); |
| SMOKE_ASSERT(psa_aead_decrypt(key, PSA_ALG_CCM, |
| buffer, sizeof(buffer), |
| NULL, 0, |
| buffer, sizeof(buffer), |
| buffer, sizeof(buffer), &length)); |
| |
| SMOKE_ASSERT(psa_sign_hash(key, PSA_ALG_ECDSA_ANY, |
| buffer, 32, |
| buffer, sizeof(buffer), &length)); |
| SMOKE_ASSERT(psa_verify_hash(key, PSA_ALG_ECDSA_ANY, |
| buffer, 32, |
| buffer, sizeof(buffer))); |
| |
| SMOKE_ASSERT(psa_asymmetric_encrypt(key, PSA_ALG_RSA_PKCS1V15_CRYPT, |
| buffer, 10, NULL, 0, |
| buffer, sizeof(buffer), &length)); |
| SMOKE_ASSERT(psa_asymmetric_decrypt(key, PSA_ALG_RSA_PKCS1V15_CRYPT, |
| buffer, sizeof(buffer), NULL, 0, |
| buffer, sizeof(buffer), &length)); |
| |
| #if defined(PSA_WANT_ALG_SHA_256) |
| /* Try the key in a plain key derivation. */ |
| PSA_ASSERT(psa_key_derivation_setup(&derivation_operation, |
| PSA_ALG_HKDF(PSA_ALG_SHA_256))); |
| PSA_ASSERT(psa_key_derivation_input_bytes(&derivation_operation, |
| PSA_KEY_DERIVATION_INPUT_SALT, |
| NULL, 0)); |
| SMOKE_ASSERT(psa_key_derivation_input_key(&derivation_operation, |
| PSA_KEY_DERIVATION_INPUT_SECRET, |
| key)); |
| PSA_ASSERT(psa_key_derivation_abort(&derivation_operation)); |
| |
| /* If the key is asymmetric, try it in a key agreement, both as |
| * part of a derivation operation and standalone. */ |
| if (psa_export_public_key(key, buffer, sizeof(buffer), &length) == |
| PSA_SUCCESS) { |
| psa_algorithm_t alg = |
| PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, |
| PSA_ALG_HKDF(PSA_ALG_SHA_256)); |
| PSA_ASSERT(psa_key_derivation_setup(&derivation_operation, alg)); |
| PSA_ASSERT(psa_key_derivation_input_bytes( |
| &derivation_operation, PSA_KEY_DERIVATION_INPUT_SALT, |
| NULL, 0)); |
| SMOKE_ASSERT(psa_key_derivation_key_agreement( |
| &derivation_operation, |
| PSA_KEY_DERIVATION_INPUT_SECRET, |
| key, buffer, length)); |
| PSA_ASSERT(psa_key_derivation_abort(&derivation_operation)); |
| |
| SMOKE_ASSERT(psa_raw_key_agreement( |
| alg, key, buffer, length, |
| buffer, sizeof(buffer), &length)); |
| } |
| #endif /* PSA_WANT_ALG_SHA_256 */ |
| |
| ok = 1; |
| |
| exit: |
| /* |
| * Key attributes may have been returned by psa_get_key_attributes() |
| * thus reset them as required. |
| */ |
| psa_reset_key_attributes(&attributes); |
| |
| return ok; |
| } |
| #endif /* AT_LEAST_ONE_BUILTIN_KDF */ |
| |
| static void psa_purge_storage(void) |
| { |
| /* The generic code in mbedtls_test_psa_purge_key_storage() |
| * (which is called by PSA_DONE()) doesn't take care of things that are |
| * specific to dynamic secure elements. */ |
| psa_key_location_t location; |
| /* Purge the transaction file. */ |
| psa_crypto_stop_transaction(); |
| /* Purge driver persistent data. */ |
| for (location = 0; location < PSA_MAX_SE_LOCATION; location++) { |
| psa_destroy_se_persistent_data(location); |
| } |
| } |
| |
| /* END_HEADER */ |
| |
| /* BEGIN_DEPENDENCIES |
| * depends_on:MBEDTLS_PSA_CRYPTO_SE_C |
| * END_DEPENDENCIES |
| */ |
| |
| /* BEGIN_CASE */ |
| void register_one(int location, int version, int expected_status_arg) |
| { |
| psa_status_t expected_status = expected_status_arg; |
| psa_drv_se_t driver; |
| |
| memset(&driver, 0, sizeof(driver)); |
| driver.hal_version = version; |
| |
| TEST_EQUAL(psa_register_se_driver(location, &driver), |
| expected_status); |
| |
| PSA_ASSERT(psa_crypto_init()); |
| |
| exit: |
| PSA_DONE(); |
| } |
| /* END_CASE */ |
| |
| /* BEGIN_CASE */ |
| void register_twice(int count) |
| { |
| psa_drv_se_t driver; |
| psa_key_location_t location; |
| psa_key_location_t max = MIN_DRIVER_LOCATION + count; |
| |
| memset(&driver, 0, sizeof(driver)); |
| driver.hal_version = PSA_DRV_SE_HAL_VERSION; |
| |
| for (location = MIN_DRIVER_LOCATION; location < max; location++) { |
| PSA_ASSERT(psa_register_se_driver(location, &driver)); |
| } |
| for (location = MIN_DRIVER_LOCATION; location < max; location++) { |
| TEST_EQUAL(psa_register_se_driver(location, &driver), |
| PSA_ERROR_ALREADY_EXISTS); |
| } |
| |
| PSA_ASSERT(psa_crypto_init()); |
| |
| exit: |
| PSA_DONE(); |
| } |
| /* END_CASE */ |
| |
| /* BEGIN_CASE */ |
| void register_max() |
| { |
| psa_drv_se_t driver; |
| psa_key_location_t location; |
| psa_key_location_t max = MIN_DRIVER_LOCATION + PSA_MAX_SE_DRIVERS; |
| |
| memset(&driver, 0, sizeof(driver)); |
| driver.hal_version = PSA_DRV_SE_HAL_VERSION; |
| |
| for (location = MIN_DRIVER_LOCATION; location < max; location++) { |
| PSA_ASSERT(psa_register_se_driver(location, &driver)); |
| } |
| |
| TEST_EQUAL(psa_register_se_driver(location, &driver), |
| PSA_ERROR_INSUFFICIENT_MEMORY); |
| |
| PSA_ASSERT(psa_crypto_init()); |
| |
| exit: |
| PSA_DONE(); |
| } |
| /* END_CASE */ |
| |
| /* BEGIN_CASE */ |
| void key_creation_import_export(int lifetime_arg, int min_slot, int restart) |
| { |
| psa_drv_se_t driver; |
| psa_drv_se_key_management_t key_management; |
| psa_key_lifetime_t lifetime = (psa_key_lifetime_t) lifetime_arg; |
| psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(lifetime); |
| mbedtls_svc_key_id_t id = mbedtls_svc_key_id_make(1, 1); |
| mbedtls_svc_key_id_t returned_id = MBEDTLS_SVC_KEY_ID_INIT; |
| psa_key_handle_t handle; |
| psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| const uint8_t key_material[3] = { 0xfa, 0xca, 0xde }; |
| uint8_t exported[sizeof(key_material)]; |
| size_t exported_length; |
| |
| TEST_USES_KEY_ID(id); |
| |
| 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(ram_slot_usage_t); |
| key_management.p_allocate = ram_allocate; |
| key_management.p_import = ram_import; |
| key_management.p_destroy = ram_destroy; |
| key_management.p_export = ram_export; |
| ram_min_slot = min_slot; |
| |
| PSA_ASSERT(psa_register_se_driver(location, &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_EXPORT); |
| psa_set_key_type(&attributes, PSA_KEY_TYPE_RAW_DATA); |
| PSA_ASSERT(psa_import_key(&attributes, |
| key_material, sizeof(key_material), |
| &returned_id)); |
| |
| if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) { |
| /* For volatile keys, check no persistent data was created */ |
| if (!check_no_persistent_data(location)) { |
| goto exit; |
| } |
| } else { |
| /* For persistent keys, check persistent data */ |
| if (!check_persistent_data(location, |
| &ram_shadow_slot_usage, |
| sizeof(ram_shadow_slot_usage))) { |
| goto exit; |
| } |
| } |
| |
| /* Test that the key was created in the expected slot. */ |
| TEST_EQUAL(ram_slots[min_slot].type, PSA_KEY_TYPE_RAW_DATA); |
| |
| /* Maybe restart, to check that the information is saved correctly. */ |
| if (restart) { |
| mbedtls_psa_crypto_free(); |
| PSA_ASSERT(psa_register_se_driver(location, &driver)); |
| PSA_ASSERT(psa_crypto_init()); |
| |
| if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) { |
| /* Check that the PSA core has no knowledge of the volatile key */ |
| TEST_ASSERT(psa_open_key(returned_id, &handle) == |
| PSA_ERROR_DOES_NOT_EXIST); |
| |
| /* Drop data from our mockup driver */ |
| ram_slots_reset(); |
| ram_min_slot = min_slot; |
| |
| /* Re-import key */ |
| PSA_ASSERT(psa_import_key(&attributes, |
| key_material, sizeof(key_material), |
| &returned_id)); |
| } else { |
| /* Check the persistent key file */ |
| if (!check_persistent_data(location, |
| &ram_shadow_slot_usage, |
| sizeof(ram_shadow_slot_usage))) { |
| goto exit; |
| } |
| } |
| } |
| |
| /* Test that the key was created in the expected slot. */ |
| TEST_EQUAL(ram_slots[min_slot].type, PSA_KEY_TYPE_RAW_DATA); |
| |
| /* Test the key attributes, including the reported slot number. */ |
| psa_set_key_bits(&attributes, |
| PSA_BYTES_TO_BITS(sizeof(key_material))); |
| psa_set_key_slot_number(&attributes, min_slot); |
| |
| if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) { |
| attributes.core.id = returned_id; |
| } else { |
| psa_set_key_id(&attributes, returned_id); |
| } |
| |
| if (!check_key_attributes(returned_id, &attributes)) { |
| goto exit; |
| } |
| |
| /* Test the key data. */ |
| PSA_ASSERT(psa_export_key(returned_id, |
| exported, sizeof(exported), |
| &exported_length)); |
| TEST_MEMORY_COMPARE(key_material, sizeof(key_material), |
| exported, exported_length); |
| |
| PSA_ASSERT(psa_destroy_key(returned_id)); |
| if (!check_persistent_data(location, |
| &ram_shadow_slot_usage, |
| sizeof(ram_shadow_slot_usage))) { |
| goto exit; |
| } |
| TEST_EQUAL(psa_open_key(returned_id, &handle), |
| PSA_ERROR_DOES_NOT_EXIST); |
| |
| /* Test that the key has been erased from the designated slot. */ |
| TEST_EQUAL(ram_slots[min_slot].type, 0); |
| |
| exit: |
| PSA_DONE(); |
| ram_slots_reset(); |
| psa_purge_storage(); |
| } |
| /* END_CASE */ |
| |
| /* BEGIN_CASE */ |
| void key_creation_in_chosen_slot(int slot_arg, |
| int restart, |
| int expected_status_arg) |
| { |
| psa_key_slot_number_t wanted_slot = slot_arg; |
| psa_status_t expected_status = expected_status_arg; |
| psa_status_t status; |
| psa_drv_se_t driver; |
| psa_drv_se_key_management_t key_management; |
| psa_key_lifetime_t lifetime = TEST_SE_PERSISTENT_LIFETIME; |
| psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(lifetime); |
| mbedtls_svc_key_id_t id = mbedtls_svc_key_id_make(1, 1); |
| mbedtls_svc_key_id_t returned_id; |
| psa_key_handle_t handle; |
| psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| const uint8_t key_material[3] = { 0xfa, 0xca, 0xde }; |
| |
| TEST_USES_KEY_ID(id); |
| |
| 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(ram_slot_usage_t); |
| key_management.p_validate_slot_number = ram_validate_slot_number; |
| key_management.p_import = ram_import; |
| key_management.p_destroy = ram_destroy; |
| key_management.p_export = ram_export; |
| |
| PSA_ASSERT(psa_register_se_driver(location, &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_EXPORT); |
| psa_set_key_type(&attributes, PSA_KEY_TYPE_RAW_DATA); |
| psa_set_key_slot_number(&attributes, wanted_slot); |
| status = psa_import_key(&attributes, |
| key_material, sizeof(key_material), |
| &returned_id); |
| TEST_EQUAL(status, expected_status); |
| |
| if (status != PSA_SUCCESS) { |
| goto exit; |
| } |
| if (!check_persistent_data(location, |
| &ram_shadow_slot_usage, |
| sizeof(ram_shadow_slot_usage))) { |
| goto exit; |
| } |
| |
| /* Maybe restart, to check that the information is saved correctly. */ |
| if (restart) { |
| mbedtls_psa_crypto_free(); |
| PSA_ASSERT(psa_register_se_driver(location, &driver)); |
| PSA_ASSERT(psa_crypto_init()); |
| if (!check_persistent_data(location, |
| &ram_shadow_slot_usage, |
| sizeof(ram_shadow_slot_usage))) { |
| goto exit; |
| } |
| } |
| |
| /* Test that the key was created in the expected slot. */ |
| TEST_EQUAL(ram_slots[wanted_slot].type, PSA_KEY_TYPE_RAW_DATA); |
| |
| /* Test that the key is reported with the correct attributes, |
| * including the expected slot. */ |
| PSA_ASSERT(psa_get_key_attributes(id, &attributes)); |
| |
| PSA_ASSERT(psa_destroy_key(id)); |
| if (!check_persistent_data(location, |
| &ram_shadow_slot_usage, |
| sizeof(ram_shadow_slot_usage))) { |
| goto exit; |
| } |
| TEST_EQUAL(psa_open_key(id, &handle), PSA_ERROR_DOES_NOT_EXIST); |
| |
| exit: |
| /* |
| * Key attributes may have been returned by psa_get_key_attributes() |
| * thus reset them as required. |
| */ |
| psa_reset_key_attributes(&attributes); |
| |
| PSA_DONE(); |
| ram_slots_reset(); |
| psa_purge_storage(); |
| } |
| /* END_CASE */ |
| |
| /* BEGIN_CASE depends_on:AT_LEAST_ONE_BUILTIN_KDF */ |
| 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; |
| psa_drv_se_t driver; |
| psa_drv_se_key_management_t key_management; |
| psa_key_lifetime_t lifetime = TEST_SE_PERSISTENT_LIFETIME; |
| psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(lifetime); |
| mbedtls_svc_key_id_t id = mbedtls_svc_key_id_make(1, 1); |
| mbedtls_svc_key_id_t returned_id; |
| psa_key_handle_t handle; |
| psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| |
| TEST_USES_KEY_ID(id); |
| |
| 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_import = null_import; |
| key_management.p_destroy = null_destroy; |
| |
| PSA_ASSERT(psa_register_se_driver(location, &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_HASH | PSA_KEY_USAGE_VERIFY_HASH | |
| 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_ASSERT(psa_import_key(&attributes, |
| key_material->x, key_material->len, |
| &returned_id)); |
| if (!check_persistent_data(location, |
| &shadow_counter, sizeof(shadow_counter))) { |
| goto exit; |
| } |
| |
| /* Do stuff with the key. */ |
| if (!smoke_test_key(id)) { |
| goto exit; |
| } |
| |
| /* Restart and try again. */ |
| mbedtls_psa_crypto_free(); |
| PSA_ASSERT(psa_register_se_driver(location, &driver)); |
| PSA_ASSERT(psa_crypto_init()); |
| if (!check_persistent_data(location, |
| &shadow_counter, sizeof(shadow_counter))) { |
| goto exit; |
| } |
| if (!smoke_test_key(id)) { |
| goto exit; |
| } |
| |
| /* We're done. */ |
| PSA_ASSERT(psa_destroy_key(id)); |
| if (!check_persistent_data(location, |
| &shadow_counter, sizeof(shadow_counter))) { |
| goto exit; |
| } |
| TEST_EQUAL(psa_open_key(id, &handle), PSA_ERROR_DOES_NOT_EXIST); |
| |
| exit: |
| PSA_DONE(); |
| counter_reset(); |
| psa_purge_storage(); |
| } |
| /* END_CASE */ |
| |
| /* BEGIN_CASE */ |
| void generate_key_not_supported(int type_arg, int bits_arg) |
| { |
| psa_key_type_t type = type_arg; |
| size_t bits = bits_arg; |
| psa_drv_se_t driver; |
| psa_drv_se_key_management_t key_management; |
| psa_key_lifetime_t lifetime = TEST_SE_PERSISTENT_LIFETIME; |
| psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(lifetime); |
| mbedtls_svc_key_id_t id = mbedtls_svc_key_id_make(1, 1); |
| mbedtls_svc_key_id_t returned_id; |
| psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| |
| TEST_USES_KEY_ID(id); |
| |
| 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; |
| /* No p_generate method */ |
| |
| PSA_ASSERT(psa_register_se_driver(location, &driver)); |
| PSA_ASSERT(psa_crypto_init()); |
| |
| psa_set_key_id(&attributes, id); |
| psa_set_key_lifetime(&attributes, lifetime); |
| psa_set_key_type(&attributes, type); |
| psa_set_key_bits(&attributes, bits); |
| TEST_EQUAL(psa_generate_key(&attributes, &returned_id), |
| PSA_ERROR_NOT_SUPPORTED); |
| |
| exit: |
| PSA_DONE(); |
| counter_reset(); |
| psa_purge_storage(); |
| } |
| /* END_CASE */ |
| |
| /* BEGIN_CASE depends_on:AT_LEAST_ONE_BUILTIN_KDF */ |
| 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 = TEST_SE_PERSISTENT_LIFETIME; |
| psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(lifetime); |
| mbedtls_svc_key_id_t id = mbedtls_svc_key_id_make(1, 1); |
| mbedtls_svc_key_id_t returned_id; |
| psa_key_handle_t handle; |
| psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| |
| TEST_USES_KEY_ID(id); |
| |
| 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; |
| key_management.p_destroy = null_destroy; |
| |
| PSA_ASSERT(psa_register_se_driver(location, &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_HASH | PSA_KEY_USAGE_VERIFY_HASH | |
| 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, &returned_id)); |
| if (!check_persistent_data(location, |
| &shadow_counter, sizeof(shadow_counter))) { |
| goto exit; |
| } |
| |
| /* Do stuff with the key. */ |
| if (!smoke_test_key(id)) { |
| goto exit; |
| } |
| |
| /* Restart and try again. */ |
| mbedtls_psa_crypto_free(); |
| PSA_ASSERT(psa_register_se_driver(location, &driver)); |
| PSA_ASSERT(psa_crypto_init()); |
| if (!check_persistent_data(location, |
| &shadow_counter, sizeof(shadow_counter))) { |
| goto exit; |
| } |
| if (!smoke_test_key(id)) { |
| goto exit; |
| } |
| |
| /* We're done. */ |
| PSA_ASSERT(psa_destroy_key(id)); |
| if (!check_persistent_data(location, |
| &shadow_counter, sizeof(shadow_counter))) { |
| goto exit; |
| } |
| TEST_EQUAL(psa_open_key(id, &handle), PSA_ERROR_DOES_NOT_EXIST); |
| |
| exit: |
| PSA_DONE(); |
| counter_reset(); |
| psa_purge_storage(); |
| } |
| /* END_CASE */ |
| |
| /* BEGIN_CASE */ |
| void sign_verify(int flow, |
| 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 = TEST_SE_PERSISTENT_LIFETIME; |
| psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(lifetime); |
| mbedtls_svc_key_id_t id = mbedtls_svc_key_id_make(1, 1); |
| mbedtls_svc_key_id_t returned_id; |
| mbedtls_svc_key_id_t sw_key = MBEDTLS_SVC_KEY_ID_INIT; |
| psa_key_attributes_t sw_attributes = PSA_KEY_ATTRIBUTES_INIT; |
| psa_key_attributes_t drv_attributes = PSA_KEY_ATTRIBUTES_INIT; |
| uint8_t signature[PSA_SIGNATURE_MAX_SIZE]; |
| size_t signature_length; |
| |
| TEST_USES_KEY_ID(id); |
| |
| 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(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; |
| } |
| 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_FAIL("unsupported flow (should be SIGN_IN_xxx)"); |
| break; |
| } |
| asymmetric.p_verify = ram_verify; |
| |
| PSA_ASSERT(psa_register_se_driver(location, &driver)); |
| PSA_ASSERT(psa_crypto_init()); |
| |
| /* 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_HASH | PSA_KEY_USAGE_VERIFY_HASH); |
| 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(&drv_attributes, bits); |
| PSA_ASSERT(psa_generate_key(&drv_attributes, &returned_id)); |
| /* 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(id, &drv_attributes)); |
| TEST_EQUAL(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(&drv_attributes, |
| key_material->x, key_material->len, |
| &returned_id)); |
| } |
| |
| /* 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_key)); |
| 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(id, |
| 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_key)); |
| break; |
| } |
| } |
| |
| /* Sign with the chosen key. */ |
| switch (flow) { |
| case SIGN_IN_DRIVER_AND_PARALLEL_CREATION: |
| case SIGN_IN_DRIVER_THEN_EXPORT_PUBLIC: |
| PSA_ASSERT_VIA_DRIVER( |
| psa_sign_hash(id, alg, |
| input->x, input->len, |
| signature, sizeof(signature), |
| &signature_length), |
| PSA_SUCCESS); |
| break; |
| case SIGN_IN_SOFTWARE_AND_PARALLEL_CREATION: |
| PSA_ASSERT(psa_sign_hash(sw_key, alg, |
| input->x, input->len, |
| signature, sizeof(signature), |
| &signature_length)); |
| break; |
| } |
| |
| /* Verify with both keys. */ |
| PSA_ASSERT(psa_verify_hash(sw_key, alg, |
| input->x, input->len, |
| signature, signature_length)); |
| PSA_ASSERT_VIA_DRIVER( |
| psa_verify_hash(id, alg, |
| input->x, input->len, |
| signature, signature_length), |
| PSA_SUCCESS); |
| |
| /* Change the signature and verify again. */ |
| signature[0] ^= 1; |
| TEST_EQUAL(psa_verify_hash(sw_key, alg, |
| input->x, input->len, |
| signature, signature_length), |
| PSA_ERROR_INVALID_SIGNATURE); |
| PSA_ASSERT_VIA_DRIVER( |
| psa_verify_hash(id, alg, |
| input->x, input->len, |
| signature, signature_length), |
| PSA_ERROR_INVALID_SIGNATURE); |
| |
| exit: |
| /* |
| * Driver key attributes may have been returned by psa_get_key_attributes() |
| * thus reset them as required. |
| */ |
| psa_reset_key_attributes(&drv_attributes); |
| |
| psa_destroy_key(id); |
| psa_destroy_key(sw_key); |
| PSA_DONE(); |
| ram_slots_reset(); |
| psa_purge_storage(); |
| } |
| /* END_CASE */ |
| |
| /* BEGIN_CASE */ |
| void register_key_smoke_test(int lifetime_arg, |
| int owner_id_arg, |
| int id_arg, |
| int validate, |
| int expected_status_arg) |
| { |
| psa_key_lifetime_t lifetime = lifetime_arg; |
| psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(lifetime); |
| psa_status_t expected_status = expected_status_arg; |
| psa_drv_se_t driver; |
| psa_drv_se_key_management_t key_management; |
| psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
| mbedtls_svc_key_id_t id = mbedtls_svc_key_id_make(owner_id_arg, id_arg); |
| psa_key_handle_t handle; |
| size_t bit_size = 48; |
| psa_key_slot_number_t wanted_slot = 0x123456789; |
| psa_status_t status; |
| |
| TEST_USES_KEY_ID(id); |
| |
| memset(&driver, 0, sizeof(driver)); |
| driver.hal_version = PSA_DRV_SE_HAL_VERSION; |
| memset(&key_management, 0, sizeof(key_management)); |
| driver.key_management = &key_management; |
| key_management.p_destroy = null_destroy; |
| if (validate >= 0) { |
| key_management.p_validate_slot_number = validate_slot_number_as_directed; |
| validate_slot_number_directions.slot_number = wanted_slot; |
| validate_slot_number_directions.method = PSA_KEY_CREATION_REGISTER; |
| validate_slot_number_directions.status = |
| (validate > 0 ? PSA_SUCCESS : PSA_ERROR_NOT_PERMITTED); |
| } |
| |
| mbedtls_test_set_step(1); |
| PSA_ASSERT(psa_register_se_driver(MIN_DRIVER_LOCATION, &driver)); |
| PSA_ASSERT(psa_crypto_init()); |
| |
| psa_set_key_id(&attributes, id); |
| psa_set_key_lifetime(&attributes, lifetime); |
| psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_EXPORT); |
| psa_set_key_type(&attributes, PSA_KEY_TYPE_RAW_DATA); |
| psa_set_key_bits(&attributes, bit_size); |
| psa_set_key_slot_number(&attributes, wanted_slot); |
| |
| status = mbedtls_psa_register_se_key(&attributes); |
| TEST_EQUAL(status, expected_status); |
| |
| if (status != PSA_SUCCESS) { |
| goto exit; |
| } |
| |
| /* Test that the key exists and has the expected attributes. */ |
| if (!check_key_attributes(id, &attributes)) { |
| goto exit; |
| } |
| |
| #if defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER) |
| mbedtls_svc_key_id_t invalid_id = |
| mbedtls_svc_key_id_make(owner_id_arg + 1, id_arg); |
| TEST_EQUAL(psa_open_key(invalid_id, &handle), PSA_ERROR_DOES_NOT_EXIST); |
| #endif |
| |
| PSA_ASSERT(psa_purge_key(id)); |
| |
| /* Restart and try again. */ |
| mbedtls_test_set_step(2); |
| PSA_SESSION_DONE(); |
| PSA_ASSERT(psa_register_se_driver(location, &driver)); |
| PSA_ASSERT(psa_crypto_init()); |
| if (!check_key_attributes(id, &attributes)) { |
| goto exit; |
| } |
| /* This time, destroy the key. */ |
| PSA_ASSERT(psa_destroy_key(id)); |
| TEST_EQUAL(psa_open_key(id, &handle), PSA_ERROR_DOES_NOT_EXIST); |
| |
| exit: |
| psa_reset_key_attributes(&attributes); |
| psa_destroy_key(id); |
| PSA_DONE(); |
| psa_purge_storage(); |
| memset(&validate_slot_number_directions, 0, |
| sizeof(validate_slot_number_directions)); |
| } |
| /* END_CASE */ |