From ba6a352cd0fb88d2bca92fb98847e32be49c6ecb Mon Sep 17 00:00:00 2001 From: Lukas-Luger Date: Fri, 28 Feb 2025 08:36:00 +0100 Subject: [PATCH] adding ecdsa psa_crypto support --- crypto.c | 5 +- dtls.c | 7 + platform-specific/dtls_ecdsa_psa.c | 266 +++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 platform-specific/dtls_ecdsa_psa.c diff --git a/crypto.c b/crypto.c index 1937681d..9e9587d3 100644 --- a/crypto.c +++ b/crypto.c @@ -458,7 +458,9 @@ int dtls_ecdh_pre_master_secret(unsigned char *priv_key, dtls_ec_key_from_uint32(result_x, key_size, result); return key_size; } - +#ifdef USE_PSA +#include "platform-specific/dtls_ecdsa_psa.c" +#else /* USE_PSA */ void dtls_ecdsa_generate_key(unsigned char *priv_key, unsigned char *pub_key_x, @@ -556,6 +558,7 @@ dtls_ecdsa_verify_sig(const unsigned char *pub_key_x, return dtls_ecdsa_verify_sig_hash(pub_key_x, pub_key_y, key_size, sha256hash, sizeof(sha256hash), result_r, result_s); } +#endif /* USE_PSA */ #endif /* DTLS_ECC */ int diff --git a/dtls.c b/dtls.c index 47590c27..f9b9c3db 100644 --- a/dtls.c +++ b/dtls.c @@ -46,6 +46,10 @@ #include "uthash.h" #endif /* DTLS_PEERS_NOHASH */ +#ifdef USE_PSA +#include "psa/crypto.h" +#endif + #include "dtls_debug.h" #include "numeric.h" #include "netq.h" @@ -327,6 +331,9 @@ free_context(dtls_context_t *context) { void dtls_init(void) { +#ifdef USE_PSA + psa_crypto_init(); +#endif /* USE_PSA */ dtls_clock_init(); crypto_init(); netq_init(); diff --git a/platform-specific/dtls_ecdsa_psa.c b/platform-specific/dtls_ecdsa_psa.c new file mode 100644 index 00000000..82f85c09 --- /dev/null +++ b/platform-specific/dtls_ecdsa_psa.c @@ -0,0 +1,266 @@ +/******************************************************************************* + * + * Copyright (c) 2011-2025 Lukas Luger (TUD) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. + * + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Lukas Luger - adding psa crypto support + * + *******************************************************************************/ +#include "crypto.h" +#include "psa/crypto.h" +#include "numeric.h" +#include "hmac.h" + +/* 0x04<1>, x_P , y_P */ +#define DTLS_EC_PUB_KEY_SIZE (1 + 2 * DTLS_EC_KEY_SIZE) + +/* curve type<1>, namedcurve<2>, + * pub_key_size<1>, pub_key + */ +#define DTLS_KEYX_PARAMS_SIZE (4 + DTLS_EC_PUB_KEY_SIZE) + +void +dtls_ecdsa_generate_key(unsigned char *priv_key, + unsigned char *pub_key_x, + unsigned char *pub_key_y, + size_t key_size) { + assert(DTLS_EC_KEY_SIZE == key_size); + + uint8_t public_key[DTLS_EC_PUB_KEY_SIZE]; + + size_t actual_len; + + psa_key_attributes_t attr = psa_key_attributes_init(); + psa_key_id_t key_id = 0; + + /* usage flags + * only export needed, because no use of psa key storage + */ + psa_key_usage_t usage = PSA_KEY_USAGE_EXPORT; + psa_set_key_usage_flags(&attr, usage); + + /* permitted alg + * PSA_ALG_ECDSA(PSA_ALG_SHA_256) - with hashing + */ + psa_algorithm_t algo = PSA_ALG_ECDSA(PSA_ALG_SHA_256); + psa_set_key_algorithm(&attr, algo); + + /* type for ECDSA with hashing (weierstrass family) */ + psa_key_type_t type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); + psa_set_key_type(&attr, type); + + psa_set_key_bits(&attr, DTLS_EC_KEY_SIZE * 8); + + psa_generate_key(&attr, &key_id); + + psa_export_public_key(key_id, public_key, PSA_EXPORT_PUBLIC_KEY_MAX_SIZE, &actual_len); + + if(actual_len != DTLS_EC_PUB_KEY_SIZE) return; + + memcpy(pub_key_x, &public_key[1], DTLS_EC_KEY_SIZE); + memcpy(pub_key_y, &public_key[1 + DTLS_EC_KEY_SIZE], DTLS_EC_KEY_SIZE); + + psa_export_key(key_id, (uint8_t *)priv_key, DTLS_EC_KEY_SIZE, &actual_len); + + psa_destroy_key(key_id); +} + +/* rfc4492#section-5.4 */ +void +dtls_ecdsa_create_sig_hash(const unsigned char *priv_key, size_t key_size, + const unsigned char *sign_hash, size_t sign_hash_size, + uint32_t point_r[9], uint32_t point_s[9]) { + assert(DTLS_EC_KEY_SIZE == key_size); + assert(DTLS_HMAC_DIGEST_SIZE == sign_hash_size); + + size_t actual_len; + + psa_key_attributes_t attr = psa_key_attributes_init(); + psa_key_id_t key_id = 0; + + psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_HASH; + psa_set_key_usage_flags(&attr, usage); + + /* permitted alg + * PSA_ALG_ECDSA_ANY - randomized, without hashing + */ + psa_algorithm_t algo = PSA_ALG_ECDSA_ANY; + psa_set_key_algorithm(&attr, algo); + + /* type for ECDSA without hashing (weierstrass family) */ + psa_key_type_t type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); + psa_set_key_type(&attr, type); + + psa_set_key_bits(&attr, DTLS_EC_KEY_SIZE * 8); + + psa_import_key(&attr, (uint8_t *)priv_key, DTLS_EC_KEY_SIZE, &key_id); + + size_t sig_len = PSA_SIGN_OUTPUT_SIZE(type, DTLS_EC_KEY_SIZE * 8, algo); + uint8_t sig[sig_len]; + + psa_sign_hash(key_id, algo, (uint8_t *)sign_hash, DTLS_HMAC_DIGEST_SIZE, sig, sig_len, &actual_len); + + if(actual_len != sig_len) return; + + dtls_ec_key_from_uint32((uint32_t *)&sig[0], sig_len/2, (unsigned char *)point_r); + dtls_ec_key_from_uint32((uint32_t *)&sig[sig_len/2], sig_len/2, (unsigned char *)point_s); + + psa_destroy_key(key_id); +} + +void +dtls_ecdsa_create_sig(const unsigned char *priv_key, size_t key_size, + const unsigned char *client_random, size_t client_random_size, + const unsigned char *server_random, size_t server_random_size, + const unsigned char *keyx_params, size_t keyx_params_size, + uint32_t point_r[9], uint32_t point_s[9]) { + assert(DTLS_EC_KEY_SIZE == key_size); + assert(DTLS_RANDOM_LENGTH == client_random_size); + assert(DTLS_RANDOM_LENGTH == server_random_size); + assert(DTLS_KEYX_PARAMS_SIZE == keyx_params_size); + /* psa only accepts uint8 arrays */ + uint8_t message[2 * DTLS_RANDOM_LENGTH + DTLS_KEYX_PARAMS_SIZE]; + memcpy(&message[0], client_random, DTLS_RANDOM_LENGTH); + memcpy(&message[DTLS_RANDOM_LENGTH], server_random, DTLS_RANDOM_LENGTH); + memcpy(&message[2 * DTLS_RANDOM_LENGTH], keyx_params, DTLS_KEYX_PARAMS_SIZE); + + size_t actual_len; + + psa_key_attributes_t attr = psa_key_attributes_init(); + psa_key_id_t key_id = 0; + + psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_MESSAGE; + psa_set_key_usage_flags(&attr, usage); + + /* permitted alg + * PSA_ALG_ECDSA(PSA_ALG_SHA_256) - with hashing + */ + psa_algorithm_t algo = PSA_ALG_ECDSA(PSA_ALG_SHA_256); + psa_set_key_algorithm(&attr, algo); + + /* type for ECDSA with hashing (weierstrass family) */ + psa_key_type_t type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); + psa_set_key_type(&attr, type); + + psa_set_key_bits(&attr, DTLS_EC_KEY_SIZE * 8); + + psa_import_key(&attr, (uint8_t *)priv_key, DTLS_EC_KEY_SIZE, &key_id); + + size_t sig_len = PSA_SIGN_OUTPUT_SIZE(type, DTLS_EC_KEY_SIZE * 8, algo); + uint8_t sig[sig_len]; + + psa_sign_message(key_id, algo, message, sizeof(message), sig, sig_len, &actual_len); + + if(actual_len != sig_len) return; + + dtls_ec_key_from_uint32((uint32_t *)&sig[0], sig_len/2, (unsigned char *)point_r); + dtls_ec_key_from_uint32((uint32_t *)&sig[sig_len/2], sig_len/2, (unsigned char *)point_s); + + psa_destroy_key(key_id); +} + +/* rfc4492#section-5.4 */ +int +dtls_ecdsa_verify_sig_hash(const unsigned char *pub_key_x, + const unsigned char *pub_key_y, size_t key_size, + const unsigned char *sign_hash, size_t sign_hash_size, + unsigned char *result_r, unsigned char *result_s) { + assert(DTLS_EC_KEY_SIZE == key_size); + assert(DTLS_HMAC_DIGEST_SIZE == sign_hash_size); + /* psa only accepts uint8 arrays */ + uint8_t public_key[DTLS_EC_PUB_KEY_SIZE]; + public_key[0] = 0x04; + memcpy(&public_key[1], pub_key_x, DTLS_EC_KEY_SIZE); + memcpy(&public_key[1 + DTLS_EC_KEY_SIZE], pub_key_y, DTLS_HMAC_DIGEST_SIZE); + + uint8_t sig[DTLS_EC_KEY_SIZE * 2]; + memcpy(&sig[0], result_r, DTLS_EC_KEY_SIZE); + memcpy(&sig[DTLS_EC_KEY_SIZE], result_s, DTLS_EC_KEY_SIZE); + + psa_key_attributes_t attr = psa_key_attributes_init(); + psa_key_id_t key_id = 0; + + psa_key_usage_t usage = PSA_KEY_USAGE_VERIFY_HASH; + psa_set_key_usage_flags(&attr, usage); + + /* permitted alg + * PSA_ALG_ECDSA_ANY - randomized, without hashing + */ + psa_algorithm_t algo = PSA_ALG_ECDSA_ANY; + psa_set_key_algorithm(&attr, algo); + + /* type for ECDSA without hashing (weierstrass family) */ + psa_key_type_t type = PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1); + + psa_set_key_type(&attr, type); + + psa_set_key_bits(&attr, DTLS_EC_KEY_SIZE * 8); + + psa_import_key(&attr, public_key, DTLS_EC_PUB_KEY_SIZE, &key_id); + + psa_status_t ret = psa_verify_hash(key_id, algo, (uint8_t *)sign_hash, DTLS_HMAC_DIGEST_SIZE, sig, DTLS_EC_KEY_SIZE * 2); + + psa_destroy_key(key_id); + + return ret; +} + +int +dtls_ecdsa_verify_sig(const unsigned char *pub_key_x, + const unsigned char *pub_key_y, size_t key_size, + const unsigned char *client_random, size_t client_random_size, + const unsigned char *server_random, size_t server_random_size, + const unsigned char *keyx_params, size_t keyx_params_size, + unsigned char *result_r, unsigned char *result_s) { + assert(DTLS_EC_KEY_SIZE == key_size); + assert(DTLS_RANDOM_LENGTH == client_random_size); + assert(DTLS_RANDOM_LENGTH == server_random_size); + assert(DTLS_KEYX_PARAMS_SIZE == keyx_params_size); + /* psa only accepts uint8 arrays */ + uint8_t public_key[DTLS_EC_PUB_KEY_SIZE]; + public_key[0] = 0x04; + memcpy(&public_key[1], pub_key_x, DTLS_EC_KEY_SIZE); + memcpy(&public_key[1+ DTLS_EC_KEY_SIZE], pub_key_y, DTLS_EC_KEY_SIZE); + + uint8_t message[2 * DTLS_RANDOM_LENGTH + DTLS_KEYX_PARAMS_SIZE]; + memcpy(&message[0], client_random, DTLS_RANDOM_LENGTH); + memcpy(&message[DTLS_RANDOM_LENGTH], server_random, DTLS_RANDOM_LENGTH); + memcpy(&message[2 * DTLS_RANDOM_LENGTH], keyx_params, DTLS_KEYX_PARAMS_SIZE); + + uint8_t sig[DTLS_EC_KEY_SIZE * 2]; + memcpy(&sig[0], result_r, DTLS_EC_KEY_SIZE); + memcpy(&sig[DTLS_EC_KEY_SIZE], result_s, DTLS_EC_KEY_SIZE); + + psa_key_attributes_t attr = psa_key_attributes_init(); + psa_key_id_t key_id = 0; + + psa_key_usage_t usage = PSA_KEY_USAGE_VERIFY_MESSAGE; + psa_set_key_usage_flags(&attr, usage); + + /* permitted alg + * PSA_ALG_ECDSA(PSA_ALG_SHA_256) - with hashing + */ + psa_algorithm_t algo = PSA_ALG_ECDSA(PSA_ALG_SHA_256); + psa_set_key_algorithm(&attr, algo); + + /* type for ECDSA with hashing (weierstrass family) */ + psa_key_type_t type = PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1); + psa_set_key_type(&attr, type); + + psa_set_key_bits(&attr, DTLS_EC_KEY_SIZE * 8); + + psa_import_key(&attr, public_key, DTLS_EC_PUB_KEY_SIZE, &key_id); + + psa_status_t ret = psa_verify_message(key_id, algo, message, sizeof(message), sig, DTLS_EC_KEY_SIZE * 2); + + psa_destroy_key(key_id); + + return ret; +}