Hi Philippe, On Mon, Jun 1, 2026 at 9:43 AM Philippe Reynes <[email protected]> wrote: > > Adds an initial support of ecdsa verify using mbedtls. > > Reviewed-by: Raymond Mao <[email protected]> > Signed-off-by: Philippe Reynes <[email protected]> > --- > v2: > - rename sw_ecdsa.c to ecdsa.c > v3: > - rename sw_ecdsa_verify to ecdsa_hash_verify > - stop on first group found > - check signature len > - use debug instead of printf > - check function returns > - fix memleaks in ecdsa_hash_verify > v4: > - move struct ecdsa_public_key from ecdsa-u-class.h to internal/ecdsa.h > - use DIV_ROUND_UP > - some code cleanup > v5: > - add kerneldoc header for ecdsa_hash_verify > - read error when setting Q.Z > v6: > - add ECDSA_VERIFY_MBEDTLS > - fix kerneldoc: doc not add a space before : > v7: > - no change > v8: > - add some useful comments > - avoid using label such as out1, out2, out3 ... > - code cleanup > > configs/sandbox_defconfig | 1 + > include/crypto/ecdsa-uclass.h | 15 +--- > include/crypto/internal/ecdsa.h | 39 ++++++++ > lib/mbedtls/Kconfig | 7 ++ > lib/mbedtls/Makefile | 3 + > lib/mbedtls/ecdsa.c | 152 ++++++++++++++++++++++++++++++++ > 6 files changed, 203 insertions(+), 14 deletions(-) > create mode 100644 include/crypto/internal/ecdsa.h > create mode 100644 lib/mbedtls/ecdsa.c >
Thanks! Reviewed-by: Raymond Mao <[email protected]> > diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig > index 03c35429bc6..9ff1afe4e64 100644 > --- a/configs/sandbox_defconfig > +++ b/configs/sandbox_defconfig > @@ -382,6 +382,7 @@ CONFIG_CMD_DHRYSTONE=y > CONFIG_MBEDTLS_LIB=y > CONFIG_HKDF_MBEDTLS=y > CONFIG_ECDSA_MBEDTLS=y > +CONFIG_ECDSA_VERIFY_MBEDTLS=y > CONFIG_ECDSA=y > CONFIG_ECDSA_VERIFY=y > CONFIG_RSASSA_PSS=y > diff --git a/include/crypto/ecdsa-uclass.h b/include/crypto/ecdsa-uclass.h > index 189843820a0..047a5eda2fc 100644 > --- a/include/crypto/ecdsa-uclass.h > +++ b/include/crypto/ecdsa-uclass.h > @@ -4,20 +4,7 @@ > */ > > #include <dm/device.h> > - > -/** > - * struct ecdsa_public_key - ECDSA public key properties > - * > - * The struct has pointers to the (x, y) curve coordinates to an ECDSA public > - * key, as well as the name of the ECDSA curve. The size of the key is > inferred > - * from the 'curve_name' > - */ > -struct ecdsa_public_key { > - const char *curve_name; /* Name of curve, e.g. "prime256v1" */ > - const void *x; /* x coordinate of public key */ > - const void *y; /* y coordinate of public key */ > - unsigned int size_bits; /* key size in bits, derived from curve name > */ > -}; > +#include <crypto/internal/ecdsa.h> > > struct ecdsa_ops { > /** > diff --git a/include/crypto/internal/ecdsa.h b/include/crypto/internal/ecdsa.h > new file mode 100644 > index 00000000000..244a07d1f1f > --- /dev/null > +++ b/include/crypto/internal/ecdsa.h > @@ -0,0 +1,39 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * Copyright (c) 2026, Philippe Reynes <[email protected]> > + */ > +#ifndef _ECDSA_HELPER_ > +#define _ECDSA_HELPER_ > + > +#include <linux/types.h> > + > +/** > + * struct ecdsa_public_key - ECDSA public key properties > + * > + * The struct has pointers to the (x, y) curve coordinates to an ECDSA public > + * key, as well as the name of the ECDSA curve. The size of the key is > inferred > + * from the 'curve_name' > + */ > +struct ecdsa_public_key { > + const char *curve_name; /* Name of curve, e.g. "prime256v1" */ > + const void *x; /* x coordinate of public key */ > + const void *y; /* y coordinate of public key */ > + unsigned int size_bits; /* key size in bits, derived from curve name > */ > +}; > + > +/** > + * ecdsa_hash_verify() - Verify the ecdsa signature of a hash > + * > + * @pubkey: ecdsa public key > + * @hash: Hash > + * @hash_len: Size of the hash > + * @signature: Signature > + * @sig_len: Size of the signature > + * > + * Return: 0 if all verified ok, <0 on error > + */ > +int ecdsa_hash_verify(const struct ecdsa_public_key *pubkey, > + const void *hash, size_t hash_len, > + const void *signature, size_t sig_len); > + > +#endif > diff --git a/lib/mbedtls/Kconfig b/lib/mbedtls/Kconfig > index e019f17d6bd..66bc16db451 100644 > --- a/lib/mbedtls/Kconfig > +++ b/lib/mbedtls/Kconfig > @@ -308,6 +308,13 @@ config ECDSA_MBEDTLS > This option enables support of ECDSA with the MbedTLS certificate > library. > > +config ECDSA_VERIFY_MBEDTLS > + bool "Enable ECDSA verify" > + depends on ECDSA_MBEDTLS && ECDSA_VERIFY > + help > + This option enables support of ECDSA signature check with > + MbedTLS certificate library. > + > endif # MBEDTLS_LIB_X509 > > config MBEDTLS_LIB_TLS > diff --git a/lib/mbedtls/Makefile b/lib/mbedtls/Makefile > index 0c86c90d15a..b96db812afc 100644 > --- a/lib/mbedtls/Makefile > +++ b/lib/mbedtls/Makefile > @@ -11,6 +11,9 @@ obj-$(CONFIG_$(PHASE_)SHA1_MBEDTLS) += sha1.o > obj-$(CONFIG_$(PHASE_)SHA256_MBEDTLS) += sha256.o > obj-$(CONFIG_$(PHASE_)SHA512_MBEDTLS) += sha512.o > > +# shim layer for ecdsa verify > +obj-$(CONFIG_$(PHASE_)ECDSA_VERIFY_MBEDTLS) += ecdsa.o > + > # x509 libraries > obj-$(CONFIG_$(PHASE_)ASYMMETRIC_PUBLIC_KEY_MBEDTLS) += \ > public_key.o > diff --git a/lib/mbedtls/ecdsa.c b/lib/mbedtls/ecdsa.c > new file mode 100644 > index 00000000000..ca4e572e638 > --- /dev/null > +++ b/lib/mbedtls/ecdsa.c > @@ -0,0 +1,152 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright (C) 2026 Philippe Reynes <[email protected]> > + */ > + > +#include <log.h> > +#include <linux/errno.h> > +#include <linux/string.h> > +#include <linux/types.h> > + > +#include <crypto/internal/ecdsa.h> > + > +#include "mbedtls_options.h" /* required to access private fields */ > +#include <mbedtls/ecdsa.h> > +#include <mbedtls/ecp.h> > + > +static mbedtls_ecp_group_id ecdsa_search_group_id(const char *curve_name) > +{ > + mbedtls_ecp_group_id grp_id = MBEDTLS_ECP_DP_NONE; > + const mbedtls_ecp_curve_info *info; > + > + if (!curve_name) > + return MBEDTLS_ECP_DP_NONE; > + > + /* > + * This curve name is read in the FIT metadata. > + * When this FIT metadata are filled by mkimage (or binman), > + * the curve name is the alias/name provided by OpenSSL. > + * And for secp256r1, OpenSSL uses the alias prime256v1. > + * So here, we have to manage this OpenSSL alias. > + */ > + if (!strcmp(curve_name, "prime256v1")) > + return MBEDTLS_ECP_DP_SECP256R1; > + > + info = mbedtls_ecp_curve_list(); > + while (info && info->name) { > + if (!strcmp(curve_name, info->name)) { > + grp_id = info->grp_id; > + break; > + } > + info++; > + } > + > + return grp_id; > +} > + > +int ecdsa_hash_verify(const struct ecdsa_public_key *pubkey, > + const void *hash, size_t hash_len, > + const void *signature, size_t sig_len) > +{ > + mbedtls_ecp_group_id grp_id; > + mbedtls_ecp_group grp; > + mbedtls_ecp_point Q; > + mbedtls_mpi r, s; > + int key_len; > + int err; > + > + key_len = DIV_ROUND_UP(pubkey->size_bits, 8); > + > + /* check the signature len */ > + if (sig_len != 2 * key_len) { > + log_debug("sig len should be twice the key len (sig len = > %zu, key len = %d)\n", > + sig_len, key_len); > + err = -EINVAL; > + goto out; > + } > + > + /* search the group */ > + grp_id = ecdsa_search_group_id(pubkey->curve_name); > + if (grp_id == MBEDTLS_ECP_DP_NONE) { > + log_debug("curve name %s not found\n", pubkey->curve_name); > + err = -EINVAL; > + goto out; > + } > + > + /* init and load the group */ > + mbedtls_ecp_group_init(&grp); > + err = mbedtls_ecp_group_load(&grp, grp_id); > + if (err) { > + err = -EINVAL; > + goto free_grp; > + } > + > + /* prepare the pubkey */ > + mbedtls_ecp_point_init(&Q); > + err = mbedtls_mpi_read_binary(&Q.X, pubkey->x, key_len); > + if (err) { > + log_debug("could not read value x of the public key (err = > %d)\n", > + err); > + err = -EINVAL; > + goto free_q; > + } > + err = mbedtls_mpi_read_binary(&Q.Y, pubkey->y, key_len); > + if (err) { > + log_debug("could not read value y of the public key (err = > %d)\n", > + err); > + err = -EINVAL; > + goto free_q; > + } > + err = mbedtls_mpi_lset(&Q.Z, 1); > + if (err) { > + log_debug("could not set value z of the public key (err = > %d)\n", > + err); > + err = -EINVAL; > + goto free_q; > + } > + > + /* check if the pubkey is valid */ > + err = mbedtls_ecp_check_pubkey(&grp, &Q); > + if (err) { > + log_debug("public key is invalid (err = %d)\n", err); > + err = -EKEYREJECTED; > + goto free_q; > + } > + > + /* compute r */ > + mbedtls_mpi_init(&r); > + err = mbedtls_mpi_read_binary(&r, signature, key_len); > + if (err) { > + log_debug("could not read value r of the signature (err = > %d)\n", > + err); > + err = -EINVAL; > + goto free_r; > + } > + > + /* compute s */ > + mbedtls_mpi_init(&s); > + err = mbedtls_mpi_read_binary(&s, signature + key_len, key_len); > + if (err) { > + log_debug("could not read value s of the signature (err = > %d)\n", > + err); > + err = -EINVAL; > + goto free_s; > + } > + > + /* check the signature */ > + err = mbedtls_ecdsa_verify(&grp, hash, hash_len, &Q, &r, &s); > + if (err) > + err = -EINVAL; > + > + free_s: > + mbedtls_mpi_free(&s); > + free_r: > + mbedtls_mpi_free(&r); > + free_q: > + mbedtls_ecp_point_free(&Q); > + free_grp: > + mbedtls_ecp_group_free(&grp); > + out: > + > + return err; > +} > -- > 2.43.0 >

