Skip to content

Commit

Permalink
Merge #19954 #19966
Browse files Browse the repository at this point in the history
19954: sys/psa_crypto: Ed25519 (EdDSA) support r=benpicco a=mguetschow

### Contribution description

- implement [`psa_sign_message()`](https://armmbed.github.io/mbed-crypto/html/api/ops/sign.html#c.psa_sign_message) and [`psa_verify_message()`](https://armmbed.github.io/mbed-crypto/html/api/ops/sign.html#c.psa_verify_message) for the two already supported [`PSA_ALG_ECDSA`](https://armmbed.github.io/mbed-crypto/html/api/ops/sign.html#c.PSA_ALG_ECDSA) algorithms, together with the CryptoCell and `micro-ecc` backends (*not* for the SE backend)
- add support for [`PSA_ALG_PURE_EDDSA`](https://armmbed.github.io/mbed-crypto/html/api/ops/sign.html#c.PSA_ALG_PURE_EDDSA), together with the CryptoCell hardware and `c25519` software backend (*not* for the SE backend)
- wipe private key data from stack for both ECDSA and EdDSA algorithms using `explicit_bzero()` (opinions from experienced Riot maintainers about usage of `goto` to avoid duplicating that function call before every `return`?)


### Testing procedure

- `examples/psa_crypto` has been updated to include EdDSA
- successfully tested configurations:
  - `nrf52840dk` with cryptocell (hardware) and `c25519` (software) backend
  - `native` with software backend


### Issues/PRs references

Thanks `@Einhornhool` for the PSA Crypto framework implementation #18547  which is great to work with!

19966: sys/event: add event_is_queued() r=benpicco a=fabian18



Co-authored-by: Mikolai Gütschow <mikolai.guetschow@tu-dresden.de>
Co-authored-by: Fabian Hüßler <fabian.huessler@ml-pa.com>
  • Loading branch information
3 people authored Oct 10, 2023
3 parents dd62f41 + b2262ae + 3047bef commit 5359ac2
Show file tree
Hide file tree
Showing 47 changed files with 1,291 additions and 201 deletions.
1 change: 1 addition & 0 deletions cpu/nrf52/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ config CPU_MODEL_NRF52840XXAA
select HAS_PERIPH_CIPHER_AES_128_CBC
select HAS_PERIPH_ECC_P192R1
select HAS_PERIPH_ECC_P256R1
select HAS_PERIPH_ECC_ED25519
select HAS_PERIPH_CRYPTOCELL_310

## CPU common symbols
Expand Down
1 change: 1 addition & 0 deletions cpu/nrf52/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ ifneq (,$(filter nrf52840xxaa,$(CPU_MODEL)))
FEATURES_PROVIDED += periph_cipher_aes_128_cbc
FEATURES_PROVIDED += periph_ecc_p192r1
FEATURES_PROVIDED += periph_ecc_p256r1
FEATURES_PROVIDED += periph_ecc_ed25519
endif

ifeq (,$(filter nrf52832%,$(CPU_MODEL)))
Expand Down
6 changes: 6 additions & 0 deletions cpu/nrf52/periph/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ config MODULE_PERIPH_ECC_P256R1
select MODULE_PERIPH_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_ECC_P256

config MODULE_PERIPH_ECC_ED25519
bool
depends on HAS_PERIPH_ECC_ED25519
select MODULE_PERIPH_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_ECC_ED25519

# Hash Related Symbols
config MODULE_PERIPH_HASH_SHA_1
bool
Expand Down
5 changes: 5 additions & 0 deletions cpu/nrf52/periph/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ ifneq (,$(filter periph_ecc_p256r1,$(USEMODULE)))
USEMODULE += psa_cryptocell_310_ecc_p256
endif

ifneq (,$(filter periph_ecc_ed25519,$(USEMODULE)))
USEPKG += driver_cryptocell_310
USEMODULE += psa_cryptocell_310_ecc_ed25519
endif

ifneq (,$(filter periph_hash_sha_1,$(USEMODULE)))
USEPKG += driver_cryptocell_310
USEMODULE += psa_cryptocell_310_hashes_sha1
Expand Down
11 changes: 8 additions & 3 deletions examples/psa_crypto/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ else
USEMODULE += psa_secure_element_ateccx08a_ecc_p256
else ifdef CUSTOM_BACKEND
# Necessary configuration when using Make dependency resolution
# This first part chooses the operation. If nothing else es specified,
# This first part chooses the operation. If nothing else is specified,
# a default backend is built depending on the platform capabilities.
USEMODULE += psa_cipher
USEMODULE += psa_cipher_aes_128_cbc
Expand All @@ -73,6 +73,7 @@ else

USEMODULE += psa_asymmetric
USEMODULE += psa_asymmetric_ecc_p256r1
USEMODULE += psa_asymmetric_ecc_ed25519

# If you want to use a custom backend, you need to do it this way.
USEMODULE += psa_cipher_aes_128_cbc_custom_backend
Expand All @@ -86,6 +87,9 @@ else

USEMODULE += psa_asymmetric_ecc_p256r1_custom_backend
USEMODULE += psa_asymmetric_ecc_p256r1_backend_microecc # force custom backend

USEMODULE += psa_asymmetric_ecc_ed25519_custom_backend
USEMODULE += psa_asymmetric_ecc_ed25519_backend_c25519 # force custom backend
else
# Necessary configuration when using Make dependency resolution
# This part only chooses the operation. If nothing else es specified,
Expand All @@ -98,11 +102,12 @@ else

USEMODULE += psa_asymmetric
USEMODULE += psa_asymmetric_ecc_p256r1
USEMODULE += psa_asymmetric_ecc_ed25519
endif

ifndef SECURE_ELEMENT
CFLAGS += -DCONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=3
CFLAGS += -DCONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=2
CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=4
endif
endif

Expand Down
3 changes: 2 additions & 1 deletion examples/psa_crypto/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ This example application is supposed to show two things:
2. How to configure the implementation with Kconfig dependency resolution vs. Make dependency resolution

## Basic usage of PSA Crypto
There are three example operations:
There are four example operations:
- AES 128 CBC
- HMAC SHA256
- ECDSA with a P256 curve
- EdDSA with the Ed25519 curve

Each comes in its own sourcefile called `example_<operation>.c`. To see which functions to call to perform each operations, please read the code.

Expand Down
5 changes: 3 additions & 2 deletions examples/psa_crypto/app.config.test.base
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ CONFIG_MODULE_PSA_MAC_HMAC_SHA_256=y

CONFIG_MODULE_PSA_ASYMMETRIC=y
CONFIG_MODULE_PSA_ASYMMETRIC_ECC_P256R1=y
CONFIG_MODULE_PSA_ASYMMETRIC_ECC_ED25519=y

CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
CONFIG_PSA_SINGLE_KEY_COUNT=3
CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=2
CONFIG_PSA_SINGLE_KEY_COUNT=4
5 changes: 3 additions & 2 deletions examples/psa_crypto/app.config.test.custom
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ CONFIG_MODULE_PSA_CIPHER_AES_128_CBC_BACKEND_RIOT=y
CONFIG_MODULE_PSA_HASH_SHA_256_BACKEND_RIOT=y
CONFIG_MODULE_PSA_MAC_HMAC_SHA_256_BACKEND_RIOT=y
CONFIG_MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_MICROECC=y
CONFIG_MODULE_PSA_ASYMMETRIC_ECC_ED25519_BACKEND_C25519=y

CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
CONFIG_PSA_SINGLE_KEY_COUNT=3
CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=2
CONFIG_PSA_SINGLE_KEY_COUNT=4
68 changes: 30 additions & 38 deletions examples/psa_crypto/example_ecdsa_p256.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@
#include "psa/crypto.h"

#define ECDSA_MESSAGE_SIZE (127)

#define ECC_KEY_SIZE (256)
#define ECC_KEY_TYPE (PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1))
#define ECC_ALG_HASH (PSA_ALG_SHA_256)
#define ECC_ALG (PSA_ALG_ECDSA(ECC_ALG_HASH))

/**
* @brief Example function to perform an ECDSA operation with a NIST P256 curve
Expand All @@ -39,26 +43,19 @@ psa_status_t example_ecdsa_p256(void)
psa_key_attributes_t pubkey_attr = psa_key_attributes_init();

psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH;
psa_key_type_t type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
psa_key_bits_t bits = ECC_KEY_SIZE;
uint8_t bytes =
PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), bits);

uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(
PSA_ECC_FAMILY_SECP_R1),
ECC_KEY_SIZE)] = { 0 };

uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(ECC_KEY_TYPE, ECC_KEY_SIZE)] = { 0 };
size_t pubkey_length;
uint8_t signature[PSA_SIGN_OUTPUT_SIZE(type, bits, alg)];
uint8_t signature[PSA_SIGN_OUTPUT_SIZE(ECC_KEY_TYPE, ECC_KEY_SIZE, ECC_ALG)];
size_t sig_length;
uint8_t msg[ECDSA_MESSAGE_SIZE] = { 0x0b };
uint8_t hash[PSA_HASH_LENGTH(PSA_ALG_SHA_256)];
uint8_t hash[PSA_HASH_LENGTH(ECC_ALG_HASH)];
size_t hash_length;

psa_set_key_algorithm(&privkey_attr, alg);
psa_set_key_algorithm(&privkey_attr, ECC_ALG);
psa_set_key_usage_flags(&privkey_attr, usage);
psa_set_key_type(&privkey_attr, type);
psa_set_key_bits(&privkey_attr, bits);
psa_set_key_type(&privkey_attr, ECC_KEY_TYPE);
psa_set_key_bits(&privkey_attr, ECC_KEY_SIZE);

#ifdef SECURE_ELEMENT
psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
Expand All @@ -78,31 +75,32 @@ psa_status_t example_ecdsa_p256(void)
return status;
}

status = psa_hash_compute(PSA_ALG_SHA_256, msg, sizeof(msg), hash, sizeof(hash), &hash_length);
status = psa_hash_compute(ECC_ALG_HASH, msg, sizeof(msg), hash, sizeof(hash), &hash_length);
if (status != PSA_SUCCESS) {
return status;
}

#ifdef SECURE_ELEMENT
psa_set_key_lifetime(&pubkey_attr, lifetime);
#endif
psa_set_key_algorithm(&pubkey_attr, alg);
psa_set_key_usage_flags(&pubkey_attr, PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(bytes));
psa_set_key_algorithm(&pubkey_attr, ECC_ALG);
psa_set_key_usage_flags(&pubkey_attr, PSA_KEY_USAGE_VERIFY_MESSAGE);
psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(pubkey_length));
psa_set_key_type(&pubkey_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));

status = psa_import_key(&pubkey_attr, public_key, pubkey_length, &pubkey_id);
if (status != PSA_SUCCESS) {
return status;
}

status = psa_sign_hash(privkey_id, alg, hash, sizeof(hash), signature, sizeof(signature),
status = psa_sign_hash(privkey_id, ECC_ALG, hash, sizeof(hash), signature, sizeof(signature),
&sig_length);
if (status != PSA_SUCCESS) {
return status;
}

return psa_verify_hash(pubkey_id, alg, hash, sizeof(hash), signature, sig_length);
/* verify on original message with internal hashing operation */
return psa_verify_message(pubkey_id, ECC_ALG, msg, sizeof(msg), signature, sig_length);
}

#ifdef MULTIPLE_SE
Expand All @@ -116,27 +114,21 @@ psa_status_t example_ecdsa_p256_sec_se(void)
psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV1);
psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH;
psa_key_type_t type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
psa_key_bits_t bits = 256;
uint8_t bytes =
PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), bits);

uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(
PSA_ECC_FAMILY_SECP_R1), 256)] = { 0 };

uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(ECC_KEY_TYPE, ECC_KEY_SIZE)] = { 0 };
size_t pubkey_length;

uint8_t signature[PSA_SIGN_OUTPUT_SIZE(type, bits, alg)];
uint8_t signature[PSA_SIGN_OUTPUT_SIZE(ECC_KEY_TYPE, ECC_KEY_SIZE, ECC_ALG)];
size_t sig_length;
uint8_t msg[ECDSA_MESSAGE_SIZE] = { 0x0b };
uint8_t hash[PSA_HASH_LENGTH(PSA_ALG_SHA_256)];
uint8_t hash[PSA_HASH_LENGTH(ECC_ALG_HASH)];
size_t hash_length;

psa_set_key_lifetime(&privkey_attr, lifetime);
psa_set_key_algorithm(&privkey_attr, alg);
psa_set_key_algorithm(&privkey_attr, ECC_ALG);
psa_set_key_usage_flags(&privkey_attr, usage);
psa_set_key_type(&privkey_attr, type);
psa_set_key_bits(&privkey_attr, bits);
psa_set_key_type(&privkey_attr, ECC_KEY_TYPE);
psa_set_key_bits(&privkey_attr, ECC_KEY_SIZE);

