1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 01:09:47 +01:00

sys/psa_crypto: ed25519 private key {ex,im}port

This commit is contained in:
Mikolai Gütschow 2024-02-02 14:59:46 +01:00
parent a9e7b441a7
commit 5f08f7478b
No known key found for this signature in database
GPG Key ID: 943E2F37AA659AD5
11 changed files with 428 additions and 35 deletions

View File

@ -36,6 +36,18 @@ psa_status_t psa_generate_ecc_ed25519_key_pair( uint8_t *priv_key_buffer, uint8_
return PSA_SUCCESS;
}
psa_status_t psa_derive_ecc_ed25519_public_key( const uint8_t *priv_key_buffer, uint8_t *pub_key_buffer,
size_t priv_key_buffer_length,
size_t *pub_key_buffer_length)
{
*pub_key_buffer_length = EDSIGN_PUBLIC_KEY_SIZE;
edsign_sec_to_pub(pub_key_buffer, priv_key_buffer);
(void)priv_key_buffer_length;
return PSA_SUCCESS;
}
psa_status_t psa_ecc_ed25519_sign_message( const uint8_t *priv_key_buffer,
size_t priv_key_buffer_size,
const uint8_t *pub_key_buffer,

View File

@ -60,6 +60,33 @@ done:
return CRYS_to_psa_error(ret);
}
psa_status_t psa_derive_ecc_ed25519_public_key( const uint8_t *priv_key_buffer, uint8_t *pub_key_buffer,
size_t priv_key_buffer_length,
size_t *pub_key_buffer_length)
{
CRYS_ECEDW_TempBuff_t tmp;
CRYSError_t ret;
/* contains seed (private key), concatenated with public key */
uint8_t secret_key[CRYS_ECEDW_ORD_SIZE_IN_BYTES + CRYS_ECEDW_MOD_SIZE_IN_BYTES] = { 0x0 };
size_t secret_key_size = sizeof(secret_key);
*pub_key_buffer_length = CRYS_ECEDW_MOD_SIZE_IN_BYTES;
cryptocell_310_enable();
ret = CRYS_ECEDW_SeedKeyPair(priv_key_buffer, priv_key_buffer_length, secret_key, &secret_key_size,
pub_key_buffer, pub_key_buffer_length, &tmp);
cryptocell_310_disable();
if (ret != CRYS_OK) {
DEBUG("CRYS_ECEDW_SeedKeyPair failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
goto done;
}
done:
explicit_bzero(&secret_key, sizeof(secret_key));
return CRYS_to_psa_error(ret);
}
psa_status_t psa_ecc_ed25519_sign_message(const uint8_t *priv_key_buffer,
size_t priv_key_buffer_size,
const uint8_t *pub_key_buffer,

View File

@ -791,6 +791,22 @@ extern "C" {
#define PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(key_type, key_bits, alg) \
/* implementation-defined value */
/**
* @brief Maximum size of the export encoding of an ECC keypair.
*
* @details The representation of an ECC keypair follows
* https://arm-software.github.io/psa-api/crypto/1.1/api/keys/management.html#key-formats
* and is dependent on the family:
* - for twisted Edwards curves: 32B
* - for Weierstrass curves: `ceiling(m/8)`-byte string, big-endian
* where m is the bit size associated with the curve.
*/
#define PSA_KEY_EXPORT_ECC_KEY_MAX_SIZE(key_type, key_bits) \
(size_t)\
(PSA_KEY_TYPE_ECC_GET_FAMILY(key_type) == PSA_ECC_FAMILY_TWISTED_EDWARDS ? 32 : \
(PSA_KEY_TYPE_ECC_GET_FAMILY(key_type) == PSA_ECC_FAMILY_SECP_R1 ? PSA_BITS_TO_BYTES(key_bits) : \
0))
/**
* @brief Sufficient output buffer size for @ref psa_export_key().
*
@ -828,7 +844,9 @@ extern "C" {
* Unspecified if the parameters are not valid.
*/
#define PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, key_bits) \
/* implementation-defined value */
(PSA_KEY_TYPE_IS_PUBLIC_KEY(key_type) ? PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, key_bits) : \
(PSA_KEY_TYPE_IS_ECC(key_type) ? PSA_KEY_EXPORT_ECC_KEY_MAX_SIZE(key_type, key_bits) : \
0))
/**
* @brief Check whether the key size is a valid ECC size for key type.
@ -861,7 +879,19 @@ extern "C" {
*
* See also @ref PSA_EXPORT_KEY_OUTPUT_SIZE().
*/
#define PSA_EXPORT_KEY_PAIR_MAX_SIZE /* implementation-defined value */
#if (IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1) || \
IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256))
#define PSA_EXPORT_KEY_PAIR_MAX_SIZE \
(PSA_EXPORT_KEY_OUTPUT_SIZE(PSA_ECC_FAMILY_SECT_R1, 256))
#elif (IS_USED(MODULE_PSA_ASYMMETRIC_ECC_ED25519))
#define PSA_EXPORT_KEY_PAIR_MAX_SIZE \
(PSA_EXPORT_KEY_OUTPUT_SIZE(PSA_ECC_FAMILY_TWISTED_EDWARDS, 255))
#elif (IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1))
#define PSA_EXPORT_KEY_PAIR_MAX_SIZE \
(PSA_EXPORT_KEY_OUTPUT_SIZE(PSA_ECC_FAMILY_SECT_R1, 192))
#else
#define PSA_EXPORT_KEY_PAIR_MAX_SIZE 0
#endif
/**
* @brief Get curve size from ECC public key
@ -958,13 +988,17 @@ extern "C" {
* See also @ref PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(@p key_type, @p key_bits).
*/
#if (IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1) || \
IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1) || \
IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256))
IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256))
#define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE \
(PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_ECC_FAMILY_SECT_R1, PSA_MAX_PRIV_KEY_SIZE))
(PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_ECC_FAMILY_SECT_R1, 256))
#elif (IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1))
#define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE \
(PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_ECC_FAMILY_SECT_R1, 192))
#elif (IS_USED(MODULE_PSA_ASYMMETRIC_ECC_ED25519))
#define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE \
(PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_ECC_FAMILY_TWISTED_EDWARDS, 255))
#else
#define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE \
(PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_ECC_FAMILY_TWISTED_EDWARDS, PSA_MAX_PRIV_KEY_SIZE))
#define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE 0
#endif
/**

View File

@ -175,6 +175,21 @@ psa_status_t psa_algorithm_dispatch_verify_message( const psa_key_attributes_t *
*/
psa_status_t psa_algorithm_dispatch_generate_key( const psa_key_attributes_t *attributes,
psa_key_slot_t *slot);
/**
* @brief Dispatch the key import function to a specific backend.
* See psa_import_key()
*
* @param attributes
* @param data
* @param data_length
* @param slot
* @param bits
* @return psa_status_t
*/
psa_status_t psa_algorithm_dispatch_import_key(const psa_key_attributes_t *attributes,
const uint8_t *data, size_t data_length,
psa_key_slot_t *slot, size_t *bits);
#endif
#if IS_USED(MODULE_PSA_CIPHER)

