[PATCH v8 03/15] ecdsa: initial support of ecdsa using mbedtls

Raymond Mao raymondmaoca at gmail.com
Mon Jun 1 20:23:31 CEST 2026


Hi Philippe,

On Mon, Jun 1, 2026 at 9:43 AM Philippe Reynes
<philippe.reynes at softathome.com> wrote:
>
> Adds an initial support of ecdsa verify using mbedtls.
>
> Reviewed-by: Raymond Mao <raymondmaoca at gmail.com>
> Signed-off-by: Philippe Reynes <philippe.reynes at softathome.com>
> ---
> 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 <raymondmaoca at gmail.com>


> 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 <philippe.reynes at softathome.com>
> + */
> +#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 <philippe.reynes at softathome.com>
> + */
> +
> +#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
>


More information about the U-Boot mailing list