psa_status_t status = PSA_ERROR_DOES_NOT_EXIST;

Expand All @@ -150,28 +142,28 @@ psa_status_t example_ecdsa_p256_sec_se(void)
return status;
}

status = psa_hash_compute(PSA_ALG_SHA_256, msg, sizeof(msg), hash, sizeof(hash), &hash_length);
status = psa_hash_compute(ECC_ALG_HASH, msg, sizeof(msg), hash, sizeof(hash), &hash_length);
if (status != PSA_SUCCESS) {
return status;
}

psa_set_key_lifetime(&pubkey_attr, lifetime);
psa_set_key_algorithm(&pubkey_attr, alg);
psa_set_key_algorithm(&pubkey_attr, ECC_ALG);
psa_set_key_usage_flags(&pubkey_attr, PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(bytes));
psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(pubkey_length));
psa_set_key_type(&pubkey_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));

status = psa_import_key(&pubkey_attr, public_key, pubkey_length, &pubkey_id);
if (status != PSA_SUCCESS) {
return status;
}

status = psa_sign_hash(privkey_id, alg, hash, sizeof(hash), signature, sizeof(signature),
status = psa_sign_hash(privkey_id, ECC_ALG, hash, sizeof(hash), signature, sizeof(signature),
&sig_length);
if (status != PSA_SUCCESS) {
return status;
}

return psa_verify_hash(pubkey_id, alg, hash, sizeof(hash), signature, sig_length);
return psa_verify_hash(pubkey_id, ECC_ALG, hash, sizeof(hash), signature, sig_length);
}
#endif
83 changes: 83 additions & 0 deletions examples/psa_crypto/example_eddsa.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2023 TU Dresden
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup examples
* @{
*
* @brief Example functions for EdDSA with PSA Crypto
*
* @author Mikolai Gütschow <mikolai.guetschow@tu-dresden.de>
*
* @}
*/
#include <stdio.h>
#include <stdint.h>