View File

@ -253,6 +253,19 @@ psa_status_t psa_generate_ecc_ed25519_key_pair( uint8_t *priv_key_buffer, uint8_
size_t *priv_key_buffer_length,
size_t *pub_key_buffer_length);
/**
* @brief Low level wrapper function to call a driver for deriving an ed25519 public key from the private key.
*
* @param[in] priv_key_buffer
* @param[out] pub_key_buffer
* @param[in] priv_key_buffer_length
* @param[inout] pub_key_buffer_length
* @return @ref psa_status_t
*/
psa_status_t psa_derive_ecc_ed25519_public_key( const uint8_t *priv_key_buffer, uint8_t *pub_key_buffer,
size_t priv_key_buffer_length,
size_t *pub_key_buffer_length);
/**
* @brief Low level wrapper function to call a driver for an ECC hash signature
* with an ed25519 key.

View File

@ -1220,16 +1220,102 @@ psa_status_t psa_destroy_key(psa_key_id_t key)
return psa_wipe_key_slot(slot);
}
/**
* @brief Export key that is stored in local memory
*
* See @ref psa_export_key
*
* @param key_buffer
* @param key_buffer_size
* @param data
* @param data_size
* @param data_length
*
* @return @ref PSA_SUCCESS
* @ref PSA_ERROR_INVALID_ARGUMENT
*/
static psa_status_t psa_builtin_export_key(const uint8_t *key_buffer,
size_t key_buffer_size,
uint8_t *data,
size_t data_size,
size_t *data_length)
{
if (!key_buffer || !data || !data_length) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (key_buffer_size == 0 || data_size == 0) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (data_size < key_buffer_size) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
memcpy(data, key_buffer, key_buffer_size);
*data_length = key_buffer_size;
return PSA_SUCCESS;
}
psa_status_t psa_export_key(psa_key_id_t key,
uint8_t *data,
size_t data_size,
size_t *data_length)
{
(void)key;
(void)data;
(void)data_size;
(void)data_length;
return PSA_ERROR_NOT_SUPPORTED;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot;
uint8_t *privkey_data = NULL;
size_t *privkey_data_len = NULL;
if (!lib_initialized) {
return PSA_ERROR_BAD_STATE;
}
if (!data || !data_length) {
return PSA_ERROR_INVALID_ARGUMENT;
}
*data_length = 0;
status = psa_get_and_lock_key_slot_with_policy(key, &slot, PSA_KEY_USAGE_EXPORT, 0);
if (status != PSA_SUCCESS) {
unlock_status = psa_unlock_key_slot(slot);
if (unlock_status != PSA_SUCCESS) {
status = unlock_status;
}
return status;
}
psa_key_lifetime_t lifetime = psa_get_key_lifetime(&slot->attr);
if (psa_key_lifetime_is_external(lifetime)) {
/* key export from an external device is currently not supported */
status = PSA_ERROR_NOT_SUPPORTED;
unlock_status = psa_unlock_key_slot(slot);
if (unlock_status != PSA_SUCCESS) {
status = unlock_status;
}
return status;
}
if (!PSA_KEY_TYPE_IS_ECC(slot->attr.type) ||
PSA_KEY_TYPE_ECC_GET_FAMILY(slot->attr.type) != PSA_ECC_FAMILY_TWISTED_EDWARDS) {
/* key export is currently only supported for ed25519 keys */
status = PSA_ERROR_NOT_SUPPORTED;
unlock_status = psa_unlock_key_slot(slot);
if (unlock_status != PSA_SUCCESS) {
status = unlock_status;
}
return status;
}
psa_get_key_data_from_key_slot(slot, &privkey_data, &privkey_data_len);
status =
psa_builtin_export_key(privkey_data, *privkey_data_len, data, data_size, data_length);
unlock_status = psa_unlock_key_slot(slot);
return ((status == PSA_SUCCESS) ? unlock_status : status);
}
/**
@ -1260,10 +1346,6 @@ static psa_status_t psa_builtin_export_public_key( const uint8_t *key_buffer,
DEBUG("PSA Crypto Builtin Export Key: Output buffer too small\n");
return PSA_ERROR_BUFFER_TOO_SMALL;
}
/** Some implementations and drivers can generate a public key from existing private key
* material. This implementation does not support the recalculation of a public key, yet.
* It requires the key to already exist in local memory and just copies it into the data
* output. */
memcpy(data, key_buffer, key_buffer_size);
*data_length = key_buffer_size;
@ -1456,8 +1538,10 @@ psa_status_t psa_builtin_import_key(const psa_key_attributes_t *attributes,
if (data_length > PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) {
return PSA_ERROR_NOT_SUPPORTED;
}
memcpy(key_buffer, data, data_length);
*key_buffer_length = data_length;
return PSA_SUCCESS;
}
return status;

