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:
parent
a9e7b441a7
commit
5f08f7478b
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 \
|
||||
#
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user