From 6ca35d770bef945019009b73b029cde7d23c5cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag=20Erik=20Gj=C3=B8rvad?= Date: Thu, 19 Dec 2024 15:59:55 +0100 Subject: [PATCH] nrf_security: drivers: cracen: Implement Ed25519 in cracenpsa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for Ed25519 and Ed25519ph in cracenpsa directly using silexpk/sxsymcrypt. This bypasses sicrypto, which saves on flash usage Remove sicrypto implementation of Ed25519 from being accessible from cracenpsa. Signed-off-by: Dag Erik Gjørvad --- .../drivers/cracen/cracenpsa/cracenpsa.cmake | 7 + .../cracen/cracenpsa/include/cracen_psa.h | 14 + .../drivers/cracen/cracenpsa/src/ed25519.c | 290 ++++++++++++++++++ .../cracen/cracenpsa/src/key_management.c | 19 +- .../src/drivers/cracen/cracenpsa/src/sign.c | 243 ++++++--------- 5 files changed, 414 insertions(+), 159 deletions(-) create mode 100644 subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ed25519.c diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/cracenpsa.cmake b/subsys/nrf_security/src/drivers/cracen/cracenpsa/cracenpsa.cmake index d18cc88822d2..a91f1bf27fc9 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/cracenpsa.cmake +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/cracenpsa.cmake @@ -44,6 +44,7 @@ endif() if(CONFIG_PSA_NEED_CRACEN_ASYMMETRIC_SIGNATURE_DRIVER) list(APPEND cracen_driver_sources ${CMAKE_CURRENT_LIST_DIR}/src/sign.c + ${CMAKE_CURRENT_LIST_DIR}/src/ed25519.c ) endif() @@ -90,6 +91,12 @@ if(CONFIG_PSA_NEED_CRACEN_KMU_DRIVER) ) endif() +if(CONFIG_PSA_NEED_CRACEN_KEY_AGREEMENT_DRIVER) + list(APPEND cracen_driver_sources + ${CMAKE_CURRENT_LIST_DIR}/src/ed25519.c + ) +endif() + if(CONFIG_PSA_NEED_CRACEN_KEY_AGREEMENT_DRIVER OR CONFIG_PSA_NEED_CRACEN_KEY_DERIVATION_DRIVER) list(APPEND cracen_driver_sources ${CMAKE_CURRENT_LIST_DIR}/src/key_derivation.c diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa.h b/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa.h index a5389c878853..61b3b5ff8bd4 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa.h +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa.h @@ -361,4 +361,18 @@ psa_status_t cracen_spake2p_get_shared_key(cracen_spake2p_operation_t *operation psa_status_t cracen_spake2p_abort(cracen_spake2p_operation_t *operation); +int cracen_ed25519_sign(const uint8_t *priv_key, char *signature, const uint8_t *message, + size_t message_length); + +int cracen_ed25519_verify(const uint8_t *pub_key, const char *message, size_t message_length, + const char *signature); + +int cracen_ed25519ph_sign(const uint8_t *priv_key, char *signature, const uint8_t *message, + size_t message_length, bool is_message); + +int cracen_ed25519ph_verify(const uint8_t *pub_key, const char *message, size_t message_length, + const char *signature, bool is_message); + +int cracen_ed25519_create_pubkey(const uint8_t *priv_key, uint8_t *pub_key); + #endif /* CRACEN_PSA_H */ diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ed25519.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ed25519.c new file mode 100644 index 000000000000..d3fd7c0b789a --- /dev/null +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ed25519.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + * + * The comments in this file use the notations and conventions from RFC 8032. + * + * Workmem layout for an Ed25519 signature verification task: + * 1. digest (size: 64 bytes). + * + * Workmem layout for an Ed25519 signature generation task: + * The workmem is made of 5 areas of 32 bytes each (total size 160 bytes). + * In the following we refer to these areas using the numbers 1 to 5. The + * first hash operation computes the private key's digest, which is stored + * in areas 1 and 2. The second hash operation computes r, which is stored + * in areas 4 and 5. The first point multiplication computes R, which is + * written directly to the output buffer. Then the secret scalar s is + * computed in place in area 1. Area 2 is cleared. The second point + * multiplication computes the public key A, which is stored in area 2. The + * third hash operation computes k, which is stored in areas 2 and 3. The + * final operation (r + k * s) mod L computes S, which is written directly + * to the output buffer. + * + * Workmem layout for an Ed25519 public key generation task: + * 1. digest (size: 64 bytes). The digest of the private key is written in + * this area. Then the secret scalar s is computed in place in the first + * 32 bytes of this area. + */ +#include +#include +#include +#include +#include +#include +#include + +#define AREA2_MEM_OFFSET 32 +#define AREA4_MEM_OFFSET 96 + +/* This is the ASCII string with the + * PHflag 1 and context size 0 appended as defined in: + * https://datatracker.ietf.org/doc/html/rfc8032.html#section-2. + * It is used for domain separation between Ed25519 and Ed25519ph. + * This can not be stored as a const due to hardware limitations + */ +static char dom2[] = {0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x6e, + 0x6f, 0x20, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x63, 0x6f, + 0x6c, 0x6c, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x01, 0x00}; + +static int hash_all_inputs(char const *inputs[], size_t inputs_lengths[], size_t input_count, + const struct sxhashalg *hashalg, char *out) +{ + struct sxhash hashopctx; + int status; + + status = sx_hash_create(&hashopctx, hashalg, sizeof(hashopctx)); + if (status != SX_OK) { + return status; + } + + for (size_t i = 0; i < input_count; i++) { + status = sx_hash_feed(&hashopctx, inputs[i], inputs_lengths[i]); + if (status != SX_OK) { + return status; + } + } + status = sx_hash_digest(&hashopctx, out); + if (status != SX_OK) { + return status; + } + + status = sx_hash_wait(&hashopctx); + + return status; +} + +static int hash_input(const char *input, size_t input_length, char *digest) +{ + char const *hash_array[] = {input}; + size_t hash_array_lengths[] = {input_length}; + + return hash_all_inputs(hash_array, hash_array_lengths, 1, &sxhashalg_sha2_512, digest); +} + +static int ed25519_calculate_r(char *workmem, const uint8_t *message, size_t message_length, + bool prehash) +{ + char const *hash_array[] = {dom2, workmem, message}; + size_t hash_array_lengths[] = {sizeof(dom2), SX_ED25519_SZ, message_length}; + size_t offset = prehash ? 0 : 1; + size_t input_count = 3 - offset; + + return hash_all_inputs(&hash_array[offset], &hash_array_lengths[offset], input_count, + &sxhashalg_sha2_512, workmem + SX_ED25519_DGST_SZ); +} + +static int ed25519_calculate_k(char *workmem, char *point_r, const char *message, + size_t message_length, bool prehash) +{ + char const *hash_array[] = {dom2, point_r, workmem, message}; + size_t hash_array_lengths[] = {sizeof(dom2), SX_ED25519_SZ, SX_ED25519_SZ, message_length}; + size_t offset = prehash ? 0 : 1; + size_t input_count = 4 - offset; + + return hash_all_inputs(&hash_array[offset], &hash_array_lengths[offset], input_count, + &sxhashalg_sha2_512, workmem); +} + +static int ed25519_sign_internal(const uint8_t *priv_key, char *signature, const uint8_t *message, + size_t message_length, bool prehash) +{ + int status; + char workmem[5 * SX_ED25519_SZ]; + uint8_t pnt_r[SX_ED25519_DGST_SZ]; + char *area_1 = workmem; + char *area_2 = workmem + AREA2_MEM_OFFSET; + char *area_4 = workmem + AREA4_MEM_OFFSET; + + /* Hash the private key, the digest is stored in the first 64 bytes of workmem*/ + status = hash_input(priv_key, SX_ED25519_SZ, area_1); + if (status != SX_OK) { + return status; + } + + /* Obtain r by hashing (prefix || message), where prefix is the second + * half of the private key digest. + */ + status = ed25519_calculate_r(area_2, message, message_length, prehash); + if (status != SX_OK) { + return status; + } + + /* Perform point multiplication R = [r]B. This is the encoded point R, + * which is the first part of the signature. + */ + status = sx_ed25519_ptmult((const struct sx_ed25519_dgst *)area_4, + (struct sx_ed25519_pt *)pnt_r); + if (status != SX_OK) { + return status; + } + + /* The secret scalar s is computed in place from the first half of the + * private key digest. + */ + decode_scalar_25519(area_1); + + /* Clear second half of private key digest: sx_ed25519_ptmult() + * works on an input of SX_ED25519_DGST_SZ bytes. + */ + safe_memset(area_2, sizeof(workmem) - SX_ED25519_SZ, 0, SX_ED25519_SZ); + /* Perform point multiplication A = [s]B, + * to obtain the public key A. which is stored in workmem[32:63] + */ + status = sx_ed25519_ptmult((const struct sx_ed25519_dgst *)area_1, + (struct sx_ed25519_pt *)area_2); + + if (status != SX_OK) { + return status; + } + + status = ed25519_calculate_k(area_2, pnt_r, message, message_length, prehash); + if (status != SX_OK) { + return status; + } + + /* Compute (r + k * s) mod L. This gives the second part of the + * signature, which is the encoded S which is stored in pnt_r. + */ + status = sx_ed25519_sign((const struct sx_ed25519_dgst *)area_2, + (const struct sx_ed25519_dgst *)area_4, + (const struct sx_ed25519_v *)area_1, + (struct sx_ed25519_v *)(pnt_r + SX_ED25519_PT_SZ)); + if (status != SX_OK) { + return status; + } + + memcpy(signature, pnt_r, SX_ED25519_DGST_SZ); + safe_memzero(workmem, sizeof(workmem)); + + return status; +} + +int cracen_ed25519_sign(const uint8_t *priv_key, char *signature, const uint8_t *message, + size_t message_length) +{ + return ed25519_sign_internal(priv_key, signature, message, message_length, false); +} + +int cracen_ed25519ph_sign(const uint8_t *priv_key, char *signature, const uint8_t *message, + size_t message_length, bool is_message) +{ + char hashedmessage[SX_ED25519_DGST_SZ]; + int status; + + if (is_message) { + status = hash_input(message, message_length, hashedmessage); + if (status != SX_OK) { + return status; + } + + return ed25519_sign_internal(priv_key, signature, hashedmessage, SX_ED25519_DGST_SZ, + true); + } else { + return ed25519_sign_internal(priv_key, signature, message, message_length, true); + } +} + +static int ed25519_verify_internal(const uint8_t *pub_key, const char *message, + size_t message_length, const char *signature, bool prehash) +{ + int status; + char digest[SX_ED25519_DGST_SZ]; + size_t ed25519_sz = SX_ED25519_SZ; + size_t offset = prehash ? 0 : 1; + size_t input_count = 4 - offset; + + char const *hash_array[] = {dom2, signature, (const char *)pub_key, message}; + size_t hash_array_lengths[] = {sizeof(dom2), ed25519_sz, ed25519_sz, message_length}; + + status = hash_all_inputs(&hash_array[offset], &hash_array_lengths[offset], input_count, + &sxhashalg_sha2_512, digest); + if (status != SX_OK) { + return status; + } + + status = + sx_ed25519_verify((struct sx_ed25519_dgst *)digest, (struct sx_ed25519_pt *)pub_key, + (const struct sx_ed25519_v *)(signature + SX_ED25519_SZ), + (const struct sx_ed25519_pt *)signature); + + return status; +} + +int cracen_ed25519_verify(const uint8_t *pub_key, const char *message, size_t message_length, + const char *signature) +{ + return ed25519_verify_internal(pub_key, message, message_length, signature, false); +} + +int cracen_ed25519ph_verify(const uint8_t *pub_key, const char *message, size_t message_length, + const char *signature, bool is_message) +{ + int status; + char message_digest[SX_ED25519_DGST_SZ]; + + if (is_message) { + status = hash_input(message, message_length, message_digest); + if (status != SX_OK) { + return status; + } + + return ed25519_verify_internal(pub_key, message_digest, SX_ED25519_DGST_SZ, + signature, true); + } + return ed25519_verify_internal(pub_key, message, message_length, signature, true); +} + +int cracen_ed25519_create_pubkey(const uint8_t *priv_key, uint8_t *pub_key) +{ + int status; + char digest[SX_ED25519_DGST_SZ]; + char *pub_key_A = digest + SX_ED25519_SZ; + + status = hash_input(priv_key, SX_ED25519_SZ, digest); + if (status != SX_OK) { + return status; + } + /* The secret scalar s is computed in place from the first half of the + * private key digest. + */ + decode_scalar_25519(digest); + + /* Clear second half of private key digest: ed25519_ptmult() + * works on an input of SX_ED25519_DGST_SZ bytes. + */ + safe_memset(pub_key_A, SX_ED25519_SZ, 0, SX_ED25519_SZ); + + /* Perform point multiplication A = [s]B, to obtain the public key A. */ + status = sx_ed25519_ptmult((const struct sx_ed25519_dgst *)digest, + (struct sx_ed25519_pt *)pub_key_A); + + if (status != SX_OK) { + return status; + } + + memcpy(pub_key, pub_key_A, SX_ED25519_SZ); + safe_memzero(digest, SX_ED25519_DGST_SZ); + + return status; +} diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c index 8eada3f22b00..dcdf5ea8c440 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c @@ -10,12 +10,9 @@ #include "cracen_psa.h" #include "platform_keys/platform_keys.h" #include - #include #include #include -#include -#include #include #include #include @@ -603,10 +600,9 @@ static psa_status_t export_ecc_public_key_from_keypair(const psa_key_attributes_ psa_status_t psa_status; size_t expected_pub_key_size = 0; int si_status = 0; - psa_algorithm_t key_alg = psa_get_key_algorithm(attributes); const struct sx_pk_ecurve *sx_curve; - struct sitask t; + struct sitask t; switch (psa_curve) { case PSA_ECC_FAMILY_BRAINPOOL_P_R1: case PSA_ECC_FAMILY_SECP_R1: @@ -631,7 +627,6 @@ static psa_status_t export_ecc_public_key_from_keypair(const psa_key_attributes_ struct si_sig_privkey priv_key; struct si_sig_pubkey pub_key; - char workmem[SX_ED448_DGST_SZ] = {}; if (PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes)) == @@ -675,15 +670,11 @@ static psa_status_t export_ecc_public_key_from_keypair(const psa_key_attributes_ break; case PSA_ECC_FAMILY_TWISTED_EDWARDS: if (key_bits_attr == 255) { - if (key_alg == PSA_ALG_ED25519PH) { - priv_key.def = si_sig_def_ed25519ph; - priv_key.key.ed25519 = (struct sx_ed25519_v *)key_buffer; - pub_key.key.ed25519 = (struct sx_ed25519_pt *)data; - } else { - priv_key.def = si_sig_def_ed25519; - priv_key.key.ed25519 = (struct sx_ed25519_v *)key_buffer; - pub_key.key.ed25519 = (struct sx_ed25519_pt *)data; + si_status = cracen_ed25519_create_pubkey(key_buffer, data); + if (si_status == SX_OK) { + *data_length = expected_pub_key_size; } + return silex_statuscodes_to_psa(si_status); } else { priv_key.def = si_sig_def_ed448; priv_key.key.ed448 = (struct sx_ed448_v *)key_buffer; diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/sign.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/sign.c index d2686b77fcce..78dce3270a51 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/sign.c +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/sign.c @@ -12,8 +12,6 @@ #include #include #include -#include -#include #include #include #include @@ -31,7 +29,6 @@ #include "common.h" #include "cracen_psa.h" - #define SI_IS_MESSAGE (1) #define SI_IS_HASH (0) #define SI_EXTRACT_PUBKEY (1) @@ -88,7 +85,7 @@ static int cracen_signature_prepare_ec_prvkey(struct si_sig_privkey *privkey, ch size_t key_buffer_size, const struct sx_pk_ecurve **sicurve, psa_algorithm_t alg, - const psa_key_attributes_t *attributes, int message, + const psa_key_attributes_t *attributes, bool is_message, size_t digestsz) { int status; @@ -120,27 +117,6 @@ static int cracen_signature_prepare_ec_prvkey(struct si_sig_privkey *privkey, ch return SX_ERR_INVALID_ARG; } - if (IS_ENABLED(PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS)) { - if (alg == PSA_ALG_PURE_EDDSA) { - privkey->def = si_sig_def_ed25519; - privkey->key.ed25519 = (struct sx_ed25519_v *)key_buffer; - return SX_OK; - } - } - - if (IS_ENABLED(PSA_NEED_CRACEN_ED25519PH)) { - if (alg == PSA_ALG_ED25519PH) { - privkey->def = si_sig_def_ed25519ph; - privkey->key.ed25519 = (struct sx_ed25519_v *)key_buffer; - if (message) { - return cracen_signature_set_hashalgo(&privkey->hashalg, alg); - } else { - return cracen_signature_set_hashalgo_from_digestsz( - &privkey->hashalg, alg, digestsz); - } - } - } - if (IS_ENABLED(PSA_NEED_CRACEN_ECDSA_SECP_R1) || IS_ENABLED(PSA_NEED_CRACEN_ECDSA_SECP_K1) || IS_ENABLED(PSA_NEED_CRACEN_ECDSA_BRAINPOOL_P_R1)) { @@ -150,7 +126,7 @@ static int cracen_signature_prepare_ec_prvkey(struct si_sig_privkey *privkey, ch : si_sig_def_ecdsa; privkey->key.eckey.curve = *sicurve; privkey->key.eckey.d = key_buffer; - if (message) { + if (is_message) { return cracen_signature_set_hashalgo(&privkey->hashalg, alg); } else { return cracen_signature_set_hashalgo_from_digestsz( @@ -163,7 +139,7 @@ static int cracen_signature_prepare_ec_prvkey(struct si_sig_privkey *privkey, ch } static int cracen_prepare_ecdsa_ec_pubkey(struct si_sig_pubkey *pubkey, - const struct sx_pk_ecurve *sicurve, int message, + const struct sx_pk_ecurve *sicurve, bool is_message, psa_algorithm_t alg, size_t digestsz, size_t curvesz, char *key_buffer) { @@ -173,7 +149,7 @@ static int cracen_prepare_ecdsa_ec_pubkey(struct si_sig_pubkey *pubkey, pubkey->def = si_sig_def_ecdsa; pubkey->key.eckey.curve = sicurve; - if (message) { + if (is_message) { status = cracen_signature_set_hashalgo(&pubkey->hashalg, alg); } else { status = cracen_signature_set_hashalgo_from_digestsz(&pubkey->hashalg, alg, @@ -194,7 +170,7 @@ static int cracen_signature_prepare_ec_pubkey(struct sitask *t, struct si_sig_pu char *key_buffer, size_t key_buffer_size, const struct sx_pk_ecurve **sicurve, psa_algorithm_t alg, - const psa_key_attributes_t *attributes, int message, + const psa_key_attributes_t *attributes, bool is_message, size_t digestsz, char *pubkey_buffer) { size_t curvesz = PSA_BITS_TO_BYTES(psa_get_key_bits(attributes)); @@ -210,37 +186,14 @@ static int cracen_signature_prepare_ec_pubkey(struct sitask *t, struct si_sig_pu status = SX_ERR_INCOMPATIBLE_HW; if (IS_ENABLED(PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS)) { - if (alg == PSA_ALG_PURE_EDDSA) { - pubkey->def = si_sig_def_ed25519; - + if (alg == PSA_ALG_PURE_EDDSA || alg == PSA_ALG_ED25519PH) { if (PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(psa_get_key_type(attributes))) { - pubkey->key.ed25519 = (struct sx_ed25519_pt *)key_buffer; + memcpy(pubkey_buffer, key_buffer, key_buffer_size); return SX_OK; } - if (curvesz != key_buffer_size) { - return SX_ERR_INVALID_KEY_SZ; - } - pubkey->key.ed25519 = (struct sx_ed25519_pt *)pubkey_buffer; - } - } - - if (IS_ENABLED(PSA_NEED_CRACEN_ED25519PH) && alg == PSA_ALG_ED25519PH) { - pubkey->def = si_sig_def_ed25519ph; - if (PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(psa_get_key_type(attributes))) { - pubkey->key.ed25519 = (struct sx_ed25519_pt *)key_buffer; - if (message) { - cracen_signature_set_hashalgo(&pubkey->hashalg, - alg); - } else { - cracen_signature_set_hashalgo_from_digestsz(&pubkey->hashalg, - alg, digestsz); - } - return SX_OK; - } - if (curvesz != key_buffer_size) { - return SX_ERR_INVALID_KEY_SZ; + status = cracen_ed25519_create_pubkey(key_buffer, pubkey_buffer); + return status; } - pubkey->key.ed25519 = (struct sx_ed25519_pt *)pubkey_buffer; } if (IS_ENABLED(PSA_NEED_CRACEN_ECDSA_SECP_R1) || @@ -259,11 +212,11 @@ static int cracen_signature_prepare_ec_pubkey(struct sitask *t, struct si_sig_pu } /* key_buffer + 1 to skip the 0x4 flag in the first byte */ - status = cracen_prepare_ecdsa_ec_pubkey(pubkey, *sicurve, message, + status = cracen_prepare_ecdsa_ec_pubkey(pubkey, *sicurve, is_message, alg, digestsz, curvesz, key_buffer + 1); } else { - status = cracen_prepare_ecdsa_ec_pubkey(pubkey, *sicurve, message, + status = cracen_prepare_ecdsa_ec_pubkey(pubkey, *sicurve, is_message, alg, digestsz, curvesz, pubkey_buffer); } @@ -278,7 +231,7 @@ static int cracen_signature_prepare_ec_pubkey(struct sitask *t, struct si_sig_pu struct si_sig_privkey m_privkey; status = cracen_signature_prepare_ec_prvkey(&m_privkey, key_buffer, key_buffer_size, - sicurve, alg, attributes, message, + sicurve, alg, attributes, is_message, digestsz); if (status != SX_OK) { return status; @@ -292,89 +245,95 @@ static int cracen_signature_prepare_ec_pubkey(struct sitask *t, struct si_sig_pu return status; } -static psa_status_t cracen_signature_ecc_sign(int message, const psa_key_attributes_t *attributes, +static psa_status_t cracen_signature_ecc_sign(bool is_message, const psa_key_attributes_t *attributes, const uint8_t *key_buffer, size_t key_buffer_size, psa_algorithm_t alg, const uint8_t *input, size_t input_length, uint8_t *signature, size_t signature_size, size_t *signature_length) { int si_status; + psa_status_t psa_status; const struct sx_pk_ecurve *curve; - struct si_sig_privkey privkey = {0}; - struct si_sig_signature sign = {0}; - struct sitask t; - /* Workmem for ecc sign task is 4 * digestsz + hmac block size + curve size */ - char workmem[4 * PSA_HASH_MAX_SIZE + PSA_HMAC_MAX_HASH_BLOCK_SIZE + - PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)]; - si_task_init(&t, workmem, sizeof(workmem)); + psa_status = cracen_ecc_get_ecurve_from_psa( + PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)), + psa_get_key_bits(attributes), &curve); + if (psa_status != PSA_SUCCESS) { + return psa_status; + } + + if ((int)signature_size < 2 * curve->sz) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } if (!PSA_KEY_TYPE_IS_ECC_KEY_PAIR(psa_get_key_type(attributes))) { - return silex_statuscodes_to_psa(SX_ERR_INCOMPATIBLE_HW); + return PSA_ERROR_NOT_SUPPORTED; } if (!PSA_ALG_IS_ECDSA(alg) && alg != PSA_ALG_PURE_EDDSA && alg != PSA_ALG_ED25519PH) { return PSA_ERROR_INVALID_ARGUMENT; } - if (((message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_SIGN_MESSAGE, attributes))) || - ((!message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_SIGN_HASH, attributes)))) { + if (((is_message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_SIGN_MESSAGE, attributes))) || + ((!is_message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_SIGN_HASH, attributes)))) { return PSA_ERROR_INVALID_ARGUMENT; } + if (alg == PSA_ALG_ED25519PH) { + si_status = cracen_ed25519ph_sign(key_buffer, signature, input, + input_length, is_message); + if (si_status == SX_OK) { + *signature_length = 2 * curve->sz; + } + return silex_statuscodes_to_psa(si_status); + } else if (alg == PSA_ALG_PURE_EDDSA) { + if (psa_get_key_bits(attributes) == 255) { + si_status = cracen_ed25519_sign(key_buffer, signature, input, input_length); + if (si_status == SX_OK) { + *signature_length = 2 * curve->sz; + } + return silex_statuscodes_to_psa(si_status); + } else { + return PSA_ERROR_NOT_SUPPORTED; + } + } - si_status = - cracen_signature_prepare_ec_prvkey(&privkey, (char *)key_buffer, key_buffer_size, - &curve, alg, attributes, message, input_length); + struct si_sig_privkey privkey = {0}; + struct si_sig_signature sign = {0}; + struct sitask t; + /* Workmem for ecc sign task is 4 * digestsz + hmac block size + curve size */ + char workmem[4 * PSA_HASH_MAX_SIZE + PSA_HMAC_MAX_HASH_BLOCK_SIZE + + PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)]; + si_task_init(&t, workmem, sizeof(workmem)); + si_status = cracen_signature_prepare_ec_prvkey(&privkey, (char *)key_buffer, + key_buffer_size, &curve, alg, + attributes, is_message, input_length); if (si_status) { return silex_statuscodes_to_psa(si_status); } - if ((int)signature_size < 2 * curve->sz) { - return silex_statuscodes_to_psa(SX_ERR_OUTPUT_BUFFER_TOO_SMALL); - } - *signature_length = 2 * curve->sz; sign.sz = *signature_length; sign.r = (char *)signature; sign.s = (char *)signature + *signature_length / 2; - /* Ed25519ph requires prehashing and supports sign and verify message - * the message is therefore hashed here before si_sig_verify is called - */ - if (alg == PSA_ALG_ED25519PH && message) { - uint8_t status; - uint8_t hash[64]; - size_t output_len; - - status = psa_hash_compute(PSA_ALG_SHA_512, - input, input_length, hash, - sizeof(hash), &output_len); - if (status != PSA_SUCCESS) { - return status; - } - + if (is_message) { si_sig_create_sign(&t, &privkey, &sign); - si_task_consume(&t, (char *)hash, sizeof(hash)); } else { - if (message) { - si_sig_create_sign(&t, &privkey, &sign); - } else { - si_sig_create_sign_digest(&t, &privkey, &sign); + si_sig_create_sign_digest(&t, &privkey, &sign); + } - } - si_task_consume(&t, (char *)input, - message ? input_length : sx_hash_get_alg_digestsz(privkey.hashalg)); + si_task_consume(&t, (char *)input, + is_message ? input_length : sx_hash_get_alg_digestsz(privkey.hashalg)); - } si_task_run(&t); si_status = si_task_wait(&t); safe_memzero(workmem, sizeof(workmem)); - return silex_statuscodes_to_psa(si_status); } -static psa_status_t cracen_signature_ecc_verify(int message, const psa_key_attributes_t *attributes, +static psa_status_t cracen_signature_ecc_verify(bool is_message, + const psa_key_attributes_t *attributes, const uint8_t *key_buffer, size_t key_buffer_size, psa_algorithm_t alg, const uint8_t *input, size_t input_length, const uint8_t *signature, @@ -392,69 +351,62 @@ static psa_status_t cracen_signature_ecc_verify(int message, const psa_key_attri if (!PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(psa_get_key_type(attributes)) && !PSA_KEY_TYPE_IS_ECC_KEY_PAIR(psa_get_key_type(attributes))) { - return silex_statuscodes_to_psa(SX_ERR_INCOMPATIBLE_HW); + return PSA_ERROR_NOT_SUPPORTED; } if (!PSA_ALG_IS_ECDSA(alg) && alg != PSA_ALG_PURE_EDDSA && !PSA_ALG_IS_HASH_EDDSA(alg)) { return PSA_ERROR_NOT_SUPPORTED; } - if (((message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_VERIFY_MESSAGE, attributes))) || - ((!message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_VERIFY_HASH, attributes)))) { + if (((is_message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_VERIFY_MESSAGE, attributes))) || + ((!is_message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_VERIFY_HASH, attributes)))) { return PSA_ERROR_INVALID_ARGUMENT; } si_task_init(&t, workmem, sizeof(workmem)); - si_status = cracen_signature_prepare_ec_pubkey(&t, &pubkey, (char *)key_buffer, key_buffer_size, &curve, alg, attributes, - message, input_length, pubkey_buffer); + is_message, input_length, pubkey_buffer); if (si_status) { return silex_statuscodes_to_psa(si_status); } if ((int)signature_length != 2 * curve->sz) { - return silex_statuscodes_to_psa(SX_ERR_INVALID_SIGNATURE); + return PSA_ERROR_INVALID_SIGNATURE; + } + + if (alg == PSA_ALG_ED25519PH) { + si_status = cracen_ed25519ph_verify(pubkey_buffer, (char *)input, input_length, + signature, is_message); + return silex_statuscodes_to_psa(si_status); + } else if (alg == PSA_ALG_PURE_EDDSA) { + si_status = cracen_ed25519_verify(pubkey_buffer, (char *)input, input_length, + signature); + return silex_statuscodes_to_psa(si_status); } + sign.sz = signature_length; sign.r = (char *)signature; sign.s = (char *)signature + signature_length / 2; - /* Ed25519ph requires prehashing and supports sign and verify message - * the message is therefore hashed here before si_sig_verify is called - */ - if (alg == PSA_ALG_ED25519PH && message) { - psa_status_t status; - uint8_t hash[64]; - size_t output_len; - - status = psa_hash_compute(PSA_ALG_SHA_512, - input, input_length, hash, - sizeof(hash), &output_len); - if (status != PSA_SUCCESS) { - return status; - } + if (is_message) { si_sig_create_verify(&t, &pubkey, &sign); - si_task_consume(&t, (char *)hash, sizeof(hash)); } else { - if (message) { - si_sig_create_verify(&t, &pubkey, &sign); - } else { - if (sx_hash_get_alg_digestsz(pubkey.hashalg) != input_length) { - return PSA_ERROR_INVALID_ARGUMENT; - } - si_sig_create_verify_digest(&t, &pubkey, &sign); + if (sx_hash_get_alg_digestsz(pubkey.hashalg) != input_length) { + return PSA_ERROR_INVALID_ARGUMENT; } - - si_task_consume(&t, (char *)input, input_length); + si_sig_create_verify_digest(&t, &pubkey, &sign); } + si_task_consume(&t, (char *)input, input_length); si_task_run(&t); si_status = si_task_wait(&t); + safe_memzero(workmem, sizeof(workmem)); + return silex_statuscodes_to_psa(si_status); } -static psa_status_t cracen_signature_rsa_sign(int message, const psa_key_attributes_t *attributes, +static psa_status_t cracen_signature_rsa_sign(bool is_message, const psa_key_attributes_t *attributes, const uint8_t *key_buffer, size_t key_buffer_size, psa_algorithm_t alg, const uint8_t *input, size_t input_length, uint8_t *signature, @@ -478,12 +430,12 @@ static psa_status_t cracen_signature_rsa_sign(int message, const psa_key_attribu return PSA_ERROR_NOT_SUPPORTED; } - if (((message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_SIGN_MESSAGE, attributes))) || - ((!message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_SIGN_HASH, attributes)))) { + if (((is_message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_SIGN_MESSAGE, attributes))) || + ((!is_message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_SIGN_HASH, attributes)))) { return PSA_ERROR_INVALID_ARGUMENT; } - if (message) { + if (is_message) { si_status = cracen_signature_set_hashalgo(&privkey.hashalg, alg); } else { si_status = cracen_signature_set_hashalgo_from_digestsz(&privkey.hashalg, alg, @@ -512,10 +464,10 @@ static psa_status_t cracen_signature_rsa_sign(int message, const psa_key_attribu sign.r = (char *)signature; if ((size_t)signature_size < sign.sz) { - return silex_statuscodes_to_psa(SX_ERR_OUTPUT_BUFFER_TOO_SMALL); + return PSA_ERROR_BUFFER_TOO_SMALL; } - if (message) { + if (is_message) { si_sig_create_sign(&t, &privkey, &sign); si_task_consume(&t, (char *)input, input_length); } else { @@ -537,7 +489,8 @@ static psa_status_t cracen_signature_rsa_sign(int message, const psa_key_attribu #endif /* PSA_MAX_RSA_KEY_BITS > 0 */ } -static psa_status_t cracen_signature_rsa_verify(int message, const psa_key_attributes_t *attributes, +static psa_status_t cracen_signature_rsa_verify(bool is_message, + const psa_key_attributes_t *attributes, const uint8_t *key_buffer, size_t key_buffer_size, psa_algorithm_t alg, const uint8_t *input, size_t input_length, const uint8_t *signature, @@ -560,12 +513,12 @@ static psa_status_t cracen_signature_rsa_verify(int message, const psa_key_attri if (alg == PSA_ALG_RSA_PKCS1V15_SIGN_RAW || key_bits_attr < 2048) { return PSA_ERROR_NOT_SUPPORTED; } - if (((message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_VERIFY_MESSAGE, attributes))) || - ((!message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_VERIFY_HASH, attributes)))) { + if (((is_message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_VERIFY_MESSAGE, attributes))) || + ((!is_message) && (!SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_VERIFY_HASH, attributes)))) { return PSA_ERROR_INVALID_ARGUMENT; } - if (message) { + if (is_message) { si_status = cracen_signature_set_hashalgo(&pubkey.hashalg, alg); } else { si_status = cracen_signature_set_hashalgo_from_digestsz(&pubkey.hashalg, alg, @@ -594,12 +547,12 @@ static psa_status_t cracen_signature_rsa_verify(int message, const psa_key_attri if ((size_t)signature_length != PSA_SIGN_OUTPUT_SIZE(PSA_KEY_TYPE_RSA_KEY_PAIR, key_bits_attr, alg)) { - return silex_statuscodes_to_psa(SX_ERR_INVALID_SIGNATURE); + return PSA_ERROR_INVALID_SIGNATURE; } sign.sz = signature_length; sign.r = (char *)signature; - if (message) { + if (is_message) { si_sig_create_verify(&t, &pubkey, &sign); si_task_consume(&t, (char *)input, input_length); } else {