21e46b39cc
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
1533 lines
55 KiB
C
1533 lines
55 KiB
C
/* 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 */
|