View File

@ -427,6 +427,73 @@ psa_status_t psa_algorithm_dispatch_generate_key( const psa_key_attributes_t *
return psa_builtin_generate_key(attributes, key_data, *key_bytes, key_bytes);
}
psa_status_t psa_algorithm_dispatch_import_key(const psa_key_attributes_t *attributes,
const uint8_t *data, size_t data_length,
psa_key_slot_t *slot, size_t *bits)
{
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
size_t key_data_size;
key_data_size = psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
/**
* Asymmetric keys needs special import handling:
* The public key needs to be derived from the imported private key.
*/
if (PSA_KEY_TYPE_IS_KEY_PAIR(attributes->type)) {
psa_asym_key_t asym_key = PSA_INVALID_OPERATION;
uint8_t *pubkey_data = NULL;
size_t *pubkey_data_len = NULL;
psa_get_public_key_data_from_key_slot(slot, &pubkey_data, &pubkey_data_len);
if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(attributes->type)) {
asym_key =
PSA_ENCODE_ECC_KEY_TYPE(attributes->bits,
PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->type));
if (asym_key == PSA_INVALID_OPERATION) {
return PSA_ERROR_INVALID_ARGUMENT;
}
}
// derive and save public from private key
psa_status_t ret = PSA_ERROR_NOT_SUPPORTED;
switch (asym_key) {
#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1)
case PSA_ECC_P192_R1:
// todo: support for Weierstrass curves
(void)slot;
ret = PSA_ERROR_NOT_SUPPORTED;
break;
#endif
#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1)
case PSA_ECC_P256_R1:
// todo: support for Weierstrass curves
(void)slot;
ret = PSA_ERROR_NOT_SUPPORTED;
break;
#endif
#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_ED25519)
case PSA_ECC_ED25519:
ret = psa_derive_ecc_ed25519_public_key(data, pubkey_data, data_length, pubkey_data_len);
break;
#endif
default:
(void)slot;
ret = PSA_ERROR_NOT_SUPPORTED;
break;
}
if (ret == PSA_SUCCESS) {
/* save private key data */
memcpy(key_data, data, data_length);
*key_bytes = data_length;
}
return ret;
}
return psa_builtin_import_key(attributes, data, data_length, key_data, key_data_size, key_bytes, bits);
}
#endif /* MODULE_PSA_KEY_MANAGEMENT */
#if IS_USED(MODULE_PSA_CIPHER)

