From f3dee551836a89aa5e9639a73343d13d75435b71 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 ECDSA in cracenpsa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for ECDSA in cracenpsa Directly using silexpk/sxsymcrypt This bypasses sicrypto, which saves on flash usage Adding support for hmac without sicrypto. Remove sicrypto implementation of ECDSA being accessible from cracenpsa. Various refactors to support this Signed-off-by: Dag Erik Gjørvad --- .../drivers/cracen/cracenpsa/cracenpsa.cmake | 8 + .../cracen/cracenpsa/include/cracen_psa.h | 14 - .../cracenpsa/include/cracen_psa_ecdsa.h | 32 + .../cracenpsa/include/cracen_psa_eddsa.h | 21 + .../cracenpsa/include/cracen_psa_primitives.h | 23 + .../src/drivers/cracen/cracenpsa/src/common.c | 82 +++ .../src/drivers/cracen/cracenpsa/src/common.h | 99 ++++ .../src/drivers/cracen/cracenpsa/src/ecc.c | 89 +++ .../src/drivers/cracen/cracenpsa/src/ecc.h | 10 + .../src/drivers/cracen/cracenpsa/src/ecdsa.c | 554 ++++++++++++++++++ .../drivers/cracen/cracenpsa/src/ed25519.c | 56 +- .../src/drivers/cracen/cracenpsa/src/hmac.c | 119 ++++ .../src/drivers/cracen/cracenpsa/src/hmac.h | 12 + .../cracen/cracenpsa/src/key_management.c | 66 +-- .../drivers/cracen/cracenpsa/src/rndinrange.c | 108 ++++ .../src/drivers/cracen/cracenpsa/src/sign.c | 354 +++++------ .../src/drivers/cracen/sicrypto/src/ecdsa.c | 21 +- .../src/drivers/cracen/sicrypto/src/hmac.c | 3 +- .../src/drivers/cracen/sicrypto/src/iksig.c | 5 + .../cracen/sxsymcrypt/sxsymcrypt.cmake | 1 + 20 files changed, 1395 insertions(+), 282 deletions(-) create mode 100644 subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa_ecdsa.h create mode 100644 subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa_eddsa.h create mode 100644 subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ecc.c create mode 100644 subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ecc.h create mode 100644 subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ecdsa.c create mode 100644 subsys/nrf_security/src/drivers/cracen/cracenpsa/src/hmac.c create mode 100644 subsys/nrf_security/src/drivers/cracen/cracenpsa/src/hmac.h create mode 100644 subsys/nrf_security/src/drivers/cracen/cracenpsa/src/rndinrange.c diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/cracenpsa.cmake b/subsys/nrf_security/src/drivers/cracen/cracenpsa/cracenpsa.cmake index a478b905212c..fd8ac7629304 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/cracenpsa.cmake +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/cracenpsa.cmake @@ -15,6 +15,8 @@ list(APPEND cracen_driver_sources ${CMAKE_CURRENT_LIST_DIR}/src/common.c ${CMAKE_CURRENT_LIST_DIR}/src/mem_helpers.c ${CMAKE_CURRENT_LIST_DIR}/src/ec_helpers.c + ${CMAKE_CURRENT_LIST_DIR}/src/ecc.c + ${CMAKE_CURRENT_LIST_DIR}/src/rndinrange.c # Note: We always need to have blkcipher.c and ctr_drbg.c since it # is used directly by many Cracen drivers. @@ -44,7 +46,10 @@ 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/ecdsa.c + ${CMAKE_CURRENT_LIST_DIR}/src/ecc.c ${CMAKE_CURRENT_LIST_DIR}/src/ed25519.c + ${CMAKE_CURRENT_LIST_DIR}/src/hmac.c ) endif() @@ -62,8 +67,11 @@ endif() if(CONFIG_PSA_NEED_CRACEN_KEY_MANAGEMENT_DRIVER OR CONFIG_PSA_NEED_CRACEN_KMU_DRIVER OR CONFIG_MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) list(APPEND cracen_driver_sources + ${CMAKE_CURRENT_LIST_DIR}/src/ed25519.c ${CMAKE_CURRENT_LIST_DIR}/src/key_management.c ${CMAKE_CURRENT_LIST_DIR}/src/ed25519.c + ${CMAKE_CURRENT_LIST_DIR}/src/ecdsa.c + ${CMAKE_CURRENT_LIST_DIR}/src/ecc.c ) endif() 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 61b3b5ff8bd4..a5389c878853 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,18 +361,4 @@ 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/include/cracen_psa_ecdsa.h b/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa_ecdsa.h new file mode 100644 index 000000000000..a0861cdaea80 --- /dev/null +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa_ecdsa.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#include + +int cracen_ecdsa_verify_message(const char *pubkey, const struct sxhashalg *hashalg, + const uint8_t *message, size_t message_length, + const struct sx_pk_ecurve *curve, const uint8_t *signature); + +int cracen_ecdsa_verify_digest(const char *pubkey, const uint8_t *digest, size_t digestsz, + const struct sx_pk_ecurve *curve, const uint8_t *signature); + +int cracen_ecdsa_sign_message(const struct ecc_priv_key *privkey, const struct sxhashalg *hashalg, + const struct sx_pk_ecurve *curve, const uint8_t *message, + size_t message_length, const uint8_t *signature); + +int cracen_ecdsa_sign_digest(const struct ecc_priv_key *privkey, const struct sxhashalg *hashalg, + const struct sx_pk_ecurve *curve, const uint8_t *digest, + size_t digest_length, const uint8_t *signature); + +int cracen_ecdsa_sign_message_deterministic(const struct ecc_priv_key *privkey, + const struct sxhashalg *hashalg, + const struct sx_pk_ecurve *curve, + const uint8_t *message, size_t message_length, + const uint8_t *signature); + +int cracen_ecdsa_sign_digest_deterministic(const struct ecc_priv_key *privkey, + const struct sxhashalg *hashalg, + const struct sx_pk_ecurve *curve, const uint8_t *digest, + size_t digestsz, const uint8_t *signature); diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa_eddsa.h b/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa_eddsa.h new file mode 100644 index 000000000000..3fa0d1b31b1d --- /dev/null +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa_eddsa.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include + +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); diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa_primitives.h b/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa_primitives.h index 6a8b58e1bd99..f0d9ce3470d2 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa_primitives.h +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa_primitives.h @@ -371,4 +371,27 @@ struct cracen_pake_operation { }; }; typedef struct cracen_pake_operation cracen_pake_operation_t; + +struct sx_pk_ecurve; + +struct ecdsa_signature { + size_t sz; /**< Total signature size, in bytes. */ + const char *r; /**< Signature element "r". */ + const char *s; /**< Signature element "s". */ +}; +struct ecc_priv_key { + const struct sx_pk_ecurve *curve; + const char *d; /** Privat key value d */ +}; + +struct ecc_pub_key { + const struct sx_pk_ecurve *curve; + char *qx; /** x coordinate of a point on the curve */ + char *qy; /** y coordinate of a point on the curve */ +}; + +struct ecc_keypair { + struct ecc_priv_key priv_key; + struct ecc_pub_key pub_key; +}; #endif /* CRACEN_PSA_PRIMITIVES_H */ diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.c index 34f5ee3c176f..cd45503b391b 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.c +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.c @@ -852,3 +852,85 @@ psa_status_t cracen_get_opaque_size(const psa_key_attributes_t *attributes, size return PSA_ERROR_INVALID_ARGUMENT; } + +void be_add(unsigned char *v, size_t sz, size_t summand) +{ + while (sz > 0) { + sz--; + summand += v[sz]; + v[sz] = summand & 0xFF; + summand >>= 8; + } +} + +int be_cmp(const unsigned char *a, const unsigned char *b, size_t sz, int carry) +{ + unsigned int neq = 0; + unsigned int gt = 0; + unsigned int ucarry; + unsigned int d; + unsigned int lt; + + /* transform carry to work with unsigned numbers */ + ucarry = 0x100 + carry; + + for (int i = sz - 1; i >= 0; i--) { + d = ucarry + a[i] - b[i]; + ucarry = 0xFF + (d >> 8); + neq |= d & 0xFF; + } + + neq |= ucarry & 0xFF; + lt = ucarry < 0x100; + gt = neq && !lt; + + return (gt ? 1 : 0) - (lt ? 1 : 0); +} + +int hash_all_inputs_with_context(struct sxhash *hashopctx, const char *inputs[], + const size_t inputs_lengths[], size_t input_count, + const struct sxhashalg *hashalg, char *digest) +{ + 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, digest); + if (status != SX_OK) { + return status; + } + + status = sx_hash_wait(hashopctx); + + return status; +} + +int hash_all_inputs(const char *inputs[], const size_t inputs_lengths[], size_t input_count, + const struct sxhashalg *hashalg, char *digest) +{ + struct sxhash hashopctx; + + return hash_all_inputs_with_context(&hashopctx, inputs, inputs_lengths, input_count, + hashalg, digest); +} + +int hash_input(const char *input, const size_t input_length, const struct sxhashalg *hashalg, + char *digest) +{ + return hash_all_inputs(&input, &input_length, 1, hashalg, digest); +} + +int hash_input_with_context(struct sxhash *hashopctx, const char *input, const size_t input_length, + const struct sxhashalg *hashalg, char *digest) +{ + return hash_all_inputs_with_context(hashopctx, &input, &input_length, 1, hashalg, digest); +} diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.h b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.h index 8971f7d23dc1..73b9234f2668 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.h +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.h @@ -186,3 +186,102 @@ psa_status_t cracen_cipher_crypt_ecb(const struct sxkeyref *key, const uint8_t * * @return sxsymcrypt error code. */ int cracen_prepare_ik_key(const uint8_t *user_data); + +/** + * @brief Big-Endian addition. + * + * @param v Big-endian Value + * @param v_size size of v + * @param summand Summand. + * + */ +void be_add(unsigned char *v, size_t v_size, size_t summand); + +/** + * @brief Big-Endian compare with carry. + * + * @param a First value to be compared + * @param b Second value to be compared + * @param size Size of a and b. + * @param carry Value of the carry. + * + * \retval 0 if equal. + * \retval 1 if a > b. + * \retval -1 if a < b. + */ +int be_cmp(const unsigned char *a, const unsigned char *b, size_t sz, int carry); + +/** + * @brief Hash several elements at different locations in memory + * + * @param inputs[in] Array of pointers to elements that will be hashed. + * @param inputs_lengths[in] Array of lengths of elements to be hashed. + * @param input_count[in] Number of elements to be hashed. + * @param hashalg[in] Hash algorithm to be used in sxhashalg format. + * @param digest[out] Buffer of at least sx_hash_get_alg_digestsz(hashalg) bytes. + * + * @return sxsymcrypt error code. + */ +int hash_all_inputs(const char *inputs[], const size_t inputs_lengths[], size_t input_count, + const struct sxhashalg *hashalg, char *digest); + +/** + * @brief Hash several elements at different locations in memory with a previously created hash + * context(sxhash) + * + * @param sxhashopctx[in] Pointer to the sxhash context. + * @param inputs[in] Array of pointers to elements that will be hashed. + * @param inputs_lengths[in] Array of lengths of elements to be hashed. + * @param input_count[in] Number of elements to be hashed. + * @param hashalg[in] Hash algorithm to be used in sxhashalg format. + * @param digest[out] Buffer of at least sx_hash_get_alg_digestsz(hashalg) bytes. + * + * @return sxsymcrypt error code. + */ +int hash_all_inputs_with_context(struct sxhash *sxhashopctx, const char *inputs[], + const size_t inputs_lengths[], size_t input_count, + const struct sxhashalg *hashalg, char *digest); + +/** + * @brief Hash a single element + * + * @param inputs[in] Pointer to the element that will be hashed. + * @param inputs_lengths[in] Length of the element to be hashed. + * @param hashalg[in] Hash algorithm to be used in sxhashalg format. + * @param digest[out] Buffer of at least sx_hash_get_alg_digestsz(hashalg) bytes. + * + * @return sxsymcrypt error code. + */ +int hash_input(const char *input, const size_t input_length, const struct sxhashalg *hashalg, + char *digest); + +/** + * @brief Hash a single element with a previously created hash context(sxhash) + * + * @param sxhashopctx[in] Pointer to the sxhash context. + * @param inputs[in] Pointer to element that will be hashed. + * @param inputs_lengths[in] Length of element to be hashed. + * @param hashalg[in] hash algorithm to be used in sxhashalg format. + * @param digest[out] Buffer of at least sx_hash_get_alg_digestsz(hashalg) bytes. + * + * @return sxsymcrypt error code. + */ +int hash_input_with_context(struct sxhash *hashopctx, const char *input, const size_t input_length, + const struct sxhashalg *hashalg, char *digest); + +/** + * @brief Generate a random number within the specified range. + * + * This function generates a random number strictly less than the given upper limit (`n`). + * The generated random number is evenly distributed over the range [0, n-1]. If the range + * is invalid (e.g., `n` is zero, less than three, or even), an error code is returned. + * + * @param n[in] Pointer to a buffer holding the upper limit of the random range. + * The upper limit must be a non-zero odd number. + * @param nsz[in] Size of the upper limit buffer in bytes. + * @param out[out] Buffer to store the generated random number. + * The size of `out` should be at least `nsz`. + * + * @return sxsymcrypt error code: + */ +int rndinrange_create(const unsigned char *n, size_t nsz, unsigned char *out); diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ecc.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ecc.c new file mode 100644 index 000000000000..6fde92dd358a --- /dev/null +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ecc.c @@ -0,0 +1,89 @@ +/* ECC key pair generation. + * Based on FIPS 186-4, section B.4.2 "Key Pair Generation by Testing + * Candidates". + * + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include +#include +#include +#include "cracen_psa.h" +#include "ecc.h" +#include "common.h" + +#define MAX_ECC_ATTEMPTS 10 + +int ecc_create_genpubkey(const char *priv_key, char *pub_key, const struct sx_pk_ecurve *curve) +{ + const char **outputs; + struct sx_pk_acq_req pkreq; + struct sx_pk_inops_ecp_mult inputs; + int opsz; + int status; + + for (int i = 0; i <= MAX_ECC_ATTEMPTS; i++) { + pkreq = sx_pk_acquire_req(SX_PK_CMD_ECC_PTMUL); + if (pkreq.status) { + return pkreq.status; + } + pkreq.status = sx_pk_list_ecc_inslots(pkreq.req, curve, 0, + (struct sx_pk_slot *)&inputs); + if (pkreq.status) { + return pkreq.status; + } + + opsz = sx_pk_curve_opsize(curve); + + /* Write the private key (random) into ba414ep device memory */ + sx_wrpkmem(inputs.k.addr, priv_key, opsz); + sx_pk_write_curve_gen(pkreq.req, curve, inputs.px, inputs.py); + + sx_pk_run(pkreq.req); + + status = sx_pk_wait(pkreq.req); + if (status != SX_OK) { + return status; + } + outputs = sx_pk_get_output_ops(pkreq.req); + + /* When countermeasures are used, the operation may fail with error code + * SX_ERR_NOT_INVERTIBLE. In this case we can try again. + */ + if (status == SX_ERR_NOT_INVERTIBLE) { + sx_pk_release_req(pkreq.req); + if (i == MAX_ECC_ATTEMPTS) { + return SX_ERR_TOO_MANY_ATTEMPTS; + } + } else { + break; + } + } + sx_rdpkmem(pub_key, outputs[0], opsz); + sx_rdpkmem(pub_key + opsz, outputs[1], opsz); + sx_pk_release_req(pkreq.req); + return status; +} + +int ecc_create_genprivkey(const struct sx_pk_ecurve *curve, char *priv_key, size_t priv_key_size) +{ + int status; + int opsz = sx_pk_curve_opsize(curve); + const char *curve_n = sx_pk_curve_order(curve); + size_t keysz = (size_t)sx_pk_curve_opsize(curve); + + if (priv_key_size < keysz) { + return SX_ERR_OUTPUT_BUFFER_TOO_SMALL; + } + + /* generate private key, a random number in [1, n-1], where n is the curve + * order + */ + status = rndinrange_create((const unsigned char *)curve_n, opsz, priv_key); + + return status; +} diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ecc.h b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ecc.h new file mode 100644 index 000000000000..212629b5bf37 --- /dev/null +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ecc.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#include + +int ecc_create_genpubkey(const char *priv_key, char *pub_key, const struct sx_pk_ecurve *curve); + +int ecc_create_genprivkey(const struct sx_pk_ecurve *curve, char *priv_key, size_t priv_key_size); diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ecdsa.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ecdsa.c new file mode 100644 index 000000000000..e22ed8d452dc --- /dev/null +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ecdsa.c @@ -0,0 +1,554 @@ +/* ECDSA signature generation and verification. + * + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + * + * Workmem layout for the ECDSA sign task: + * 1. Hash digest of the message to be signed (size: digestsz). + * 2. Output of the rndinrange subtask (size: curve_op_size, which is the + * max size in bytes of parameters and operands for the selected curve). + * + * Workmem layout for the ECDSA Deterministic sign task: + * 1. HMAC task requirements (size: digestsz + blocksz) + * 2. Hash digest of the message to be signed (size: digestsz). + * 4. K (HMAC key) (size: digestsz) + * 5. V (size: digestsz) + * 6. T (size: curve_op_size) + * + * Workmem layout for the ECDSA verify task: + * 1. Hash digest of the message whose signature is being verified + * (size: digestsz). + */ + +#include +#include +#include +#include +#include +#include +#include "sxsymcrypt/hash.h" +#include "cracen_psa_ecdsa.h" +#include "cracen_psa_primitives.h" +#include "sxsymcrypt/hash.h" +#include "hashdefs.h" +#include "common.h" +#include "hmac.h" + +#define INTERNAL_OCTET_NOT_USED ((uint8_t)0xFFu) +#define DETERMINISTIC_HMAC_STEPS 6 + +#ifndef MAX_ECDSA_ATTEMPTS +#define MAX_ECDSA_ATTEMPTS 255 +#endif + +typedef enum { + INTERNAL_OCTET_ZERO, + INTERNAL_OCTET_ONE, + INTERNAL_OCTET_UNUSED, +} internal_octet_t; + +struct ecdsa_hmac_operation { + int attempts; + uint16_t tlen; + uint8_t step; + int deterministic_retries; +}; + +/* Counts leading zeroes in a u8 */ +static int clz_u8(uint8_t i) +{ + int r = 0; + + while (((1 << (7 - r)) & i) == 0) { + r++; + } + return r; +} + +/** Convert a digest into an operand for ECDSA + * + * The raw digest may need to be padded or truncated to fit the curve + * operand used for ECDSA.s + * + * Conversion could also imply byte order inversion, but that is not + * implemented here. It's expected that SilexPK takes big endian + * operands here. + * + * As the digest size is expressed in bytes, this procedure does not + * work for curves which have sizes not multiples of 8 bits. + */ +static void digest2op(const char *digest, size_t sz, char *dst, size_t opsz) +{ + if (opsz > sz) { + sx_clrpkmem(dst, opsz - sz); + dst += opsz - sz; + } + sx_wrpkmem(dst, digest, opsz); +} + +/** + * @brief Perform bits2int according to definition in RFC-6979. + */ +void bits2int(const uint8_t *data, size_t data_len, uint8_t *out_data, size_t qlen) +{ + size_t data_bitlen = data_len * 8; + size_t qbytes = ROUND_UP(qlen, 8) / 8; + + if (data_bitlen > qlen) { + uint32_t rshift = qbytes * 8 - qlen; + + memmove(out_data, data, qbytes); + + if (rshift) { + uint8_t prev = 0; + + for (size_t i = 0; i < qbytes; i++) { + uint8_t tmp = out_data[i]; + + out_data[i] = prev << (8 - rshift) | (tmp >> rshift); + prev = tmp; + } + } + + } else { + memset(out_data, 0, qbytes - data_len); + memmove(out_data + (qbytes - data_len), data, data_len); + } +} + +/** + * @brief Perform bits2octects according to definition in RFC-6979. + */ +void bits2octets(const uint8_t *data, size_t data_len, uint8_t *out_data, const uint8_t *order, + size_t order_len) +{ + bits2int(data, data_len, out_data, order_len * 8 - clz_u8(order[0])); + + int ge = be_cmp(out_data, order, order_len, 0); + + if (ge >= 0) { + uint8_t carry = 0; + + for (size_t i = order_len; i > 0; i--) { + uint32_t a = out_data[i - 1]; + uint32_t b = order[i - 1] + carry; + + if (b > a) { + a += 0x100; + carry = 1; + } else { + carry = 0; + } + out_data[i - 1] = a - b; + } + } +} + +static void ecdsa_write_pk(const char *pubkey, char *x, char *y, size_t opsz) +{ + sx_wrpkmem(x, pubkey, opsz); + sx_wrpkmem(y, pubkey + opsz, opsz); +} + +static void ecdsa_write_sig(const struct ecdsa_signature *sig, char *r, char *s, size_t opsz) +{ + sx_wrpkmem(r, sig->r, opsz); + sx_wrpkmem(s, sig->s, opsz); +} + +static void ecdsa_write_sk(const struct ecc_priv_key *sk, char *d, size_t opsz) +{ + sx_wrpkmem(d, sk->d, opsz); +} + +static void ecdsa_read_sig(struct ecdsa_signature *sig, const char *r, const char *s, size_t opsz) +{ + sx_rdpkmem((char *)sig->r, (char *)r, opsz); + if (!sig->s) { + sig->s = sig->r + opsz; + } + sx_rdpkmem((char *)sig->s, (char *)s, opsz); +} + +int cracen_ecdsa_sign_message(const struct ecc_priv_key *privkey, const struct sxhashalg *hashalg, + const struct sx_pk_ecurve *curve, const uint8_t *message, + size_t message_length, const uint8_t *signature) +{ + int status; + size_t digestsz = sx_hash_get_alg_digestsz(hashalg); + char digest[digestsz]; + + status = hash_input(message, message_length, hashalg, digest); + if (status != SX_OK) { + return status; + } + + return cracen_ecdsa_sign_digest(privkey, hashalg, curve, digest, digestsz, signature); +} + +int cracen_ecdsa_sign_digest(const struct ecc_priv_key *privkey, const struct sxhashalg *hashalg, + const struct sx_pk_ecurve *curve, const uint8_t *digest, + size_t digest_length, const uint8_t *signature) +{ + int status; + size_t digestsz = sx_hash_get_alg_digestsz(hashalg); + size_t opsz = sx_pk_curve_opsize(curve); + struct sx_pk_acq_req pkreq; + struct sx_pk_inops_ecdsa_generate inputs; + const char *curve_n; + size_t workmem_requirement = digestsz + opsz; + struct ecdsa_signature internal_signature = {0}; + char workmem[workmem_requirement]; + + memcpy(workmem, digest, digest_length); + curve_n = sx_pk_curve_order(curve); + + internal_signature.r = signature; + internal_signature.s = signature + opsz; + + for (int i = 0; i <= MAX_ECDSA_ATTEMPTS; i++) { + status = + rndinrange_create((const unsigned char *)curve_n, opsz, workmem + digestsz); + if (status != SX_OK) { + return status; + } + pkreq = sx_pk_acquire_req(SX_PK_CMD_ECDSA_GEN); + if (pkreq.status) { + return pkreq.status; + } + pkreq.status = + sx_pk_list_ecc_inslots(pkreq.req, curve, 0, (struct sx_pk_slot *)&inputs); + if (pkreq.status) { + return pkreq.status; + } + + ecdsa_write_sk(privkey, inputs.d.addr, opsz); + sx_wrpkmem(inputs.k.addr, workmem + digestsz, opsz); + digest2op(workmem, digestsz, inputs.h.addr, opsz); + sx_pk_run(pkreq.req); + status = sx_pk_wait(pkreq.req); + if (status != SX_OK) { + return status; + } + status = sx_pk_has_finished(pkreq.req); + if (status == SX_ERR_BUSY) { + return SX_ERR_HW_PROCESSING; + } + + /* SX_ERR_NOT_INVERTIBLE may be due to silexpk countermeasures. */ + if ((status == SX_ERR_INVALID_SIGNATURE) || (status == SX_ERR_NOT_INVERTIBLE)) { + sx_pk_release_req(pkreq.req); + if (i == MAX_ECDSA_ATTEMPTS) { + return SX_ERR_TOO_MANY_ATTEMPTS; + } + } else { + break; + } + } + if (status != SX_OK) { + sx_pk_release_req(pkreq.req); + return status; + } + + const char **outputs = sx_pk_get_output_ops(pkreq.req); + + ecdsa_read_sig(&internal_signature, outputs[0], outputs[1], opsz); + sx_pk_release_req(pkreq.req); + safe_memzero(workmem, workmem_requirement); + + return SX_OK; +} + +static int run_deterministic_ecdsa_hmac_step(const struct sxhashalg *hashalg, size_t opsz, + const char *curve_n, size_t digestsz, size_t blocksz, + char *workmem, struct ecdsa_hmac_operation *hmac_op, + const struct ecc_priv_key *privkey); + +static int deterministic_ecdsa_hmac(const struct sxhashalg *hashalg, const uint8_t *key, + const uint8_t *v, size_t hash_len, + internal_octet_t internal_octet, const uint8_t *sk, + const uint8_t *hash, size_t key_len, uint8_t *hmac); + +int cracen_ecdsa_sign_digest_deterministic(const struct ecc_priv_key *privkey, + const struct sxhashalg *hashalg, + const struct sx_pk_ecurve *curve, const uint8_t *digest, + size_t digestsz, const uint8_t *signature) +{ + int status; + int attempts = MAX_ECDSA_ATTEMPTS; + size_t opsz = (size_t)sx_pk_curve_opsize(curve); + size_t blocksz = sx_hash_get_alg_blocksz(hashalg); + size_t workmem_requirement = digestsz * 4 + opsz + blocksz; + const char *curve_n = sx_pk_curve_order(curve); + char workmem[workmem_requirement]; + + struct sx_pk_acq_req pkreq; + struct sx_pk_inops_ecdsa_generate inputs; + struct ecdsa_signature internal_signature = {0}; + + internal_signature.r = signature; + internal_signature.s = signature + opsz; + memcpy(workmem, digest, digestsz); + + do { + struct ecdsa_hmac_operation hmac_op = {0}; + + hmac_op.attempts = MAX_ECDSA_ATTEMPTS; + + uint8_t *h1 = workmem + digestsz + blocksz; + + memcpy(h1, workmem, digestsz); + while (hmac_op.step <= DETERMINISTIC_HMAC_STEPS) { + status = run_deterministic_ecdsa_hmac_step(hashalg, opsz, curve_n, digestsz, + blocksz, workmem, &hmac_op, + privkey); + if (status != SX_OK && status != SX_ERR_HW_PROCESSING) { + return status; + } + } + + pkreq = sx_pk_acquire_req(SX_PK_CMD_ECDSA_GEN); + if (pkreq.status) { + return pkreq.status; + } + pkreq.status = + sx_pk_list_ecc_inslots(pkreq.req, curve, 0, (struct sx_pk_slot *)&inputs); + if (pkreq.status) { + return pkreq.status; + } + ecdsa_write_sk(privkey, inputs.d.addr, opsz); + sx_wrpkmem(inputs.k.addr, workmem + digestsz, opsz); + digest2op(workmem, digestsz, inputs.h.addr, opsz); + sx_pk_run(pkreq.req); + status = sx_pk_wait(pkreq.req); + if (status != SX_OK) { + sx_pk_release_req(pkreq.req); + } + + } while ((attempts--) && ((pkreq.status == SX_ERR_INVALID_SIGNATURE) || + (pkreq.status == SX_ERR_NOT_INVERTIBLE))); + const char **outputs = sx_pk_get_output_ops(pkreq.req); + + ecdsa_read_sig(&internal_signature, outputs[0], outputs[1], opsz); + sx_pk_release_req(pkreq.req); + safe_memzero(workmem, workmem_requirement); + + return SX_OK; +} + +int cracen_ecdsa_sign_message_deterministic(const struct ecc_priv_key *privkey, + const struct sxhashalg *hashalg, + const struct sx_pk_ecurve *curve, + const uint8_t *message, size_t message_length, + const uint8_t *signature) +{ + int status; + size_t digestsz = sx_hash_get_alg_digestsz(hashalg); + char digest[digestsz]; + + status = hash_input(message, message_length, hashalg, digest); + if (status != SX_OK) { + return status; + } + + return cracen_ecdsa_sign_digest_deterministic(privkey, hashalg, curve, digest, digestsz, + signature); +} + +static int run_deterministic_ecdsa_hmac_step(const struct sxhashalg *hashalg, size_t opsz, + const char *curve_n, size_t digestsz, size_t blocksz, + char *workmem, struct ecdsa_hmac_operation *hmac_op, + const struct ecc_priv_key *privkey) +{ + int status = SX_OK; + uint8_t *h1 = workmem + digestsz + blocksz; + uint8_t *K = h1 + digestsz; + uint8_t *V = K + digestsz; + uint8_t *T = V + digestsz; + uint8_t step = hmac_op->step; + + switch (step) { + case 0: /* K = HMAC_K(V || 0x00 || privkey || h1) */ + for (size_t i = 0; i < digestsz; i++) { + K[i] = 0x0; /* Initialize K = 0x00 0x00 ... */ + V[i] = 0x1; /* Initialize V = 0x01 0x01 ... */ + } + + /* The original h1 must be preserved for the sign operation. We reuse T for the + * transformed value. + */ + bits2octets(h1, digestsz, T, curve_n, opsz); + + status = deterministic_ecdsa_hmac(hashalg, K, V, digestsz, INTERNAL_OCTET_ZERO, + privkey->d, T, opsz, K); + break; + + case 1: /* V = HMAC_K(V) */ + status = deterministic_ecdsa_hmac(hashalg, K, V, digestsz, INTERNAL_OCTET_NOT_USED, + NULL, NULL, opsz, V); + break; + + case 2: /* K = HMAC_K(V || 0x01 || privkey || h1) */ + status = deterministic_ecdsa_hmac(hashalg, K, V, digestsz, INTERNAL_OCTET_ONE, + privkey->d, T, opsz, K); + break; + + case 3: /* V = HMAC_K(V) */ + case 4: /* same as case 3. */ + status = deterministic_ecdsa_hmac(hashalg, K, V, digestsz, INTERNAL_OCTET_NOT_USED, + NULL, NULL, opsz, V); + break; + + case 5: /* T = T || V */ + size_t copylen = MIN(digestsz, opsz - hmac_op->tlen); + + memcpy(T + hmac_op->tlen, V, copylen); + hmac_op->tlen += copylen; + if (hmac_op->tlen < opsz) { + /* We need more data. */ + hmac_op->step = 4; + return SX_ERR_HW_PROCESSING; + } + break; + + case 6: /* Verify that T is in range [1, q-1] */ + { + int rshift = clz_u8(curve_n[0]); + + /* Only use the first qlen bits that was generated. */ + bits2int(T, opsz, T, opsz * 8 - rshift); + + bool is_zero = true; + + for (size_t i = 0; i < opsz; i++) { + if (T[i]) { + is_zero = false; + break; + } + } + int ge = be_cmp(T, curve_n, opsz, 0); + bool must_retry = + hmac_op->deterministic_retries < (MAX_ECDSA_ATTEMPTS - hmac_op->attempts); + if (is_zero || ge >= 0 || must_retry) { + /* T is out of range. Retry */ + hmac_op->step = 3; + hmac_op->tlen = 0; + hmac_op->deterministic_retries++; + /* K = HMAC_K(V || 0x00) */ + deterministic_ecdsa_hmac(hashalg, K, V, digestsz, INTERNAL_OCTET_ZERO, NULL, + NULL, 0, K); + return SX_ERR_HW_PROCESSING; + } + memcpy(workmem, h1, digestsz); + memcpy(workmem + digestsz, T, opsz); + break; + } + default: + status = SX_ERR_INVALID_PARAM; + } + hmac_op->step++; + return status; +} + +static int deterministic_ecdsa_hmac(const struct sxhashalg *hashalg, const uint8_t *key, + const uint8_t *v, size_t hash_len, uint8_t internal_octet, + const uint8_t *sk, const uint8_t *hash, size_t key_len, + uint8_t *hmac) +{ + + struct sxhash hashopctx; + size_t workmemsz = sx_hash_get_alg_digestsz(hashalg) + sx_hash_get_alg_blocksz(hashalg); + char workmem[workmemsz]; + int status; + + status = mac_create_hmac(hashalg, &hashopctx, key, hash_len, workmem, workmemsz); + if (status != SX_OK) { + return status; + } + /* The hash function is initialized in mac_create_hmac */ + status = sx_hash_feed(&hashopctx, v, hash_len); + if (status != SX_OK) { + return status; + } + + if (internal_octet != INTERNAL_OCTET_NOT_USED) { + + static uint8_t internal_octet_values[] = { + [INTERNAL_OCTET_ZERO] = 0, + [INTERNAL_OCTET_ONE] = 1, + [INTERNAL_OCTET_UNUSED] = 0xFF, + + }; + uint8_t value = internal_octet_values[internal_octet]; + + status = sx_hash_feed(&hashopctx, &value, sizeof(value)); + } + if (sk) { + status = sx_hash_feed(&hashopctx, sk, key_len); + } + if (hash) { + status = sx_hash_feed(&hashopctx, hash, key_len); + } + if (status != SX_OK) { + return status; + } + + return hmac_produce(&hashopctx, hashalg, hmac, hash_len, workmem); +} + +int cracen_ecdsa_verify_message(const char *pubkey, const struct sxhashalg *hashalg, + const uint8_t *message, size_t message_length, + const struct sx_pk_ecurve *curve, const uint8_t *signature) +{ + int status; + size_t digestsz = sx_hash_get_alg_digestsz(hashalg); + char digest[digestsz]; + + status = hash_input(message, message_length, hashalg, digest); + if (status != SX_OK) { + return status; + } + + return cracen_ecdsa_verify_digest(pubkey, digest, digestsz, curve, signature); +} + +int cracen_ecdsa_verify_digest(const char *pubkey, const uint8_t *digest, size_t digestsz, + const struct sx_pk_ecurve *curve, const uint8_t *signature) +{ + int status; + size_t opsz = sx_pk_curve_opsize(curve); + + struct sx_pk_acq_req pkreq; + struct sx_pk_inops_ecdsa_verify inputs; + struct ecdsa_signature internal_signature = {0}; + + internal_signature.r = (const char *)signature; + internal_signature.s = (const char *)signature + opsz; + + pkreq = sx_pk_acquire_req(SX_PK_CMD_ECDSA_VER); + if (pkreq.status) { + sx_pk_release_req(pkreq.req); + return pkreq.status; + } + pkreq.status = sx_pk_list_ecc_inslots(pkreq.req, curve, 0, (struct sx_pk_slot *)&inputs); + if (pkreq.status) { + sx_pk_release_req(pkreq.req); + return pkreq.status; + } + + opsz = sx_pk_curve_opsize(curve); + ecdsa_write_pk(pubkey, inputs.qx.addr, inputs.qy.addr, opsz); + ecdsa_write_sig(&internal_signature, inputs.r.addr, inputs.s.addr, opsz); + + digest2op(digest, digestsz, inputs.h.addr, opsz); + sx_pk_run(pkreq.req); + status = sx_pk_wait(pkreq.req); + if (status != SX_OK) { + sx_pk_release_req(pkreq.req); + return status; + } + sx_pk_release_req(pkreq.req); + + return pkreq.status; +} diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ed25519.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ed25519.c index d3fd7c0b789a..046ecb9a90a6 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ed25519.c +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ed25519.c @@ -33,6 +33,8 @@ #include #include #include +#include "common.h" +#include "cracen_psa_eddsa.h" #define AREA2_MEM_OFFSET 32 #define AREA4_MEM_OFFSET 96 @@ -47,41 +49,6 @@ static char dom2[] = {0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39 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) { @@ -90,7 +57,7 @@ static int ed25519_calculate_r(char *workmem, const uint8_t *message, size_t mes 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, + return hash_all_inputs(hash_array + offset, hash_array_lengths + offset, input_count, &sxhashalg_sha2_512, workmem + SX_ED25519_DGST_SZ); } @@ -117,7 +84,7 @@ static int ed25519_sign_internal(const uint8_t *priv_key, char *signature, const 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); + status = hash_input(priv_key, SX_ED25519_SZ, &sxhashalg_sha2_512, area_1); if (status != SX_OK) { return status; } @@ -193,7 +160,7 @@ int cracen_ed25519ph_sign(const uint8_t *priv_key, char *signature, const uint8_ int status; if (is_message) { - status = hash_input(message, message_length, hashedmessage); + status = hash_input(message, message_length, &sxhashalg_sha2_512, hashedmessage); if (status != SX_OK) { return status; } @@ -222,11 +189,10 @@ static int ed25519_verify_internal(const uint8_t *pub_key, const char *message, 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); + 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; } @@ -244,7 +210,7 @@ int cracen_ed25519ph_verify(const uint8_t *pub_key, const char *message, size_t char message_digest[SX_ED25519_DGST_SZ]; if (is_message) { - status = hash_input(message, message_length, message_digest); + status = hash_input(message, message_length, &sxhashalg_sha2_512, message_digest); if (status != SX_OK) { return status; } @@ -261,7 +227,7 @@ int cracen_ed25519_create_pubkey(const uint8_t *priv_key, uint8_t *pub_key) char digest[SX_ED25519_DGST_SZ]; char *pub_key_A = digest + SX_ED25519_SZ; - status = hash_input(priv_key, SX_ED25519_SZ, digest); + status = hash_input(priv_key, SX_ED25519_SZ, &sxhashalg_sha2_512, digest); if (status != SX_OK) { return status; } diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/hmac.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/hmac.c new file mode 100644 index 000000000000..b9f456b0350e --- /dev/null +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/hmac.c @@ -0,0 +1,119 @@ +/* HMAC implementation, based on FIPS 198-1. + * + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + * + * Workmem layout for the HMAC task: + * 1. Area used to store values obtained from processing the key. + * Size: hash algorithm block size. + * 2. Area used to store the intermediate hash value. + * Size: hash algorithm digest size. + */ + +#include +#include +#include +#include +#include "cracen_psa_primitives.h" +#include "cracen_psa.h" +#include "common.h" + +/* xor bytes in 'buf' with a constant 'v', in place */ +static void xorbuf(char *buf, char v, size_t sz) +{ + for (size_t i = 0; i < sz; i++) { + *buf = *buf ^ v; + buf++; + } +} + +int hmac_produce(struct sxhash *hashctx, const struct sxhashalg *hashalg, char *digest, size_t sz, + char *workmem) +{ + int status; + size_t blocksz; + size_t digestsz; + + digestsz = sx_hash_get_alg_digestsz(hashalg); + if (sz < digestsz) { + sx_hash_free(hashctx); + return SX_ERR_OUTPUT_BUFFER_TOO_SMALL; + } + + blocksz = sx_hash_get_alg_blocksz(hashalg); + + /* run hash (1st hash of HMAC algorithm), result inside workmem */ + status = sx_hash_digest(hashctx, workmem + blocksz); + if (status != SX_OK) { + return status; + } + + status = sx_hash_wait(hashctx); + if (status != SX_OK) { + return status; + } + + /* compute K0 xor opad (0x36 ^ 0x5C = 0x6A) */ + xorbuf(workmem, 0x6A, blocksz); + + return hash_input(workmem, blocksz + digestsz, hashalg, digest); +} + +static int start_hmac_computation(struct sxhash *hashopctx, const struct sxhashalg *hashalg, + char *workmem) +{ + int status; + size_t blocksz; + + /* task for computing the 1st hash in the HMAC algorithm */ + status = sx_hash_create(hashopctx, hashalg, sizeof(*hashopctx)); + if (status != SX_OK) { + return status; + } + + blocksz = sx_hash_get_alg_blocksz(hashalg); + + /* The "prepared" key (called K0 in FIPS 198-1) is available and + * workmem points to it. Here we compute K0 xor ipad. + */ + xorbuf(workmem, 0x36, blocksz); + + /* start feeding the hash task */ + status = sx_hash_feed(hashopctx, workmem, blocksz); + + return status; +} + +int mac_create_hmac(const struct sxhashalg *hashalg, struct sxhash *hashopctx, const char *key, + size_t keysz, char *workmem, size_t workmemsz) +{ + int status; + size_t digestsz; + size_t blocksz; + + digestsz = sx_hash_get_alg_digestsz(hashalg); + blocksz = sx_hash_get_alg_blocksz(hashalg); + + /* a key longer than hash block size needs an additional preparation + * step + */ + if (keysz > blocksz) { + /* hash the key */ + status = hash_input_with_context(hashopctx, key, keysz, hashalg, workmem); + if (status != SX_OK) { + return status; + } + + /* zero padding */ + safe_memset(workmem + digestsz, workmemsz - digestsz, 0, blocksz - digestsz); + status = start_hmac_computation(hashopctx, hashalg, workmem); + } else { + memcpy(workmem, key, keysz); + /* zero padding */ + safe_memset(workmem + keysz, workmemsz - keysz, 0, blocksz - keysz); + + status = start_hmac_computation(hashopctx, hashalg, workmem); + } + return status; +} diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/hmac.h b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/hmac.h new file mode 100644 index 000000000000..498d932b744b --- /dev/null +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/hmac.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#include + +int mac_create_hmac(const struct sxhashalg *hashalg, struct sxhash *hashopctx, const char *key, + size_t keysz, char *workmem, size_t workmemsz); + +int hmac_produce(struct sxhash *hashctx, const struct sxhashalg *hashalg, char *out, size_t sz, + char *workmem); 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 a73c95e03198..fa83d33ce02a 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 @@ -11,8 +11,9 @@ #include "platform_keys/platform_keys.h" #include #include -#include -#include +#include "ecc.h" +#include "cracen_psa_ecdsa.h" +#include "cracen_psa_eddsa.h" #include #include #include @@ -520,9 +521,7 @@ static psa_status_t generate_ecc_private_key(const psa_key_attributes_t *attribu psa_ecc_family_t psa_curve = PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)); psa_status_t psa_status; int si_status; - struct sitask t; const struct sx_pk_ecurve *sx_curve; - struct si_eccsk si_priv_key; uint8_t workmem[PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS)] = {}; *key_buffer_length = 0; @@ -569,22 +568,17 @@ static psa_status_t generate_ecc_private_key(const psa_key_attributes_t *attribu memcpy(key_buffer, workmem, key_size_bytes); } else { - si_task_init(&t, workmem, key_size_bytes); - - si_priv_key.d = key_buffer; - si_ecc_create_genprivkey(&t, sx_curve, &si_priv_key); - si_task_run(&t); - si_status = si_task_wait(&t); + si_status = ecc_create_genprivkey(sx_curve, key_buffer, key_buffer_size); if (si_status != SX_OK) { - psa_status = silex_statuscodes_to_psa(si_status); + return silex_statuscodes_to_psa(si_status); } } safe_memzero(workmem, sizeof(workmem)); *key_buffer_length = key_size_bytes; - return psa_status; + return PSA_SUCCESS; #else return PSA_ERROR_NOT_SUPPORTED; #endif /* PSA_VENDOR_ECC_MAX_CURVE_BITS > 0 */ @@ -639,13 +633,9 @@ static psa_status_t handle_curve_family(psa_ecc_family_t psa_curve, size_t key_b if (IS_ENABLED(PSA_NEED_CRACEN_KEY_TYPE_ECC_SECP_R1) || IS_ENABLED(PSA_NEED_CRACEN_KEY_TYPE_ECC_SECP_K1) || IS_ENABLED(PSA_NEED_CRACEN_KEY_TYPE_ECC_BRAINPOOL_P_R1)) { - priv_key->def = si_sig_def_ecdsa; - priv_key->key.eckey.curve = sx_curve; - priv_key->key.eckey.d = (char *)key_buffer; - data[0] = SI_ECC_PUBKEY_UNCOMPRESSED; - pub_key->key.eckey.qx = &data[1]; - pub_key->key.eckey.qy = &data[1 + sx_pk_curve_opsize(sx_curve)]; + return silex_statuscodes_to_psa( + ecc_create_genpubkey(key_buffer, data + 1, sx_curve)); } else { return PSA_ERROR_NOT_SUPPORTED; } @@ -670,9 +660,8 @@ static psa_status_t handle_curve_family(psa_ecc_family_t psa_curve, size_t key_b case PSA_ECC_FAMILY_TWISTED_EDWARDS: if (key_bits_attr == 255 && IS_ENABLED(PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS_255)) { - int si_status = cracen_ed25519_create_pubkey(key_buffer, data); - - return silex_statuscodes_to_psa(si_status); + return silex_statuscodes_to_psa( + cracen_ed25519_create_pubkey(key_buffer, data)); } else if (key_bits_attr == 448 && IS_ENABLED(PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS_448)) { priv_key->def = si_sig_def_ed448; @@ -716,27 +705,32 @@ static psa_status_t export_ecc_public_key_from_keypair(const psa_key_attributes_ if (PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes)) == PSA_KEY_LOCATION_CRACEN) { - return handle_identity_key(key_buffer, key_buffer_size, sx_curve, data, - &priv_key, &pub_key); + return handle_identity_key(key_buffer, key_buffer_size, sx_curve, data, &priv_key, + &pub_key); } else { status = handle_curve_family(psa_curve, key_bits_attr, key_buffer, data, sx_curve, - &priv_key, &pub_key); + &priv_key, &pub_key); } if (status != PSA_SUCCESS) { return status; } - if (psa_curve != PSA_ECC_FAMILY_TWISTED_EDWARDS) { - char workmem[SX_ED448_DGST_SZ] = {}; - struct sitask t; - - si_task_init(&t, workmem, sizeof(workmem)); - si_sig_create_pubkey(&t, &priv_key, &pub_key); - si_task_run(&t); - - status = silex_statuscodes_to_psa(si_task_wait(&t)); - safe_memzero(workmem, sizeof(workmem)); - if (status != PSA_SUCCESS) { - return status; + if (IS_ENABLED(PSA_NEED_CRACEN_KEY_TYPE_ECC_MONTGOMERY_255) || + IS_ENABLED(PSA_NEED_CRACEN_KEY_TYPE_ECC_MONTGOMERY_448)) { + if (psa_curve != PSA_ECC_FAMILY_TWISTED_EDWARDS && + psa_curve != PSA_ECC_FAMILY_SECP_R1 && psa_curve != PSA_ECC_FAMILY_SECP_K1 && + psa_curve != PSA_ECC_FAMILY_BRAINPOOL_P_R1) { + char workmem[SX_ED448_DGST_SZ] = {}; + struct sitask t; + + si_task_init(&t, workmem, sizeof(workmem)); + si_sig_create_pubkey(&t, &priv_key, &pub_key); + si_task_run(&t); + + status = silex_statuscodes_to_psa(si_task_wait(&t)); + safe_memzero(workmem, sizeof(workmem)); + if (status != PSA_SUCCESS) { + return status; + } } } *data_length = expected_pub_key_size; diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/rndinrange.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/rndinrange.c new file mode 100644 index 000000000000..9d984615d823 --- /dev/null +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/rndinrange.c @@ -0,0 +1,108 @@ +/** + * @file + * + * @copyright Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include "../include/sicrypto/sicrypto.h" +#include +#include +#include +#include "common.h" + +/* Return 1 if the given byte string contains only zeros, 0 otherwise. */ +static int is_zero_bytestring(const char *a, size_t sz) +{ + int acc = 0; + + for (size_t i = 0; i < sz; i++) { + acc |= a[i]; + } + return !acc; +} + +static int rndinrange_continue(unsigned char *out, size_t rndsz, const unsigned char *upper_limit, + unsigned char msb_mask) +{ + int z; + int ge; + + /* Set to zero excess high-order bits in the most significant byte */ + out[0] &= msb_mask; + + /* If the generated number is 0 or >= n, then discard it and repeat */ + z = is_zero_bytestring((char *)out, rndsz); + ge = be_cmp(out, upper_limit, rndsz, 0); + if (z || (ge >= 0)) { + return SX_ERR_HW_PROCESSING; + } + + /* The generated number is valid */ + return SX_OK; +} + +static psa_status_t rndinrange_getrnd(unsigned char *out, size_t rndsz, + const unsigned char *upper_limit, unsigned char msb_mask) +{ + /* Get random octets from the PRNG in the environment. + * Place them directly in the user's output buffer. + */ + int result; + psa_status_t status; + + do { + status = cracen_get_random(NULL, out, rndsz); + + if (status != PSA_SUCCESS) { + return SX_ERR_UNKNOWN_ERROR; + } + result = rndinrange_continue(out, rndsz, upper_limit, msb_mask); + + } while (result == SX_ERR_HW_PROCESSING); + + return result; +} + +int rndinrange_create(const unsigned char *upper_limit, size_t upper_limit_sz, unsigned char *out) +{ + size_t index; + unsigned char msb_mask; + + /* Error if the provided upper limit has size 0 */ + if (upper_limit_sz == 0) { + return SX_ERR_INPUT_BUFFER_TOO_SMALL; + } + + /* Get index of most significant non-zero byte in n */ + for (index = 0; (upper_limit[index] == 0) && (index < upper_limit_sz); index++) { + /* Do nothing; just increment 'index' */ + } + + /* Error if the provided upper limit is 0 or if it is > 0 but < 3 */ + if ((index == upper_limit_sz) || + ((index == upper_limit_sz - 1) && (upper_limit[index] < 3))) { + return SX_ERR_INPUT_BUFFER_TOO_SMALL; + } + + /* Error if the provided upper limit is not odd */ + if ((upper_limit[upper_limit_sz - 1] & 0x01) == 0) { + return SX_ERR_INVALID_ARG; + } + + /* Get bit mask of the most significant non-zero byte in n */ + for (msb_mask = 0xFF; upper_limit[index] & msb_mask; msb_mask <<= 1) { + /* Do nothing; just increment 'index' */ + } + msb_mask = ~msb_mask; + + size_t rndsz = upper_limit_sz - index; + const unsigned char *adjusted_upper_limit = upper_limit + index; + unsigned char *adjusted_out = out + index; + + /* Write high-order zero bytes, if any, in the output buffer */ + safe_memset(out, upper_limit_sz, 0, index); + return rndinrange_getrnd(adjusted_out, rndsz, adjusted_upper_limit, msb_mask); +} 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 78a284c55811..4d7d84a5f48d 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/sign.c +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/sign.c @@ -1,7 +1,7 @@ /** * @file * - * @copyright Copyright (c) 2023 Nordic Semiconductor ASA + * @copyright Copyright (c) 2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -26,9 +25,13 @@ #include #include #include +#include "hashdefs.h" #include "common.h" #include "cracen_psa.h" +#include "cracen_psa_ecdsa.h" +#include "cracen_psa_eddsa.h" +#include "ecc.h" #define SI_IS_MESSAGE (1) #define SI_IS_HASH (0) #define SI_EXTRACT_PUBKEY (1) @@ -88,6 +91,7 @@ static int cracen_signature_prepare_ec_prvkey(struct si_sig_privkey *privkey, ch const psa_key_attributes_t *attributes, bool is_message, size_t digestsz) { + /* This code can be removed once IKSIG is rewritten */ int status; status = cracen_ecc_get_ecurve_from_psa( @@ -117,61 +121,26 @@ static int cracen_signature_prepare_ec_prvkey(struct si_sig_privkey *privkey, ch return SX_ERR_INVALID_ARG; } + if (alg == PSA_ALG_PURE_EDDSA || alg == PSA_ALG_ED25519PH) { + return SX_OK; + } + 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)) { if (PSA_ALG_IS_ECDSA(alg)) { - privkey->def = PSA_ALG_ECDSA_IS_DETERMINISTIC(alg) - ? si_sig_def_ecdsa_deterministic - : si_sig_def_ecdsa; - privkey->key.eckey.curve = *sicurve; - privkey->key.eckey.d = key_buffer; - if (is_message) { - return cracen_signature_set_hashalgo(&privkey->hashalg, alg); - } else { - return cracen_signature_set_hashalgo_from_digestsz( - &privkey->hashalg, alg, digestsz); - } + return SX_OK; } } return SX_ERR_INCOMPATIBLE_HW; } -static int cracen_prepare_ecdsa_ec_pubkey(struct si_sig_pubkey *pubkey, - const struct sx_pk_ecurve *sicurve, bool is_message, - psa_algorithm_t alg, size_t digestsz, size_t curvesz, - char *key_buffer) -{ - - int status = SX_ERR_INCOMPATIBLE_HW; - - pubkey->def = si_sig_def_ecdsa; - pubkey->key.eckey.curve = sicurve; - - if (is_message) { - status = cracen_signature_set_hashalgo(&pubkey->hashalg, alg); - } else { - status = cracen_signature_set_hashalgo_from_digestsz(&pubkey->hashalg, alg, - digestsz); - } - - if (status != SX_OK) { - return status; - } - - pubkey->key.eckey.qx = key_buffer; - pubkey->key.eckey.qy = key_buffer + curvesz; - - return SX_OK; -} - -static int cracen_signature_prepare_ec_pubkey(struct sitask *t, struct si_sig_pubkey *pubkey, - char *key_buffer, size_t key_buffer_size, +static int cracen_signature_prepare_ec_pubkey(const char *key_buffer, size_t key_buffer_size, const struct sx_pk_ecurve **sicurve, psa_algorithm_t alg, const psa_key_attributes_t *attributes, - bool is_message, size_t digestsz, char *pubkey_buffer) + char *pubkey_buffer) { size_t curvesz = PSA_BITS_TO_BYTES(psa_get_key_bits(attributes)); int status; @@ -212,37 +181,123 @@ 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, - is_message, alg, digestsz, - curvesz, key_buffer + 1); - } else { - status = cracen_prepare_ecdsa_ec_pubkey(pubkey, *sicurve, - is_message, alg, digestsz, - curvesz, pubkey_buffer); - } + memcpy(pubkey_buffer, key_buffer + 1, key_buffer_size - 1); + return SX_OK; - if (status != SX_OK) { + } else { + status = ecc_create_genpubkey(key_buffer, pubkey_buffer, *sicurve); return status; } } } + return status; +} - if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(psa_get_key_type(attributes))) { - struct si_sig_privkey m_privkey; +static psa_status_t validate_key_attributes(const psa_key_attributes_t *attributes, + size_t key_buffer_size, + const struct sx_pk_ecurve **ecurve) +{ + psa_status_t status = cracen_ecc_get_ecurve_from_psa( + PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)), + psa_get_key_bits(attributes), ecurve); + if (status != PSA_SUCCESS) { + return status; + } + if (key_buffer_size != PSA_BITS_TO_BYTES(psa_get_key_bits(attributes))) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + if (!PSA_KEY_TYPE_IS_ECC_KEY_PAIR(psa_get_key_type(attributes))) { + return PSA_ERROR_NOT_SUPPORTED; + } - status = cracen_signature_prepare_ec_prvkey(&m_privkey, key_buffer, key_buffer_size, - sicurve, alg, attributes, is_message, - digestsz); - if (status != SX_OK) { - return status; + return PSA_SUCCESS; +} + +static psa_status_t validate_signing_conditions(bool is_message, psa_algorithm_t alg, + const psa_key_attributes_t *attributes) +{ + if (!PSA_ALG_IS_ECDSA(alg) && alg != PSA_ALG_PURE_EDDSA && alg != PSA_ALG_ED25519PH) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (is_message && !SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_SIGN_MESSAGE, attributes)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (!is_message && !SI_PSA_IS_KEY_FLAG(PSA_KEY_USAGE_SIGN_HASH, attributes)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return PSA_SUCCESS; +} + +static psa_status_t handle_eddsa_sign(bool is_message, psa_algorithm_t alg, + const psa_key_attributes_t *attributes, + const uint8_t *key_buffer, uint8_t *signature, + const uint8_t *input, size_t input_length, + const struct sx_pk_ecurve *ecurve, size_t *signature_length) +{ + int status; + + if (alg == PSA_ALG_ED25519PH && IS_ENABLED(CONFIG_PSA_WANT_ALG_ED25519PH)) { + status = cracen_ed25519ph_sign(key_buffer, signature, input, input_length, + is_message); + if (status == SX_OK) { + *signature_length = 2 * ecurve->sz; + } + return silex_statuscodes_to_psa(status); + } + if (alg == PSA_ALG_PURE_EDDSA && psa_get_key_bits(attributes) == 255 && + IS_ENABLED(CONFIG_PSA_WANT_ALG_PURE_EDDSA)) { + status = cracen_ed25519_sign(key_buffer, signature, input, input_length); + if (status == SX_OK) { + *signature_length = 2 * ecurve->sz; } + return silex_statuscodes_to_psa(status); + } + return PSA_ERROR_NOT_SUPPORTED; +} + +static psa_status_t handle_ecdsa_sign(bool is_message, psa_algorithm_t alg, + const uint8_t *key_buffer, const uint8_t *input, + size_t input_length, uint8_t *signature, + const struct sx_pk_ecurve *ecurve, size_t *signature_length) +{ + int status; + struct ecc_priv_key privkey; + struct sxhashalg hashalg = {0}; + const struct sxhashalg *hashalgpointer = &hashalg; + + privkey.d = (const char *)key_buffer; + status = hash_get_algo(alg, &hashalgpointer); - si_sig_create_pubkey(t, &m_privkey, pubkey); - si_task_run(t); - return si_task_wait(t); + if (status != PSA_SUCCESS) { + return status; } - return status; + *signature_length = 2 * ecurve->sz; + status = PSA_ERROR_NOT_SUPPORTED; + + if (PSA_ALG_IS_DETERMINISTIC_ECDSA(alg) && + IS_ENABLED(CONFIG_PSA_WANT_ALG_DETERMINISTIC_ECDSA)) { + if (is_message) { + status = cracen_ecdsa_sign_message_deterministic( + &privkey, hashalgpointer, ecurve, input, input_length, signature); + } else { + status = cracen_ecdsa_sign_digest_deterministic( + &privkey, hashalgpointer, ecurve, input, input_length, signature); + } + } else if (IS_ENABLED(CONFIG_PSA_WANT_ALG_ECDSA)) { + if (is_message) { + status = cracen_ecdsa_sign_message(&privkey, hashalgpointer, ecurve, input, + input_length, signature); + } else { + status = cracen_ecdsa_sign_digest(&privkey, hashalgpointer, ecurve, input, + input_length, signature); + } + } + + return silex_statuscodes_to_psa(status); } static psa_status_t cracen_signature_ecc_sign(bool is_message, @@ -252,85 +307,56 @@ static psa_status_t cracen_signature_ecc_sign(bool is_message, 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; + psa_status_t status; + const struct sx_pk_ecurve *ecurve; - 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; + status = validate_key_attributes(attributes, key_buffer_size, &ecurve); + if (status != PSA_SUCCESS) { + return status; } - if ((int)signature_size < 2 * curve->sz) { + if ((int)signature_size < 2 * ecurve->sz) { return PSA_ERROR_BUFFER_TOO_SMALL; } - if (!PSA_KEY_TYPE_IS_ECC_KEY_PAIR(psa_get_key_type(attributes))) { - 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; + status = validate_signing_conditions(is_message, alg, attributes); + if (status != PSA_SUCCESS) { + return status; } - 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; - } + if (alg == PSA_ALG_PURE_EDDSA && (IS_ENABLED(CONFIG_PSA_WANT_ALG_ED25519PH) || + IS_ENABLED(CONFIG_PSA_WANT_ALG_PURE_EDDSA))) { + return handle_eddsa_sign(is_message, alg, attributes, key_buffer, signature, input, + input_length, ecurve, signature_length); + } else if (PSA_ALG_IS_ECDSA(alg) && (IS_ENABLED(CONFIG_PSA_WANT_ALG_ECDSA) || + IS_ENABLED(CONFIG_PSA_WANT_ALG_DETERMINISTIC_ECDSA))) { + return handle_ecdsa_sign(is_message, alg, key_buffer, input, input_length, + signature, ecurve, signature_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)]; + return PSA_ERROR_INVALID_ARGUMENT; +} - 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); +static psa_status_t validate_ec_signature_inputs(bool is_message, + const psa_key_attributes_t *attributes, + psa_key_type_t key_type, psa_algorithm_t alg) +{ + if (!(PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(key_type) || PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type))) { + return PSA_ERROR_NOT_SUPPORTED; } - *signature_length = 2 * curve->sz; - sign.sz = *signature_length; - sign.r = (char *)signature; - sign.s = (char *)signature + *signature_length / 2; - - if (is_message) { - si_sig_create_sign(&t, &privkey, &sign); - } else { - si_sig_create_sign_digest(&t, &privkey, &sign); + if (!(PSA_ALG_IS_ECDSA(alg) || PSA_ALG_IS_DETERMINISTIC_ECDSA(alg) || + alg == PSA_ALG_PURE_EDDSA || alg == PSA_ALG_ED25519PH || + PSA_ALG_IS_HASH_EDDSA(alg))) { + return PSA_ERROR_NOT_SUPPORTED; } - si_task_consume(&t, (char *)input, - is_message ? input_length : sx_hash_get_alg_digestsz(privkey.hashalg)); + 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_run(&t); - si_status = si_task_wait(&t); - safe_memzero(workmem, sizeof(workmem)); - return silex_statuscodes_to_psa(si_status); + return PSA_SUCCESS; } static psa_status_t cracen_signature_ecc_verify(bool is_message, @@ -340,69 +366,65 @@ static psa_status_t cracen_signature_ecc_verify(bool is_message, size_t input_length, const uint8_t *signature, size_t signature_length) { - int si_status = 0; - const struct sx_pk_ecurve *curve; - struct si_sig_pubkey pubkey = {0}; - struct si_sig_signature sign = {0}; - char pubkey_buffer[132] = {0}; /* 521 bits * 2 */ + psa_key_type_t key_type = psa_get_key_type(attributes); - /* Workmem for sicrypto ecc verify task is digest size. */ - char workmem[PSA_HASH_MAX_SIZE]; - struct sitask t; + psa_status_t status = validate_ec_signature_inputs(is_message, attributes, key_type, alg); - 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 PSA_ERROR_NOT_SUPPORTED; + if (status != PSA_SUCCESS) { + return status; } - if (!PSA_ALG_IS_ECDSA(alg) && alg != PSA_ALG_PURE_EDDSA && !PSA_ALG_IS_HASH_EDDSA(alg)) { + size_t public_key_size = + PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, psa_get_key_bits(attributes)); + if (public_key_size == 0) { return PSA_ERROR_NOT_SUPPORTED; } - 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; - } + char pubkey_buffer[public_key_size]; + const struct sx_pk_ecurve *curve = NULL; - 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, - is_message, input_length, pubkey_buffer); - if (si_status) { + int si_status = cracen_signature_prepare_ec_pubkey( + (const char *)key_buffer, key_buffer_size, &curve, alg, attributes, pubkey_buffer); + if (si_status != PSA_SUCCESS) { return silex_statuscodes_to_psa(si_status); } - if ((int)signature_length != 2 * curve->sz) { + if (signature_length != 2 * curve->sz) { 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; + } else if (PSA_ALG_IS_ECDSA(alg) || PSA_ALG_IS_DETERMINISTIC_ECDSA(alg)) { + struct sxhashalg hashalg = {0}; + const struct sxhashalg *hash_algorithm_ptr = &hashalg; - if (is_message) { - si_sig_create_verify(&t, &pubkey, &sign); - } else { - if (sx_hash_get_alg_digestsz(pubkey.hashalg) != input_length) { - return PSA_ERROR_INVALID_ARGUMENT; + status = cracen_ecc_get_ecurve_from_psa(PSA_KEY_TYPE_ECC_GET_FAMILY(key_type), + psa_get_key_bits(attributes), &curve); + if (status != PSA_SUCCESS) { + return status; } - 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)); + status = hash_get_algo(alg, &hash_algorithm_ptr); + if (status != PSA_SUCCESS) { + return status; + } + + si_status = is_message ? cracen_ecdsa_verify_message(pubkey_buffer, + hash_algorithm_ptr, input, + input_length, curve, signature) + : cracen_ecdsa_verify_digest(pubkey_buffer, input, + input_length, curve, signature); + + } else { + return PSA_ERROR_NOT_SUPPORTED; + } return silex_statuscodes_to_psa(si_status); } diff --git a/subsys/nrf_security/src/drivers/cracen/sicrypto/src/ecdsa.c b/subsys/nrf_security/src/drivers/cracen/sicrypto/src/ecdsa.c index 40ad62c484b0..14bf475d3e75 100644 --- a/subsys/nrf_security/src/drivers/cracen/sicrypto/src/ecdsa.c +++ b/subsys/nrf_security/src/drivers/cracen/sicrypto/src/ecdsa.c @@ -385,26 +385,7 @@ void bits2int(const uint8_t *data, size_t data_len, uint8_t *out_data, size_t ql void bits2octets(const uint8_t *data, size_t data_len, uint8_t *out_data, const uint8_t *order, size_t order_len) { - bits2int(data, data_len, out_data, order_len * 8 - clz_u8(order[0])); - - int ge = si_be_cmp(out_data, order, order_len, 0); - - if (ge >= 0) { - uint8_t carry = 0; - - for (size_t i = order_len; i > 0; i--) { - uint32_t a = out_data[i - 1]; - uint32_t b = order[i - 1] + carry; - - if (b > a) { - a += 0x100; - carry = 1; - } else { - carry = 0; - } - out_data[i - 1] = a - b; - } - } + /* Kept for compliance */ } static int run_deterministic_ecdsa_hmac_step(struct sitask *t, struct siwq *wq) diff --git a/subsys/nrf_security/src/drivers/cracen/sicrypto/src/hmac.c b/subsys/nrf_security/src/drivers/cracen/sicrypto/src/hmac.c index e3475dc976ec..d7b54bb75c8e 100644 --- a/subsys/nrf_security/src/drivers/cracen/sicrypto/src/hmac.c +++ b/subsys/nrf_security/src/drivers/cracen/sicrypto/src/hmac.c @@ -31,7 +31,8 @@ static void xorbuf(char *buf, char v, size_t sz) static int finish_hmac_computation(struct sitask *t, struct siwq *wq) { - size_t blocksz, digestsz; + size_t blocksz; + size_t digestsz; (void)wq; if (t->statuscode) { diff --git a/subsys/nrf_security/src/drivers/cracen/sicrypto/src/iksig.c b/subsys/nrf_security/src/drivers/cracen/sicrypto/src/iksig.c index dcfba82da3a9..33298f66ac52 100644 --- a/subsys/nrf_security/src/drivers/cracen/sicrypto/src/iksig.c +++ b/subsys/nrf_security/src/drivers/cracen/sicrypto/src/iksig.c @@ -279,6 +279,11 @@ static void create_pubkey(struct sitask *t, const struct si_sig_privkey *privkey pubkey->key.eckey.curve = privkey->key.ref.curve; } +const struct si_sig_def *const si_sig_def_ecdsa = &(const struct si_sig_def){ + .pubkey = create_pubkey, + .sigcomponents = 2, +}; + static const struct si_sig_def si_sig_def_ik = { .sign = create_sign, .sign_digest = create_sign_digest, diff --git a/subsys/nrf_security/src/drivers/cracen/sxsymcrypt/sxsymcrypt.cmake b/subsys/nrf_security/src/drivers/cracen/sxsymcrypt/sxsymcrypt.cmake index 774dd1e15d56..7b0e269aeac2 100644 --- a/subsys/nrf_security/src/drivers/cracen/sxsymcrypt/sxsymcrypt.cmake +++ b/subsys/nrf_security/src/drivers/cracen/sxsymcrypt/sxsymcrypt.cmake @@ -18,4 +18,5 @@ list(APPEND cracen_driver_sources list(APPEND cracen_driver_include_dirs ${CMAKE_CURRENT_LIST_DIR}/include + ${CMAKE_CURRENT_LIST_DIR}/src )