#include "psa/crypto.h"

#define EDDSA_MESSAGE_SIZE (127)

#define ECC_KEY_SIZE (255)
#define ECC_KEY_TYPE (PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS))
#define ECC_ALG (PSA_ALG_PURE_EDDSA)

/**
* @brief Example function to perform an EdDSA operation with the twisted Edwards curve Edwards25519
* with the PSA Crypto API.
*/
psa_status_t example_eddsa(void)
{
psa_key_id_t privkey_id;
psa_key_attributes_t privkey_attr = psa_key_attributes_init();
psa_key_id_t pubkey_id;
psa_key_attributes_t pubkey_attr = psa_key_attributes_init();

psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE;

uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(ECC_KEY_TYPE, ECC_KEY_SIZE)] = { 0 };
size_t pubkey_length;
uint8_t signature[PSA_SIGN_OUTPUT_SIZE(ECC_KEY_TYPE, ECC_KEY_SIZE, ECC_ALG)];
size_t sig_length;
uint8_t msg[EDDSA_MESSAGE_SIZE] = { 0x0b };

psa_set_key_algorithm(&privkey_attr, ECC_ALG);
psa_set_key_usage_flags(&privkey_attr, usage);
psa_set_key_type(&privkey_attr, ECC_KEY_TYPE);
psa_set_key_bits(&privkey_attr, ECC_KEY_SIZE);

