Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions pkg/c25519/psa_c25519/edsign.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@
return PSA_SUCCESS;
}

psa_status_t psa_derive_ecc_ed25519_public_key( const uint8_t *priv_key_buffer, uint8_t *pub_key_buffer,

Check warning on line 39 in pkg/c25519/psa_c25519/edsign.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
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,
Expand Down
27 changes: 27 additions & 0 deletions pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_ed25519.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,33 @@
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,

Check warning on line 63 in pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_ed25519.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
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,

Check warning on line 77 in pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_ed25519.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
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));

Check warning on line 81 in pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_ed25519.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
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,
Expand All @@ -80,7 +107,7 @@
/* 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 };

if (priv_key_buffer_size != CRYS_ECEDW_ORD_SIZE_IN_BYTES || pub_key_buffer_size != CRYS_ECEDW_MOD_SIZE_IN_BYTES) {

Check warning on line 110 in pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_ed25519.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
return PSA_ERROR_INVALID_ARGUMENT;
}

Expand All @@ -89,7 +116,7 @@
*signature_length = signature_size;

cryptocell_310_enable();
ret = CRYS_ECEDW_Sign(signature, signature_length, input, input_length, secret_key, sizeof(secret_key), &tmp);

Check warning on line 119 in pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_ed25519.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
cryptocell_310_disable();
if (ret != CRYS_OK) {
DEBUG("CRYS_ECEDW_Sign failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
Expand Down Expand Up @@ -118,7 +145,7 @@
}

cryptocell_310_enable();
ret = CRYS_ECEDW_Verify(signature, signature_length, key_buffer, key_buffer_size, (uint8_t *)input, input_length, &tmp);

Check warning on line 148 in pkg/driver_cryptocell_310/psa_cryptocell_310/ecc_ed25519.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
cryptocell_310_disable();
if (ret != CRYS_OK) {
DEBUG("CRYS_ECEDW_Verify failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
Expand Down
48 changes: 41 additions & 7 deletions sys/include/psa_crypto/psa/crypto_sizes.h
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,22 @@
#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) : \

Check warning on line 807 in sys/include/psa_crypto/psa/crypto_sizes.h

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
0))

/**
* @brief Sufficient output buffer size for @ref psa_export_key().
*
Expand Down Expand Up @@ -828,7 +844,9 @@
* 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) : \

Check warning on line 847 in sys/include/psa_crypto/psa/crypto_sizes.h

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
(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.
Expand Down Expand Up @@ -861,7 +879,19 @@
*
* 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
Expand Down Expand Up @@ -958,13 +988,17 @@
* 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))
#else
(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, PSA_MAX_PRIV_KEY_SIZE))
(PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_ECC_FAMILY_TWISTED_EDWARDS, 255))
#else
#define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE 0
#endif

/**
Expand Down Expand Up @@ -1025,7 +1059,7 @@
* If the parameters are not valid, the return value is unspecified.
*/
#define PSA_SIGN_OUTPUT_SIZE(key_type, key_bits, alg) \
(PSA_KEY_TYPE_IS_ECC(key_type) ? PSA_ECDSA_SIGNATURE_SIZE(PSA_ECC_KEY_GET_CURVE(key_type, key_bits)) : \

Check warning on line 1062 in sys/include/psa_crypto/psa/crypto_sizes.h

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
((void)alg, 0))

#ifdef __cplusplus
Expand Down
15 changes: 15 additions & 0 deletions sys/psa_crypto/include/psa_crypto_algorithm_dispatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Teufelchen1 marked this conversation as resolved.
Show resolved Hide resolved
*/
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)
Expand Down
13 changes: 13 additions & 0 deletions sys/psa_crypto/include/psa_ecc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
102 changes: 93 additions & 9 deletions sys/psa_crypto/psa_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand Down Expand Up @@ -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");
mguetschow marked this conversation as resolved.
Show resolved Hide resolved
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;

Expand Down Expand Up @@ -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;
Expand Down
67 changes: 67 additions & 0 deletions sys/psa_crypto/psa_crypto_algorithm_dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading
Loading