View File

@ -66,15 +66,10 @@ psa_status_t psa_location_dispatch_import_key( const psa_key_attributes_t *attri
const uint8_t *data, size_t data_length,
psa_key_slot_t *slot, size_t *bits)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime);
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
size_t key_data_size;
key_data_size = psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
@ -100,9 +95,8 @@ psa_status_t psa_location_dispatch_import_key( const psa_key_attributes_t *attri
switch (location) {
case PSA_KEY_LOCATION_LOCAL_STORAGE:
return psa_builtin_import_key(attributes, data, data_length, key_data, key_data_size, key_bytes, bits);
return psa_algorithm_dispatch_import_key(attributes, data, data_length, slot, bits);
default:
(void)status;
return PSA_ERROR_NOT_SUPPORTED;
}
}

View File

@ -4,6 +4,8 @@ USEMODULE += embunit
USEMODULE += psa_crypto
CFLAGS += -DTHREAD_STACKSIZE_MAIN=\(8*THREAD_STACKSIZE_DEFAULT\)
CFLAGS += -DCONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=1

View File

@ -6,6 +6,21 @@ BOARD_INSUFFICIENT_MEMORY := \
atmega328p \
atmega328p-xplained-mini \
atmega8 \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
nucleo-f030r8 \
nucleo-f031k6 \
nucleo-f042k6 \
nucleo-l011k4 \
nucleo-l031k6 \
nucleo-l053r8 \
samd10-xmini \
slstk3400a \
stk3200 \
stm32f030f4-demo \
stm32f0discovery \
stm32g0316-disco \
stm32l0538-disco \
waspmote-pro \
weact-g030f6 \
#

View File