psa_status_t status = PSA_ERROR_DOES_NOT_EXIST;

status = psa_generate_key(&privkey_attr, &privkey_id);
if (status != PSA_SUCCESS) {
return status;
}

status = psa_export_public_key(privkey_id, public_key, sizeof(public_key), &pubkey_length);
if (status != PSA_SUCCESS) {
return status;
}

psa_set_key_algorithm(&pubkey_attr, ECC_ALG);
psa_set_key_usage_flags(&pubkey_attr, PSA_KEY_USAGE_VERIFY_MESSAGE);
psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(pubkey_length));
psa_set_key_type(&pubkey_attr, PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(ECC_KEY_TYPE));

status = psa_import_key(&pubkey_attr, public_key, pubkey_length, &pubkey_id);
if (status != PSA_SUCCESS) {
return status;
}

status = psa_sign_message(privkey_id, ECC_ALG, msg, sizeof(msg), signature, sizeof(signature),
&sig_length);
if (status != PSA_SUCCESS) {
return status;
}

return psa_verify_message(pubkey_id, ECC_ALG, msg, sizeof(msg), signature, sig_length);
}
8 changes: 8 additions & 0 deletions examples/psa_crypto/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
extern psa_status_t example_cipher_aes_128(void);
extern psa_status_t example_hmac_sha256(void);
extern psa_status_t example_ecdsa_p256(void);
extern psa_status_t example_eddsa(void);

#ifdef MULTIPLE_SE
extern psa_status_t example_cipher_aes_128_sec_se(void);
Expand Down Expand Up @@ -60,6 +61,13 @@ int main(void)
printf("ECDSA failed: %s\n", psa_status_to_humanly_readable(status));
}

start = ztimer_now(ZTIMER_USEC);
status = example_eddsa();
printf("EdDSA took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start));
if (status != PSA_SUCCESS) {
printf("EdDSA failed: %s\n", psa_status_to_humanly_readable(status));
}

#ifdef MULTIPLE_SE
puts("Running Examples with secondary SE:");
status = example_hmac_sha256_sec_se();
Expand Down
5 changes: 5 additions & 0 deletions kconfigs/Kconfig.features
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ config HAS_PERIPH_ECC_P256R1
help
Indicates that there is ECC P256R1 hardware acceleration peripheral present.

config HAS_PERIPH_ECC_ED25519
bool
help
Indicates that there is ECC Edwards25519 hardware acceleration peripheral present.

config HAS_PERIPH_EEPROM
bool
help
Expand Down
1 change: 1 addition & 0 deletions makefiles/features_modules.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ PERIPH_IGNORE_MODULES := \
periph_cryptocell_310 \
periph_ecc_p192r1 \
periph_ecc_p256r1 \
periph_ecc_ed25519 \
periph_eth \
periph_eth_common \
periph_flash \
Expand Down
Loading

0 comments on commit 5359ac2

Please sign in to comment.