@ -22,37 +22,167 @@
#include "embUnit.h"
#include "psa/crypto.h"
#define TEST_ASSERT_PSA(func_) TEST_ASSERT_MESSAGE(func_ == PSA_SUCCESS, #func_ " failed");
void addFailurePSA(const char *func, psa_status_t errcode, long line, const char *file)
{
static char msg[128];
strncpy(msg, func, sizeof(msg));
strcat(msg, ": ");
strcat(msg, psa_status_to_humanly_readable(errcode));
addFailure(msg, line, file);
}
#define TEST_ASSERT_PSA(func_, do_) { psa_status_t ret = func_; if (ret != PSA_SUCCESS) { addFailurePSA(#func_, ret, __LINE__, __FILE__); do_; } }
#define TEST_ASSERT_PSA_CLEANUP(func_) TEST_ASSERT_PSA(func_, goto cleanup)
#define TEST_ASSERT_PSA_RETURN(func_) TEST_ASSERT_PSA(func_, return)
#define TEST_ASSERT_PSA_CONTINUE(func_) TEST_ASSERT_PSA(func_, )
/*
* A second call to psa_crypto_init() should not reset key data.
*/
static void test_init_twice(void)
{
TEST_ASSERT_PSA(psa_crypto_init());
const psa_key_type_t key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS);
const size_t key_bits = 255;
const psa_algorithm_t key_alg = PSA_ALG_PURE_EDDSA;
uint8_t key_data[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, key_bits)];
size_t key_data_len;
psa_key_id_t key_id = PSA_KEY_ID_NULL;
psa_key_attributes_t key_attr = psa_key_attributes_init();
psa_set_key_algorithm(&key_attr, PSA_ALG_PURE_EDDSA);
psa_set_key_algorithm(&key_attr, key_alg);
psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_EXPORT);
psa_set_key_bits(&key_attr, 255);
psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS));
TEST_ASSERT_PSA(psa_generate_key(&key_attr, &key_id));
psa_set_key_bits(&key_attr, key_bits);
psa_set_key_type(&key_attr, key_type);
uint8_t key_data[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(psa_get_key_type(&key_attr), psa_get_key_bits(&key_attr))];
size_t key_data_len;
TEST_ASSERT_PSA_CLEANUP(psa_crypto_init());
TEST_ASSERT_PSA_CLEANUP(psa_generate_key(&key_attr, &key_id));
TEST_ASSERT_PSA(psa_export_public_key(key_id, key_data, sizeof(key_data), &key_data_len));
TEST_ASSERT_PSA(psa_crypto_init());
TEST_ASSERT_PSA(psa_export_public_key(key_id, key_data, sizeof(key_data), &key_data_len));
TEST_ASSERT_PSA_CLEANUP(psa_export_public_key(key_id, key_data, sizeof(key_data), &key_data_len));
TEST_ASSERT_PSA_CLEANUP(psa_crypto_init());
TEST_ASSERT_PSA_CLEANUP(psa_export_public_key(key_id, key_data, sizeof(key_data), &key_data_len));
cleanup:
TEST_ASSERT_PSA_CONTINUE(psa_destroy_key(key_id));
}
/**
* Exporting and re-importing a private Ed25519 key should result in the same public key and signature.
*/
static void test_exported_key_is_identical_when_imported_again_ed25519(void)
{
const psa_key_type_t key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS);
const size_t key_bits = 255;
const psa_algorithm_t key_alg = PSA_ALG_PURE_EDDSA;
// buffers to hold randomly generated Ed25519 keypair
uint8_t privkey[PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, key_bits)];
size_t privkey_len;
uint8_t pubkey[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, key_bits)];
size_t pubkey_len;
// buffer to hold Ed25519 public key derived from imported private key
uint8_t pubkey2[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, key_bits)];
size_t pubkey2_len;
// buffers to hold signature for verification
uint8_t msg[] = "Hello world!";
uint8_t sig[PSA_SIGN_OUTPUT_SIZE(key_type, key_bits, key_alg)];
size_t sig_len;
uint8_t sig2[PSA_SIGN_OUTPUT_SIZE(key_type, key_bits, key_alg)];
size_t sig2_len;
// work on Ed25519 keypair which can be exported and used for signing messages
psa_key_id_t key_id = PSA_KEY_ID_NULL;
psa_key_attributes_t key_attr = psa_key_attributes_init();
psa_set_key_algorithm(&key_attr, key_alg);
psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_EXPORT);
psa_set_key_bits(&key_attr, key_bits);
psa_set_key_type(&key_attr, key_type);
// randomly generate keypair
TEST_ASSERT_PSA_CLEANUP(psa_crypto_init());
TEST_ASSERT_PSA_CLEANUP(psa_generate_key(&key_attr, &key_id));
// sign msg with generated keypair
TEST_ASSERT_PSA_CLEANUP(psa_sign_message(key_id, key_alg, msg, sizeof(msg), sig, sizeof(sig), &sig_len));
// export public and private key, then free slot
TEST_ASSERT_PSA_CLEANUP(psa_export_public_key(key_id, pubkey, sizeof(pubkey), &pubkey_len));
TEST_ASSERT_PSA_CLEANUP(psa_export_key(key_id, privkey, sizeof(privkey), &privkey_len));
TEST_ASSERT_PSA_CLEANUP(psa_destroy_key(key_id));
// import private key and compare public keys
psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_MESSAGE);
TEST_ASSERT_PSA_CLEANUP(psa_import_key(&key_attr, privkey, privkey_len, &key_id));
TEST_ASSERT_PSA_CLEANUP(psa_export_public_key(key_id, pubkey2, sizeof(pubkey2), &pubkey2_len));
TEST_ASSERT(pubkey_len == pubkey2_len && memcmp(pubkey, pubkey2, pubkey_len) == 0);
// sign msg with imported key and compare signatures
TEST_ASSERT_PSA_CLEANUP(psa_sign_message(key_id, key_alg, msg, sizeof(msg), sig2, sizeof(sig2), &sig2_len));
TEST_ASSERT(sig_len == sig2_len && memcmp(sig, sig2, sig_len) == 0);
cleanup:
TEST_ASSERT_PSA_CONTINUE(psa_destroy_key(key_id));
}
/**
* psa_export_key() is an alias for psa_export_public_key() if the given key is a public key
*/
static void test_export_public_key_ed25519(void)
{
const psa_key_type_t key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS);
const psa_key_type_t key_type2 = PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_TWISTED_EDWARDS);
const size_t key_bits = 255;
const psa_algorithm_t key_alg = PSA_ALG_PURE_EDDSA;
// buffers to hold exported public key
uint8_t pubkey[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, key_bits)];
size_t pubkey_len;
uint8_t pubkey2[PSA_EXPORT_KEY_OUTPUT_SIZE(key_type2, key_bits)];
size_t pubkey2_len;
// work on Ed25519 keypair which has no special usage permissions
// as exporting the public key is allowed even without PSA_KEY_USAGE_EXPORT
psa_key_id_t key_id = PSA_KEY_ID_NULL;
psa_key_attributes_t key_attr = psa_key_attributes_init();
psa_set_key_algorithm(&key_attr, key_alg);
psa_set_key_usage_flags(&key_attr, 0);
psa_set_key_bits(&key_attr, key_bits);
psa_set_key_type(&key_attr, key_type);
psa_key_id_t key_id2 = PSA_KEY_ID_NULL;
// randomly generate keypair
TEST_ASSERT_PSA_CLEANUP(psa_crypto_init());
TEST_ASSERT_PSA_CLEANUP(psa_generate_key(&key_attr, &key_id));
// export public key
TEST_ASSERT_PSA_CLEANUP(psa_export_public_key(key_id, pubkey, sizeof(pubkey), &pubkey_len));
// import public key into single-key slot
psa_set_key_type(&key_attr, key_type2);
TEST_ASSERT_PSA_CLEANUP(psa_import_key(&key_attr, pubkey, pubkey_len, &key_id2));
// export public key from single slot using `psa_export_key()` and compare
TEST_ASSERT_PSA_CLEANUP(psa_export_key(key_id2, pubkey2, sizeof(pubkey2), &pubkey2_len));
TEST_ASSERT(pubkey_len == pubkey2_len && memcmp(pubkey, pubkey2, pubkey_len) == 0);
// export public key from single slot using `psa_export_public_key()` and compare again
TEST_ASSERT_PSA_CLEANUP(psa_export_public_key(key_id2, pubkey2, sizeof(pubkey2), &pubkey2_len));
TEST_ASSERT(pubkey_len == pubkey2_len && memcmp(pubkey, pubkey2, pubkey_len) == 0);
cleanup:
TEST_ASSERT_PSA_CONTINUE(psa_destroy_key(key_id));
TEST_ASSERT_PSA_CONTINUE(psa_destroy_key(key_id2));
}
static Test *tests_psa_crypto(void)
{
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(test_init_twice),
new_TestFixture(test_exported_key_is_identical_when_imported_again_ed25519),
new_TestFixture(test_export_public_key_ed25519),
};
EMB_UNIT_TESTCALLER(tests, NULL, NULL, fixtures);