* [PATCH v5 01/15] ecdsa: fix support of secp521r1
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-22 0:11 ` Simon Glass
2026-04-22 18:32 ` Raymond Mao
2026-04-21 21:09 ` [PATCH v5 02/15] mbedtls: enable support of ecc Philippe Reynes
` (15 subsequent siblings)
16 siblings, 2 replies; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes
Current implementation of ecdsa only supports key len aligned on
8 bits. But the curve secp521r1 uses a key of 521 bits which is not
aligned on 8 bits. In this commit, we update the keys management
for ecdsa to support keys that are not aligned on 8 bits.
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v2:
- intitial version
v3:
- fix typo in comments
v4:
- fix commit message
- clean code with DIV_ROUND_UP-
- duplicate data before shifting
- support ecdsa521 and secp521r1
- clean code
v5:
- check that x and y are not null before using them
- free keys when keys not found
lib/ecdsa/ecdsa-libcrypto.c | 63 ++++++++++++++++++++++++++++++-
lib/ecdsa/ecdsa-verify.c | 75 +++++++++++++++++++++++++++++++++----
lib/fdt-libcrypto.c | 2 +-
tools/image-sig-host.c | 7 ++++
4 files changed, 137 insertions(+), 10 deletions(-)
diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c
index c4bfb2cec61..41590d22a51 100644
--- a/lib/ecdsa/ecdsa-libcrypto.c
+++ b/lib/ecdsa/ecdsa-libcrypto.c
@@ -26,6 +26,8 @@
#include <openssl/ec.h>
#include <openssl/bn.h>
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+
/* Image signing context for openssl-libcrypto */
struct signer {
EVP_PKEY *evp_key; /* Pointer to EVP_PKEY object */
@@ -41,10 +43,26 @@ struct ecdsa_public_key {
int size_bits;
};
+static char *memdup(char *buf, size_t size)
+{
+ char *dup;
+
+ dup = malloc(size);
+ if (dup)
+ memcpy(dup, buf, size);
+
+ return dup;
+}
+
static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node)
{
+ const char *x;
+ const char *y;
int x_len;
int y_len;
+ int expected_len;
+
+ memset(key, 0, sizeof(*key));
key->curve_name = fdt_getprop(fdt, node, "ecdsa,curve", NULL);
if (!key->curve_name)
@@ -54,6 +72,8 @@ static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node)
key->size_bits = 256;
else if (!strcmp(key->curve_name, "secp384r1"))
key->size_bits = 384;
+ else if (!strcmp(key->curve_name, "secp521r1"))
+ key->size_bits = 521;
else
return -EINVAL;
@@ -63,12 +83,43 @@ static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node)
if (!key->x || !key->y)
return -EINVAL;
- if (x_len != key->size_bits / 8 || y_len != key->size_bits / 8)
+ /*
+ * The public key is stored as an array of u32, so if the key size is
+ * not a multiple of 32 (for example 521), we may have extra bytes.
+ * To avoid any issue later, we shift the x and y pointer to the first
+ * useful byte.
+ */
+ expected_len = DIV_ROUND_UP(key->size_bits, 8);
+
+ if (x_len < expected_len || y_len < expected_len)
return -EINVAL;
+ x = memdup((char *)key->x + (x_len - expected_len), expected_len);
+ if (!x) {
+ fprintf(stderr, "Cannot allocate memory for point X");
+ return -ENOMEM;
+ }
+ key->x = (const uint8_t *)x;
+
+ y = memdup((char *)key->y + (y_len - expected_len), expected_len);
+ if (!y) {
+ fprintf(stderr, "Cannot allocate memory for point Y");
+ free((char *)x);
+ return -ENOMEM;
+ }
+ key->y = (const uint8_t *)y;
+
return 0;
}
+static void fdt_free_key(struct ecdsa_public_key *key)
+{
+ if (!key)
+ return;
+ free((char *)key->x);
+ free((char *)key->y);
+}
+
static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node)
{
struct ecdsa_public_key pubkey;
@@ -89,8 +140,11 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node)
nid = NID_X9_62_prime256v1;
} else if (!strcmp(pubkey.curve_name, "secp384r1")) {
nid = NID_secp384r1;
+ } else if (!strcmp(pubkey.curve_name, "secp521r1")) {
+ nid = NID_secp521r1;
} else {
fprintf(stderr, "Unsupported curve name: '%s'\n", pubkey.curve_name);
+ fdt_free_key(&pubkey);
return -EINVAL;
}
@@ -100,6 +154,7 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node)
ec_key = EC_KEY_new_by_curve_name(nid);
if (!ec_key) {
fprintf(stderr, "Failed to allocate EC_KEY for curve %s\n", pubkey.curve_name);
+ fdt_free_key(&pubkey);
return -ENOMEM;
}
@@ -108,10 +163,11 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node)
if (!point) {
fprintf(stderr, "Failed to allocate EC_POINT\n");
EC_KEY_free(ec_key);
+ fdt_free_key(&pubkey);
return -ENOMEM;
}
- len = pubkey.size_bits / 8;
+ len = DIV_ROUND_UP(pubkey.size_bits, 8);
uint8_t buf[1 + len * 2];
@@ -123,6 +179,7 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node)
fprintf(stderr, "Failed to convert (x,y) point to EC_POINT\n");
EC_POINT_free(point);
EC_KEY_free(ec_key);
+ fdt_free_key(&pubkey);
return -EINVAL;
}
@@ -130,11 +187,13 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node)
fprintf(stderr, "Failed to set EC_POINT as public key\n");
EC_POINT_free(point);
EC_KEY_free(ec_key);
+ fdt_free_key(&pubkey);
return -EINVAL;
}
fprintf(stderr, "Successfully loaded ECDSA key from FDT node %d\n", node);
EC_POINT_free(point);
+ fdt_free_key(&pubkey);
ctx->ecdsa_key = ec_key;
return 0;
diff --git a/lib/ecdsa/ecdsa-verify.c b/lib/ecdsa/ecdsa-verify.c
index 629b662cf6c..e503627f490 100644
--- a/lib/ecdsa/ecdsa-verify.c
+++ b/lib/ecdsa/ecdsa-verify.c
@@ -10,6 +10,7 @@
#include <crypto/ecdsa-uclass.h>
#include <dm/uclass.h>
+#include <malloc.h>
#include <u-boot/ecdsa.h>
/*
@@ -24,13 +25,19 @@ static int ecdsa_key_size(const char *curve_name)
return 256;
else if (!strcmp(curve_name, "secp384r1"))
return 384;
+ else if (!strcmp(curve_name, "secp521r1"))
+ return 521;
return 0;
}
static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node)
{
- int x_len, y_len;
+ int expected_len, x_len, y_len;
+ const char *x;
+ const char *y;
+
+ memset(key, 0, sizeof(*key));
key->curve_name = fdt_getprop(fdt, node, "ecdsa,curve", NULL);
if (!key->curve_name) {
@@ -50,15 +57,46 @@ static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node)
if (!key->x || !key->y)
return -EINVAL;
- if (x_len != (key->size_bits / 8) || y_len != (key->size_bits / 8)) {
+ /*
+ * The public key is stored as an array of u32, so if the key size is
+ * not a multiple of 32 (for example 521), we may have extra bytes.
+ * To avoid any issue later, we shift the x and y pointer to the first
+ * useful byte.
+ */
+ expected_len = DIV_ROUND_UP(key->size_bits, 8);
+
+ if (x_len < expected_len || y_len < expected_len) {
printf("%s: node=%d, curve@%p x@%p+%i y@%p+%i\n", __func__,
node, key->curve_name, key->x, x_len, key->y, y_len);
return -EINVAL;
}
+ x = memdup((char *)key->x + (x_len - expected_len), expected_len);
+ if (!x) {
+ debug("Cannot allocate memory for point X");
+ return -ENOMEM;
+ }
+ key->x = (const uint8_t *)x;
+
+ y = memdup((char *)key->y + (y_len - expected_len), expected_len);
+ if (!y) {
+ debug("Cannot allocate memory for point Y");
+ free((char *)x);
+ return -ENOMEM;
+ }
+ key->y = (const uint8_t *)y;
+
return 0;
}
+static void fdt_free_key(struct ecdsa_public_key *key)
+{
+ if (!key)
+ return;
+ free((char *)key->x);
+ free((char *)key->y);
+}
+
static int ecdsa_verify_hash(struct udevice *dev,
const struct image_sign_info *info,
const void *hash, const void *sig, uint sig_len)
@@ -73,11 +111,16 @@ static int ecdsa_verify_hash(struct udevice *dev,
if (info->required_keynode > 0) {
ret = fdt_get_key(&key, info->fdt_blob, info->required_keynode);
- if (ret < 0)
+ if (ret < 0) {
+ fdt_free_key(&key);
return ret;
+ }
+
+ ret = ops->verify(dev, &key, hash, algo->checksum_len,
+ sig, sig_len);
+ fdt_free_key(&key);
- return ops->verify(dev, &key, hash, algo->checksum_len,
- sig, sig_len);
+ return ret;
}
sig_node = fdt_subnode_offset(info->fdt_blob, 0, FIT_SIG_NODENAME);
@@ -87,15 +130,21 @@ static int ecdsa_verify_hash(struct udevice *dev,
/* Try all possible keys under the "/signature" node */
fdt_for_each_subnode(key_node, info->fdt_blob, sig_node) {
ret = fdt_get_key(&key, info->fdt_blob, key_node);
- if (ret < 0)
+ if (ret < 0) {
+ fdt_free_key(&key);
continue;
+ }
ret = ops->verify(dev, &key, hash, algo->checksum_len,
sig, sig_len);
/* On success, don't worry about remaining keys */
- if (!ret)
+ if (!ret) {
+ fdt_free_key(&key);
return 0;
+ }
+
+ fdt_free_key(&key);
}
return -EPERM;
@@ -135,6 +184,18 @@ U_BOOT_CRYPTO_ALGO(ecdsa384) = {
.verify = ecdsa_verify,
};
+U_BOOT_CRYPTO_ALGO(ecdsa521) = {
+ .name = "ecdsa521",
+ .key_len = ECDSA521_BYTES,
+ .verify = ecdsa_verify,
+};
+
+U_BOOT_CRYPTO_ALGO(secp521r1) = {
+ .name = "secp521r1",
+ .key_len = ECDSA521_BYTES,
+ .verify = ecdsa_verify,
+};
+
/*
* uclass definition for ECDSA API
*
diff --git a/lib/fdt-libcrypto.c b/lib/fdt-libcrypto.c
index ecb0344c8f6..090246b44e9 100644
--- a/lib/fdt-libcrypto.c
+++ b/lib/fdt-libcrypto.c
@@ -10,7 +10,7 @@
int fdt_add_bignum(void *blob, int noffset, const char *prop_name,
BIGNUM *num, int num_bits)
{
- int nwords = num_bits / 32;
+ int nwords = (num_bits + 31) / 32;
int size;
uint32_t *buf, *ptr;
BIGNUM *tmp, *big2, *big32, *big2_32;
diff --git a/tools/image-sig-host.c b/tools/image-sig-host.c
index 5285263c616..285547994ca 100644
--- a/tools/image-sig-host.c
+++ b/tools/image-sig-host.c
@@ -83,6 +83,13 @@ struct crypto_algo crypto_algos[] = {
.add_verify_data = ecdsa_add_verify_data,
.verify = ecdsa_verify,
},
+ {
+ .name = "ecdsa521",
+ .key_len = ECDSA521_BYTES,
+ .sign = ecdsa_sign,
+ .add_verify_data = ecdsa_add_verify_data,
+ .verify = ecdsa_verify,
+ },
{
.name = "secp521r1",
.key_len = ECDSA521_BYTES,
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [PATCH v5 01/15] ecdsa: fix support of secp521r1
2026-04-21 21:09 ` [PATCH v5 01/15] ecdsa: fix support of secp521r1 Philippe Reynes
@ 2026-04-22 0:11 ` Simon Glass
2026-04-22 18:32 ` Raymond Mao
1 sibling, 0 replies; 29+ messages in thread
From: Simon Glass @ 2026-04-22 0:11 UTC (permalink / raw)
To: philippe.reynes
Cc: marko.makela, jonny.green, raymondmaoca, trini, simon.glass,
u-boot
Hi Philippe,
On 2026-04-21T21:09:51, Philippe Reynes <philippe.reynes@softathome.com> wrote:
> ecdsa: fix support of secp521r1
>
> Current implementation of ecdsa only supports key len aligned on
> 8 bits. But the curve secp521r1 uses a key of 521 bits which is not
> aligned on 8 bits. In this commit, we update the keys management
> for ecdsa to support keys that are not aligned on 8 bits.
>
> Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
>
> lib/ecdsa/ecdsa-libcrypto.c | 63 +++++++++++++++++++++++++++++++++++--
> lib/ecdsa/ecdsa-verify.c | 75 ++++++++++++++++++++++++++++++++++++++++-----
> lib/fdt-libcrypto.c | 2 +-
> tools/image-sig-host.c | 7 +++++
> 4 files changed, 137 insertions(+), 10 deletions(-)
> diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c
> @@ -26,6 +26,8 @@
> +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
DIV_ROUND_UP is already defined in include/linux/kernel.h. Please can
you include that header instead.
> diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c
> @@ -41,10 +43,26 @@ struct ecdsa_public_key {
> +static char *memdup(char *buf, size_t size)
> +{
> + char *dup;
> +
> + dup = malloc(size);
> + if (dup)
> + memcpy(dup, buf, size);
> +
> + return dup;
> +}
A global memdup() exists in lib/string.c (declared in
include/linux/string.h). Please can you use that instead to avoid
conflicts.
> diff --git a/lib/ecdsa/ecdsa-verify.c b/lib/ecdsa/ecdsa-verify.c
> @@ -73,11 +111,16 @@ static int ecdsa_verify_hash(struct udevice *dev,
> if (info->required_keynode > 0) {
> ret = fdt_get_key(&key, info->fdt_blob, info->required_keynode);
> - if (ret < 0)
> + if (ret < 0) {
> + fdt_free_key(&key);
> return ret;
> + }
Calling fdt_free_key() after fdt_get_key() fails is unnecessary. When
fdt_get_key() returns early, key->x and key->y may be uninitialised.
Please can you remove the fdt_free_key() call in this error path.
> diff --git a/lib/ecdsa/ecdsa-verify.c b/lib/ecdsa/ecdsa-verify.c
> @@ -87,15 +130,21 @@ static int ecdsa_verify_hash(struct udevice *dev,
> fdt_for_each_subnode(key_node, info->fdt_blob, sig_node) {
> ret = fdt_get_key(&key, info->fdt_blob, key_node);
> - if (ret < 0)
> + if (ret < 0) {
> + fdt_free_key(&key);
> continue;
> + }
Same issue here.
> diff --git a/lib/ecdsa/ecdsa-verify.c b/lib/ecdsa/ecdsa-verify.c
> @@ -135,6 +184,18 @@ U_BOOT_CRYPTO_ALGO(ecdsa384) = {
> +U_BOOT_CRYPTO_ALGO(secp521r1) = {
> + .name = 'secp521r1',
> + .key_len = ECDSA521_BYTES,
> + .verify = ecdsa_verify,
> +};
Just to check — why add secp521r1 as an alias for ecdsa521 but not
secp256r1/secp384r1 for the other curves?
Regards,
Simon
^ permalink raw reply [flat|nested] 29+ messages in thread* Re: [PATCH v5 01/15] ecdsa: fix support of secp521r1
2026-04-21 21:09 ` [PATCH v5 01/15] ecdsa: fix support of secp521r1 Philippe Reynes
2026-04-22 0:11 ` Simon Glass
@ 2026-04-22 18:32 ` Raymond Mao
2026-05-16 17:09 ` Marko Mäkelä
1 sibling, 1 reply; 29+ messages in thread
From: Raymond Mao @ 2026-04-22 18:32 UTC (permalink / raw)
To: Philippe Reynes; +Cc: marko.makela, jonny.green, trini, simon.glass, u-boot
Hi Philippe,
On Tue, Apr 21, 2026 at 5:10 PM Philippe Reynes
<philippe.reynes@softathome.com> wrote:
>
> Current implementation of ecdsa only supports key len aligned on
> 8 bits. But the curve secp521r1 uses a key of 521 bits which is not
> aligned on 8 bits. In this commit, we update the keys management
> for ecdsa to support keys that are not aligned on 8 bits.
>
> Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
> ---
> v2:
> - intitial version
> v3:
> - fix typo in comments
> v4:
> - fix commit message
> - clean code with DIV_ROUND_UP-
> - duplicate data before shifting
> - support ecdsa521 and secp521r1
> - clean code
> v5:
> - check that x and y are not null before using them
> - free keys when keys not found
>
> lib/ecdsa/ecdsa-libcrypto.c | 63 ++++++++++++++++++++++++++++++-
> lib/ecdsa/ecdsa-verify.c | 75 +++++++++++++++++++++++++++++++++----
> lib/fdt-libcrypto.c | 2 +-
> tools/image-sig-host.c | 7 ++++
> 4 files changed, 137 insertions(+), 10 deletions(-)
>
> diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c
> index c4bfb2cec61..41590d22a51 100644
> --- a/lib/ecdsa/ecdsa-libcrypto.c
> +++ b/lib/ecdsa/ecdsa-libcrypto.c
> @@ -26,6 +26,8 @@
> #include <openssl/ec.h>
> #include <openssl/bn.h>
>
> +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
> +
> /* Image signing context for openssl-libcrypto */
> struct signer {
> EVP_PKEY *evp_key; /* Pointer to EVP_PKEY object */
> @@ -41,10 +43,26 @@ struct ecdsa_public_key {
> int size_bits;
> };
>
> +static char *memdup(char *buf, size_t size)
> +{
> + char *dup;
> +
> + dup = malloc(size);
> + if (dup)
> + memcpy(dup, buf, size);
> +
> + return dup;
> +}
> +
> static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node)
> {
> + const char *x;
> + const char *y;
> int x_len;
> int y_len;
> + int expected_len;
> +
> + memset(key, 0, sizeof(*key));
>
> key->curve_name = fdt_getprop(fdt, node, "ecdsa,curve", NULL);
> if (!key->curve_name)
> @@ -54,6 +72,8 @@ static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node)
> key->size_bits = 256;
> else if (!strcmp(key->curve_name, "secp384r1"))
> key->size_bits = 384;
> + else if (!strcmp(key->curve_name, "secp521r1"))
> + key->size_bits = 521;
> else
> return -EINVAL;
>
> @@ -63,12 +83,43 @@ static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node)
> if (!key->x || !key->y)
> return -EINVAL;
>
> - if (x_len != key->size_bits / 8 || y_len != key->size_bits / 8)
> + /*
> + * The public key is stored as an array of u32, so if the key size is
> + * not a multiple of 32 (for example 521), we may have extra bytes.
> + * To avoid any issue later, we shift the x and y pointer to the first
> + * useful byte.
> + */
> + expected_len = DIV_ROUND_UP(key->size_bits, 8);
> +
> + if (x_len < expected_len || y_len < expected_len)
> return -EINVAL;
>
> + x = memdup((char *)key->x + (x_len - expected_len), expected_len);
> + if (!x) {
> + fprintf(stderr, "Cannot allocate memory for point X");
> + return -ENOMEM;
> + }
> + key->x = (const uint8_t *)x;
> +
> + y = memdup((char *)key->y + (y_len - expected_len), expected_len);
> + if (!y) {
> + fprintf(stderr, "Cannot allocate memory for point Y");
> + free((char *)x);
> + return -ENOMEM;
> + }
> + key->y = (const uint8_t *)y;
> +
> return 0;
> }
>
> +static void fdt_free_key(struct ecdsa_public_key *key)
> +{
> + if (!key)
> + return;
> + free((char *)key->x);
It is safer to be:
if (key->x)
free((char *)key->x);
> + free((char *)key->y);
Ditto.
> +}
> +
> static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node)
> {
> struct ecdsa_public_key pubkey;
> @@ -89,8 +140,11 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node)
> nid = NID_X9_62_prime256v1;
> } else if (!strcmp(pubkey.curve_name, "secp384r1")) {
> nid = NID_secp384r1;
> + } else if (!strcmp(pubkey.curve_name, "secp521r1")) {
> + nid = NID_secp521r1;
> } else {
> fprintf(stderr, "Unsupported curve name: '%s'\n", pubkey.curve_name);
> + fdt_free_key(&pubkey);
> return -EINVAL;
> }
>
> @@ -100,6 +154,7 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node)
> ec_key = EC_KEY_new_by_curve_name(nid);
> if (!ec_key) {
> fprintf(stderr, "Failed to allocate EC_KEY for curve %s\n", pubkey.curve_name);
> + fdt_free_key(&pubkey);
> return -ENOMEM;
> }
>
> @@ -108,10 +163,11 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node)
> if (!point) {
> fprintf(stderr, "Failed to allocate EC_POINT\n");
> EC_KEY_free(ec_key);
> + fdt_free_key(&pubkey);
> return -ENOMEM;
> }
>
> - len = pubkey.size_bits / 8;
> + len = DIV_ROUND_UP(pubkey.size_bits, 8);
>
> uint8_t buf[1 + len * 2];
>
> @@ -123,6 +179,7 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node)
> fprintf(stderr, "Failed to convert (x,y) point to EC_POINT\n");
> EC_POINT_free(point);
> EC_KEY_free(ec_key);
> + fdt_free_key(&pubkey);
> return -EINVAL;
> }
>
> @@ -130,11 +187,13 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node)
> fprintf(stderr, "Failed to set EC_POINT as public key\n");
> EC_POINT_free(point);
> EC_KEY_free(ec_key);
> + fdt_free_key(&pubkey);
> return -EINVAL;
> }
>
> fprintf(stderr, "Successfully loaded ECDSA key from FDT node %d\n", node);
> EC_POINT_free(point);
> + fdt_free_key(&pubkey);
> ctx->ecdsa_key = ec_key;
>
> return 0;
> diff --git a/lib/ecdsa/ecdsa-verify.c b/lib/ecdsa/ecdsa-verify.c
> index 629b662cf6c..e503627f490 100644
> --- a/lib/ecdsa/ecdsa-verify.c
> +++ b/lib/ecdsa/ecdsa-verify.c
> @@ -10,6 +10,7 @@
>
> #include <crypto/ecdsa-uclass.h>
> #include <dm/uclass.h>
> +#include <malloc.h>
> #include <u-boot/ecdsa.h>
>
> /*
> @@ -24,13 +25,19 @@ static int ecdsa_key_size(const char *curve_name)
> return 256;
> else if (!strcmp(curve_name, "secp384r1"))
> return 384;
> + else if (!strcmp(curve_name, "secp521r1"))
> + return 521;
>
> return 0;
> }
>
> static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node)
> {
> - int x_len, y_len;
> + int expected_len, x_len, y_len;
> + const char *x;
> + const char *y;
> +
> + memset(key, 0, sizeof(*key));
>
> key->curve_name = fdt_getprop(fdt, node, "ecdsa,curve", NULL);
> if (!key->curve_name) {
> @@ -50,15 +57,46 @@ static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node)
> if (!key->x || !key->y)
> return -EINVAL;
>
> - if (x_len != (key->size_bits / 8) || y_len != (key->size_bits / 8)) {
> + /*
> + * The public key is stored as an array of u32, so if the key size is
> + * not a multiple of 32 (for example 521), we may have extra bytes.
> + * To avoid any issue later, we shift the x and y pointer to the first
> + * useful byte.
> + */
> + expected_len = DIV_ROUND_UP(key->size_bits, 8);
> +
> + if (x_len < expected_len || y_len < expected_len) {
> printf("%s: node=%d, curve@%p x@%p+%i y@%p+%i\n", __func__,
> node, key->curve_name, key->x, x_len, key->y, y_len);
> return -EINVAL;
> }
>
> + x = memdup((char *)key->x + (x_len - expected_len), expected_len);
> + if (!x) {
> + debug("Cannot allocate memory for point X");
> + return -ENOMEM;
> + }
> + key->x = (const uint8_t *)x;
> +
> + y = memdup((char *)key->y + (y_len - expected_len), expected_len);
> + if (!y) {
> + debug("Cannot allocate memory for point Y");
> + free((char *)x);
> + return -ENOMEM;
> + }
> + key->y = (const uint8_t *)y;
> +
> return 0;
> }
>
> +static void fdt_free_key(struct ecdsa_public_key *key)
> +{
> + if (!key)
> + return;
> + free((char *)key->x);
> + free((char *)key->y);
> +}
> +
> static int ecdsa_verify_hash(struct udevice *dev,
> const struct image_sign_info *info,
> const void *hash, const void *sig, uint sig_len)
> @@ -73,11 +111,16 @@ static int ecdsa_verify_hash(struct udevice *dev,
>
> if (info->required_keynode > 0) {
> ret = fdt_get_key(&key, info->fdt_blob, info->required_keynode);
> - if (ret < 0)
> + if (ret < 0) {
> + fdt_free_key(&key);
> return ret;
> + }
> +
> + ret = ops->verify(dev, &key, hash, algo->checksum_len,
> + sig, sig_len);
> + fdt_free_key(&key);
>
> - return ops->verify(dev, &key, hash, algo->checksum_len,
> - sig, sig_len);
> + return ret;
> }
>
> sig_node = fdt_subnode_offset(info->fdt_blob, 0, FIT_SIG_NODENAME);
> @@ -87,15 +130,21 @@ static int ecdsa_verify_hash(struct udevice *dev,
> /* Try all possible keys under the "/signature" node */
> fdt_for_each_subnode(key_node, info->fdt_blob, sig_node) {
> ret = fdt_get_key(&key, info->fdt_blob, key_node);
> - if (ret < 0)
> + if (ret < 0) {
'if (ret)' is fine. Moreover, when fdt_get_key() returns a non-zero
value, the key is already free.
> + fdt_free_key(&key);
> continue;
> + }
>
> ret = ops->verify(dev, &key, hash, algo->checksum_len,
> sig, sig_len);
>
> /* On success, don't worry about remaining keys */
> - if (!ret)
> + if (!ret) {
> + fdt_free_key(&key);
> return 0;
> + }
> +
> + fdt_free_key(&key);
Above few lines can be simplified as:
```
fdt_free_key(&key);
if (!ret)
return 0;
```
Regards,
Raymond
> }
>
> return -EPERM;
> @@ -135,6 +184,18 @@ U_BOOT_CRYPTO_ALGO(ecdsa384) = {
> .verify = ecdsa_verify,
> };
>
> +U_BOOT_CRYPTO_ALGO(ecdsa521) = {
> + .name = "ecdsa521",
> + .key_len = ECDSA521_BYTES,
> + .verify = ecdsa_verify,
> +};
> +
> +U_BOOT_CRYPTO_ALGO(secp521r1) = {
> + .name = "secp521r1",
> + .key_len = ECDSA521_BYTES,
> + .verify = ecdsa_verify,
> +};
> +
> /*
> * uclass definition for ECDSA API
> *
> diff --git a/lib/fdt-libcrypto.c b/lib/fdt-libcrypto.c
> index ecb0344c8f6..090246b44e9 100644
> --- a/lib/fdt-libcrypto.c
> +++ b/lib/fdt-libcrypto.c
> @@ -10,7 +10,7 @@
> int fdt_add_bignum(void *blob, int noffset, const char *prop_name,
> BIGNUM *num, int num_bits)
> {
> - int nwords = num_bits / 32;
> + int nwords = (num_bits + 31) / 32;
> int size;
> uint32_t *buf, *ptr;
> BIGNUM *tmp, *big2, *big32, *big2_32;
> diff --git a/tools/image-sig-host.c b/tools/image-sig-host.c
> index 5285263c616..285547994ca 100644
> --- a/tools/image-sig-host.c
> +++ b/tools/image-sig-host.c
> @@ -83,6 +83,13 @@ struct crypto_algo crypto_algos[] = {
> .add_verify_data = ecdsa_add_verify_data,
> .verify = ecdsa_verify,
> },
> + {
> + .name = "ecdsa521",
> + .key_len = ECDSA521_BYTES,
> + .sign = ecdsa_sign,
> + .add_verify_data = ecdsa_add_verify_data,
> + .verify = ecdsa_verify,
> + },
> {
> .name = "secp521r1",
> .key_len = ECDSA521_BYTES,
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 29+ messages in thread* Re: [PATCH v5 01/15] ecdsa: fix support of secp521r1
2026-04-22 18:32 ` Raymond Mao
@ 2026-05-16 17:09 ` Marko Mäkelä
2026-05-20 23:04 ` Simon Glass
0 siblings, 1 reply; 29+ messages in thread
From: Marko Mäkelä @ 2026-05-16 17:09 UTC (permalink / raw)
To: Raymond Mao; +Cc: Philippe Reynes, jonny.green, trini, simon.glass, u-boot
Hi Philippe, Raymond, all,
Wed, Apr 22, 2026 at 02:32:22PM -0400, Raymond Mao wrote:
>Hi Philippe,
>
>On Tue, Apr 21, 2026 at 5:10 PM Philippe Reynes
><philippe.reynes@softathome.com> wrote:
>>
>> Current implementation of ecdsa only supports key len aligned on
>> 8 bits. But the curve secp521r1 uses a key of 521 bits which is not
>> aligned on 8 bits. In this commit, we update the keys management
>> for ecdsa to support keys that are not aligned on 8 bits.
>>
>> Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
[snip]
>> +static void fdt_free_key(struct ecdsa_public_key *key)
>> +{
>> + if (!key)
>> + return;
>> + free((char *)key->x);
>
>It is safer to be:
>if (key->x)
> free((char *)key->x);
>
>> + free((char *)key->y);
>
>Ditto.
Sorry, did I understand correctly that you are requesting to add
redundant checks to prevent invocations of free() on a NULL pointer?
The C standard specifies that free(NULL) has no effect. The
implementation fREe_impl() in common/dlmalloc.c documents this as well.
I think that we should aim for minimal code size.
With best regards,
Marko
^ permalink raw reply [flat|nested] 29+ messages in thread* Re: [PATCH v5 01/15] ecdsa: fix support of secp521r1
2026-05-16 17:09 ` Marko Mäkelä
@ 2026-05-20 23:04 ` Simon Glass
0 siblings, 0 replies; 29+ messages in thread
From: Simon Glass @ 2026-05-20 23:04 UTC (permalink / raw)
To: Marko Mäkelä
Cc: Raymond Mao, Philippe Reynes, jonny.green, trini, simon.glass,
u-boot
Hi Marko,
On Sat, 16 May 2026 at 12:09, Marko Mäkelä <marko.makela@iki.fi> wrote:
>
> Hi Philippe, Raymond, all,
>
> Wed, Apr 22, 2026 at 02:32:22PM -0400, Raymond Mao wrote:
> >Hi Philippe,
> >
> >On Tue, Apr 21, 2026 at 5:10 PM Philippe Reynes
> ><philippe.reynes@softathome.com> wrote:
> >>
> >> Current implementation of ecdsa only supports key len aligned on
> >> 8 bits. But the curve secp521r1 uses a key of 521 bits which is not
> >> aligned on 8 bits. In this commit, we update the keys management
> >> for ecdsa to support keys that are not aligned on 8 bits.
> >>
> >> Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
>
> [snip]
>
> >> +static void fdt_free_key(struct ecdsa_public_key *key)
> >> +{
> >> + if (!key)
> >> + return;
> >> + free((char *)key->x);
> >
> >It is safer to be:
> >if (key->x)
> > free((char *)key->x);
> >
> >> + free((char *)key->y);
> >
> >Ditto.
>
> Sorry, did I understand correctly that you are requesting to add
> redundant checks to prevent invocations of free() on a NULL pointer?
>
> The C standard specifies that free(NULL) has no effect. The
> implementation fREe_impl() in common/dlmalloc.c documents this as well.
> I think that we should aim for minimal code size.
Yes, good point. It is a bit strange to make fdt_free_key() handle a
NULL arg though. I'll leave it up to you.
Regards,
Simon
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v5 02/15] mbedtls: enable support of ecc
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
2026-04-21 21:09 ` [PATCH v5 01/15] ecdsa: fix support of secp521r1 Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-22 0:10 ` Simon Glass
2026-04-22 18:15 ` Raymond Mao
2026-04-21 21:09 ` [PATCH v5 03/15] ecdsa: initial support of ecdsa using mbedtls Philippe Reynes
` (14 subsequent siblings)
16 siblings, 2 replies; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes
Enables the support of ecc in mbedtls.
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v2:
- move ecdsa to MBEDTLS_LIB_X509
- enhance depencendies
v3:
- do not use _MBEDTLS in mbedtls_def_config.h
v4:
- do not select ECDSA on some configs
- remove duplicated MBEDTLS_ECP_DP_SECP256K1_ENABLED
- change dependencies for ECDSA configs
v5:
- MBEDTLS_LIB_TLS depends en ECDSA_MBEDTLS
- update some configs according to previous change
- build of ecdsa is conditionned by ECDSA_MBEDTLS
configs/amd_versal2_virt_defconfig | 3 +++
configs/qemu_arm64_lwip_defconfig | 3 +++
configs/sandbox_defconfig | 1 +
configs/starfive_visionfive2_defconfig | 3 +++
configs/xilinx_versal_net_virt_defconfig | 3 +++
configs/xilinx_versal_virt_defconfig | 3 +++
configs/xilinx_zynqmp_kria_defconfig | 3 +++
configs/xilinx_zynqmp_virt_defconfig | 3 +++
lib/ecdsa/Kconfig | 1 +
lib/mbedtls/Kconfig | 14 ++++++++++++++
lib/mbedtls/Makefile | 16 +++++++++-------
lib/mbedtls/mbedtls_def_config.h | 17 +++++++++++++++++
12 files changed, 63 insertions(+), 7 deletions(-)
diff --git a/configs/amd_versal2_virt_defconfig b/configs/amd_versal2_virt_defconfig
index 0f4b75c72e1..cbc0789d5b3 100644
--- a/configs/amd_versal2_virt_defconfig
+++ b/configs/amd_versal2_virt_defconfig
@@ -167,6 +167,9 @@ CONFIG_VIRTIO_MMIO=y
CONFIG_VIRTIO_NET=y
CONFIG_VIRTIO_BLK=y
CONFIG_MBEDTLS_LIB=y
+CONFIG_ECDSA_MBEDTLS=y
+CONFIG_ECDSA=y
+CONFIG_ECDSA_VERIFY=y
CONFIG_TPM=y
# CONFIG_OPTEE_LIB is not set
CONFIG_TOOLS_MKFWUMDATA=y
diff --git a/configs/qemu_arm64_lwip_defconfig b/configs/qemu_arm64_lwip_defconfig
index a974970c3d3..151506eaca2 100644
--- a/configs/qemu_arm64_lwip_defconfig
+++ b/configs/qemu_arm64_lwip_defconfig
@@ -3,6 +3,9 @@
CONFIG_ARM=y
CONFIG_ARCH_QEMU=y
+CONFIG_ECDSA=y
+CONFIG_ECDSA_VERIFY=y
+CONFIG_ECDSA_MBEDTLS=y
CONFIG_NET_LWIP=y
CONFIG_CMD_DNS=y
CONFIG_CMD_NFS=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index f26295103f1..15831dd7e04 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -391,6 +391,7 @@ CONFIG_PANIC_HANG=y
CONFIG_CMD_DHRYSTONE=y
CONFIG_MBEDTLS_LIB=y
CONFIG_HKDF_MBEDTLS=y
+CONFIG_ECDSA_MBEDTLS=y
CONFIG_ECDSA=y
CONFIG_ECDSA_VERIFY=y
CONFIG_RSASSA_PSS=y
diff --git a/configs/starfive_visionfive2_defconfig b/configs/starfive_visionfive2_defconfig
index 74a24dfd074..77b3146f6cb 100644
--- a/configs/starfive_visionfive2_defconfig
+++ b/configs/starfive_visionfive2_defconfig
@@ -156,3 +156,6 @@ CONFIG_USB_GADGET=y
CONFIG_WDT=y
CONFIG_WDT_STARFIVE=y
CONFIG_MBEDTLS_LIB=y
+CONFIG_ECDSA_MBEDTLS=y
+CONFIG_ECDSA=y
+CONFIG_ECDSA_VERIFY=y
diff --git a/configs/xilinx_versal_net_virt_defconfig b/configs/xilinx_versal_net_virt_defconfig
index 3410b874a04..90c04b98e0d 100644
--- a/configs/xilinx_versal_net_virt_defconfig
+++ b/configs/xilinx_versal_net_virt_defconfig
@@ -155,4 +155,7 @@ CONFIG_VIRTIO_MMIO=y
CONFIG_VIRTIO_NET=y
CONFIG_VIRTIO_BLK=y
CONFIG_MBEDTLS_LIB=y
+CONFIG_ECDSA_MBEDTLS=y
+CONFIG_ECDSA=y
+CONFIG_ECDSA_VERIFY=y
CONFIG_TPM=y
diff --git a/configs/xilinx_versal_virt_defconfig b/configs/xilinx_versal_virt_defconfig
index d5d60d7f87d..bd3e368d1b4 100644
--- a/configs/xilinx_versal_virt_defconfig
+++ b/configs/xilinx_versal_virt_defconfig
@@ -170,5 +170,8 @@ CONFIG_VIRTIO_MMIO=y
CONFIG_VIRTIO_NET=y
CONFIG_VIRTIO_BLK=y
CONFIG_MBEDTLS_LIB=y
+CONFIG_ECDSA_MBEDTLS=y
+CONFIG_ECDSA=y
+CONFIG_ECDSA_VERIFY=y
CONFIG_TPM=y
CONFIG_TOOLS_MKFWUMDATA=y
diff --git a/configs/xilinx_zynqmp_kria_defconfig b/configs/xilinx_zynqmp_kria_defconfig
index 72a4668b448..7a741416685 100644
--- a/configs/xilinx_zynqmp_kria_defconfig
+++ b/configs/xilinx_zynqmp_kria_defconfig
@@ -221,6 +221,9 @@ CONFIG_VIRTIO_BLK=y
CONFIG_BINMAN_DTB="./arch/arm/dts/zynqmp-binman-som.dtb"
CONFIG_PANIC_HANG=y
CONFIG_MBEDTLS_LIB=y
+CONFIG_ECDSA_MBEDTLS=y
+CONFIG_ECDSA=y
+CONFIG_ECDSA_VERIFY=y
CONFIG_TPM=y
CONFIG_SPL_GZIP=y
CONFIG_TOOLS_MKFWUMDATA=y
diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig
index 1433b63979a..7dd73c48c1b 100644
--- a/configs/xilinx_zynqmp_virt_defconfig
+++ b/configs/xilinx_zynqmp_virt_defconfig
@@ -239,6 +239,9 @@ CONFIG_VIRTIO_BLK=y
CONFIG_BINMAN_DTB="./arch/arm/dts/zynqmp-binman.dtb"
CONFIG_PANIC_HANG=y
CONFIG_MBEDTLS_LIB=y
+CONFIG_ECDSA_MBEDTLS=y
+CONFIG_ECDSA=y
+CONFIG_ECDSA_VERIFY=y
CONFIG_TPM=y
CONFIG_SPL_GZIP=y
CONFIG_TOOLS_MKFWUMDATA=y
diff --git a/lib/ecdsa/Kconfig b/lib/ecdsa/Kconfig
index ca13b6bfa1f..dac8bcf23dd 100644
--- a/lib/ecdsa/Kconfig
+++ b/lib/ecdsa/Kconfig
@@ -1,6 +1,7 @@
config ECDSA
bool "Enable ECDSA support"
depends on DM
+ select ASN1_DECODER
help
This enables the ECDSA (elliptic curve signature) algorithm for FIT
image verification in U-Boot. The ECDSA algorithm is implemented
diff --git a/lib/mbedtls/Kconfig b/lib/mbedtls/Kconfig
index 789721ee6cd..e948a8876f6 100644
--- a/lib/mbedtls/Kconfig
+++ b/lib/mbedtls/Kconfig
@@ -247,6 +247,9 @@ config MBEDTLS_LIB_X509
if MBEDTLS_LIB_X509
+config BIGNUM_MBEDTLS
+ bool
+
config ASN1_DECODER_MBEDTLS
bool "ASN1 decoder with MbedTLS certificate library"
depends on MBEDTLS_LIB_X509 && ASN1_DECODER
@@ -264,6 +267,7 @@ config RSA_PUBLIC_KEY_PARSER_MBEDTLS
bool "RSA public key parser with MbedTLS certificate library"
depends on ASYMMETRIC_PUBLIC_KEY_MBEDTLS
select ASN1_DECODER_MBEDTLS
+ select BIGNUM_MBEDTLS
help
This option chooses MbedTLS certificate library for RSA public key
parser.
@@ -292,6 +296,15 @@ config MSCODE_PARSER_MBEDTLS
This option chooses MbedTLS certificate library for MS authenticode
parser.
+config ECDSA_MBEDTLS
+ bool "Enable ECDSA support with MbedTLS certificate library"
+ depends on MBEDTLS_LIB_X509 && ECDSA_VERIFY
+ select ASN1_DECODER_MBEDTLS if ASN1_DECODER
+ select BIGNUM_MBEDTLS
+ help
+ This option enables support of ECDSA with the MbedTLS certificate
+ library.
+
endif # MBEDTLS_LIB_X509
config MBEDTLS_LIB_TLS
@@ -300,6 +313,7 @@ config MBEDTLS_LIB_TLS
depends on X509_CERTIFICATE_PARSER_MBEDTLS
depends on ASYMMETRIC_PUBLIC_KEY_MBEDTLS
depends on ASN1_DECODER_MBEDTLS
+ depends on ECDSA_MBEDTLS
depends on MBEDTLS_LIB
help
Enable MbedTLS TLS library. Required for HTTPs support
diff --git a/lib/mbedtls/Makefile b/lib/mbedtls/Makefile
index c5b445bd85c..a24c8389744 100644
--- a/lib/mbedtls/Makefile
+++ b/lib/mbedtls/Makefile
@@ -39,13 +39,20 @@ mbedtls_lib_crypto-$(CONFIG_$(PHASE_)HKDF_MBEDTLS) += \
# MbedTLS X509 library
obj-$(CONFIG_$(XPL_)MBEDTLS_LIB_X509) += mbedtls_lib_x509.o
mbedtls_lib_x509-y := $(MBEDTLS_LIB_DIR)/x509.o
+mbedtls_lib_x509-$(CONFIG_$(PHASE_)ECDSA_MBEDTLS) += \
+ $(MBEDTLS_LIB_DIR)/ecdsa.o \
+ $(MBEDTLS_LIB_DIR)/ecp.o \
+ $(MBEDTLS_LIB_DIR)/ecp_curves.o \
+ $(MBEDTLS_LIB_DIR)/ecp_curves_new.o \
+ $(MBEDTLS_LIB_DIR)/pk_ecc.o
+mbedtls_lib_x509-$(CONFIG_$(PHASE_)BIGNUM_MBEDTLS) += \
+ $(MBEDTLS_LIB_DIR)/bignum.o \
+ $(MBEDTLS_LIB_DIR)/bignum_core.o
mbedtls_lib_x509-$(CONFIG_$(PHASE_)ASN1_DECODER_MBEDTLS) += \
$(MBEDTLS_LIB_DIR)/asn1parse.o \
$(MBEDTLS_LIB_DIR)/asn1write.o \
$(MBEDTLS_LIB_DIR)/oid.o
mbedtls_lib_x509-$(CONFIG_$(PHASE_)RSA_PUBLIC_KEY_PARSER_MBEDTLS) += \
- $(MBEDTLS_LIB_DIR)/bignum.o \
- $(MBEDTLS_LIB_DIR)/bignum_core.o \
$(MBEDTLS_LIB_DIR)/rsa.o \
$(MBEDTLS_LIB_DIR)/rsa_alt_helpers.o
mbedtls_lib_x509-$(CONFIG_$(PHASE_)ASYMMETRIC_PUBLIC_KEY_MBEDTLS) += \
@@ -64,7 +71,6 @@ mbedtls_lib_tls-y := \
$(MBEDTLS_LIB_DIR)/mps_reader.o \
$(MBEDTLS_LIB_DIR)/mps_trace.o \
$(MBEDTLS_LIB_DIR)/net_sockets.o \
- $(MBEDTLS_LIB_DIR)/pk_ecc.o \
$(MBEDTLS_LIB_DIR)/ssl_cache.o \
$(MBEDTLS_LIB_DIR)/ssl_ciphersuites.o \
$(MBEDTLS_LIB_DIR)/ssl_client.o \
@@ -82,8 +88,4 @@ mbedtls_lib_tls-y := \
$(MBEDTLS_LIB_DIR)/cipher.o \
$(MBEDTLS_LIB_DIR)/cipher_wrap.o \
$(MBEDTLS_LIB_DIR)/ecdh.o \
- $(MBEDTLS_LIB_DIR)/ecdsa.o \
- $(MBEDTLS_LIB_DIR)/ecp.o \
- $(MBEDTLS_LIB_DIR)/ecp_curves.o \
- $(MBEDTLS_LIB_DIR)/ecp_curves_new.o \
$(MBEDTLS_LIB_DIR)/gcm.o \
diff --git a/lib/mbedtls/mbedtls_def_config.h b/lib/mbedtls/mbedtls_def_config.h
index dda3f4dd6e4..d1bbcaa0924 100644
--- a/lib/mbedtls/mbedtls_def_config.h
+++ b/lib/mbedtls/mbedtls_def_config.h
@@ -89,6 +89,23 @@
#define MBEDTLS_ASN1_WRITE_C
#endif
+#if CONFIG_IS_ENABLED(ECDSA_MBEDTLS)
+#define MBEDTLS_ECDSA_C
+#define MBEDTLS_ECP_C
+#define MBEDTLS_BIGNUM_C
+#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
+#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
+#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
+#define MBEDTLS_ECP_DP_BP256R1_ENABLED
+#define MBEDTLS_ECP_DP_BP384R1_ENABLED
+#define MBEDTLS_ECP_DP_BP512R1_ENABLED
+#endif
+
#endif /* #if CONFIG_IS_ENABLED(MBEDTLS_LIB_X509) */
#if CONFIG_IS_ENABLED(MBEDTLS_LIB_TLS)
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [PATCH v5 02/15] mbedtls: enable support of ecc
2026-04-21 21:09 ` [PATCH v5 02/15] mbedtls: enable support of ecc Philippe Reynes
@ 2026-04-22 0:10 ` Simon Glass
2026-04-22 18:15 ` Raymond Mao
1 sibling, 0 replies; 29+ messages in thread
From: Simon Glass @ 2026-04-22 0:10 UTC (permalink / raw)
To: philippe.reynes
Cc: marko.makela, jonny.green, raymondmaoca, trini, simon.glass,
u-boot
Hi Philippe,
On 2026-04-21T21:09:51, Philippe Reynes <philippe.reynes@softathome.com> wrote:
> mbedtls: enable support of ecc
>
> Enables the support of ecc in mbedtls.
>
> Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
>
> configs/amd_versal2_virt_defconfig | 3 +++
> configs/qemu_arm64_lwip_defconfig | 3 +++
> configs/sandbox_defconfig | 1 +
> configs/starfive_visionfive2_defconfig | 3 +++
> configs/xilinx_versal_net_virt_defconfig | 3 +++
> configs/xilinx_versal_virt_defconfig | 3 +++
> configs/xilinx_zynqmp_kria_defconfig | 3 +++
> configs/xilinx_zynqmp_virt_defconfig | 3 +++
> lib/ecdsa/Kconfig | 1 +
> lib/mbedtls/Kconfig | 14 ++++++++++++++
> lib/mbedtls/Makefile | 16 +++++++++-------
> lib/mbedtls/mbedtls_def_config.h | 17 +++++++++++++++++
> 12 files changed, 63 insertions(+), 7 deletions(-)
> diff --git a/lib/mbedtls/Kconfig b/lib/mbedtls/Kconfig
> @@ -300,6 +313,7 @@ config MBEDTLS_LIB_TLS
> + depends on ECDSA_MBEDTLS
Adding ECDSA_MBEDTLS as a hard dependency on MBEDTLS_LIB_TLS means
every board using TLS now requires CONFIG_ECDSA and
CONFIG_ECDSA_VERIFY. I suspect you want to separate the TLS ECC
requirements from FIT signature verification. Perhaps the ECC curve
support should be in a separate CONFIG_ECC_MBEDTLS option that both
TLS and ECDSA verification can select?
> diff --git a/configs/qemu_arm64_lwip_defconfig b/configs/qemu_arm64_lwip_defconfig
> @@ -3,6 +3,9 @@
> +CONFIG_ECDSA=y
> +CONFIG_ECDSA_VERIFY=y
> +CONFIG_ECDSA_MBEDTLS=y
This suggests the coupling between TLS and ECDSA verification is too
tight. These boards want HTTPS but might not need FIT ECDSA signature
verification.
> diff --git a/lib/mbedtls/mbedtls_def_config.h b/lib/mbedtls/mbedtls_def_config.h
> @@ -89,6 +89,23 @@
> +#if CONFIG_IS_ENABLED(ECDSA_MBEDTLS)
> +#define MBEDTLS_ECDSA_C
> +#define MBEDTLS_ECP_C
> +#define MBEDTLS_BIGNUM_C
> +#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
> +#define MBEDTLS_ECP_DP_BP256R1_ENABLED
> +#define MBEDTLS_ECP_DP_BP384R1_ENABLED
> +#define MBEDTLS_ECP_DP_BP512R1_ENABLED
> +#endif
How much code size is added by enabling all ECC curves unconditionally?
Regards,
Simon
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v5 02/15] mbedtls: enable support of ecc
2026-04-21 21:09 ` [PATCH v5 02/15] mbedtls: enable support of ecc Philippe Reynes
2026-04-22 0:10 ` Simon Glass
@ 2026-04-22 18:15 ` Raymond Mao
1 sibling, 0 replies; 29+ messages in thread
From: Raymond Mao @ 2026-04-22 18:15 UTC (permalink / raw)
To: Philippe Reynes; +Cc: marko.makela, jonny.green, trini, simon.glass, u-boot
Hi Philippe,
On Tue, Apr 21, 2026 at 5:10 PM Philippe Reynes
<philippe.reynes@softathome.com> wrote:
>
> Enables the support of ecc in mbedtls.
>
> Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
> ---
> v2:
> - move ecdsa to MBEDTLS_LIB_X509
> - enhance depencendies
> v3:
> - do not use _MBEDTLS in mbedtls_def_config.h
> v4:
> - do not select ECDSA on some configs
> - remove duplicated MBEDTLS_ECP_DP_SECP256K1_ENABLED
> - change dependencies for ECDSA configs
> v5:
> - MBEDTLS_LIB_TLS depends en ECDSA_MBEDTLS
> - update some configs according to previous change
> - build of ecdsa is conditionned by ECDSA_MBEDTLS
>
> configs/amd_versal2_virt_defconfig | 3 +++
> configs/qemu_arm64_lwip_defconfig | 3 +++
> configs/sandbox_defconfig | 1 +
> configs/starfive_visionfive2_defconfig | 3 +++
> configs/xilinx_versal_net_virt_defconfig | 3 +++
> configs/xilinx_versal_virt_defconfig | 3 +++
> configs/xilinx_zynqmp_kria_defconfig | 3 +++
> configs/xilinx_zynqmp_virt_defconfig | 3 +++
> lib/ecdsa/Kconfig | 1 +
> lib/mbedtls/Kconfig | 14 ++++++++++++++
> lib/mbedtls/Makefile | 16 +++++++++-------
> lib/mbedtls/mbedtls_def_config.h | 17 +++++++++++++++++
> 12 files changed, 63 insertions(+), 7 deletions(-)
>
> diff --git a/configs/amd_versal2_virt_defconfig b/configs/amd_versal2_virt_defconfig
> index 0f4b75c72e1..cbc0789d5b3 100644
> --- a/configs/amd_versal2_virt_defconfig
> +++ b/configs/amd_versal2_virt_defconfig
> @@ -167,6 +167,9 @@ CONFIG_VIRTIO_MMIO=y
> CONFIG_VIRTIO_NET=y
> CONFIG_VIRTIO_BLK=y
> CONFIG_MBEDTLS_LIB=y
> +CONFIG_ECDSA_MBEDTLS=y
> +CONFIG_ECDSA=y
> +CONFIG_ECDSA_VERIFY=y
> CONFIG_TPM=y
> # CONFIG_OPTEE_LIB is not set
> CONFIG_TOOLS_MKFWUMDATA=y
> diff --git a/configs/qemu_arm64_lwip_defconfig b/configs/qemu_arm64_lwip_defconfig
> index a974970c3d3..151506eaca2 100644
> --- a/configs/qemu_arm64_lwip_defconfig
> +++ b/configs/qemu_arm64_lwip_defconfig
> @@ -3,6 +3,9 @@
> CONFIG_ARM=y
> CONFIG_ARCH_QEMU=y
>
> +CONFIG_ECDSA=y
> +CONFIG_ECDSA_VERIFY=y
> +CONFIG_ECDSA_MBEDTLS=y
> CONFIG_NET_LWIP=y
> CONFIG_CMD_DNS=y
> CONFIG_CMD_NFS=y
> diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
> index f26295103f1..15831dd7e04 100644
> --- a/configs/sandbox_defconfig
> +++ b/configs/sandbox_defconfig
> @@ -391,6 +391,7 @@ CONFIG_PANIC_HANG=y
> CONFIG_CMD_DHRYSTONE=y
> CONFIG_MBEDTLS_LIB=y
> CONFIG_HKDF_MBEDTLS=y
> +CONFIG_ECDSA_MBEDTLS=y
> CONFIG_ECDSA=y
> CONFIG_ECDSA_VERIFY=y
> CONFIG_RSASSA_PSS=y
> diff --git a/configs/starfive_visionfive2_defconfig b/configs/starfive_visionfive2_defconfig
> index 74a24dfd074..77b3146f6cb 100644
> --- a/configs/starfive_visionfive2_defconfig
> +++ b/configs/starfive_visionfive2_defconfig
> @@ -156,3 +156,6 @@ CONFIG_USB_GADGET=y
> CONFIG_WDT=y
> CONFIG_WDT_STARFIVE=y
> CONFIG_MBEDTLS_LIB=y
> +CONFIG_ECDSA_MBEDTLS=y
> +CONFIG_ECDSA=y
> +CONFIG_ECDSA_VERIFY=y
> diff --git a/configs/xilinx_versal_net_virt_defconfig b/configs/xilinx_versal_net_virt_defconfig
> index 3410b874a04..90c04b98e0d 100644
> --- a/configs/xilinx_versal_net_virt_defconfig
> +++ b/configs/xilinx_versal_net_virt_defconfig
> @@ -155,4 +155,7 @@ CONFIG_VIRTIO_MMIO=y
> CONFIG_VIRTIO_NET=y
> CONFIG_VIRTIO_BLK=y
> CONFIG_MBEDTLS_LIB=y
> +CONFIG_ECDSA_MBEDTLS=y
> +CONFIG_ECDSA=y
> +CONFIG_ECDSA_VERIFY=y
> CONFIG_TPM=y
> diff --git a/configs/xilinx_versal_virt_defconfig b/configs/xilinx_versal_virt_defconfig
> index d5d60d7f87d..bd3e368d1b4 100644
> --- a/configs/xilinx_versal_virt_defconfig
> +++ b/configs/xilinx_versal_virt_defconfig
> @@ -170,5 +170,8 @@ CONFIG_VIRTIO_MMIO=y
> CONFIG_VIRTIO_NET=y
> CONFIG_VIRTIO_BLK=y
> CONFIG_MBEDTLS_LIB=y
> +CONFIG_ECDSA_MBEDTLS=y
> +CONFIG_ECDSA=y
> +CONFIG_ECDSA_VERIFY=y
> CONFIG_TPM=y
> CONFIG_TOOLS_MKFWUMDATA=y
> diff --git a/configs/xilinx_zynqmp_kria_defconfig b/configs/xilinx_zynqmp_kria_defconfig
> index 72a4668b448..7a741416685 100644
> --- a/configs/xilinx_zynqmp_kria_defconfig
> +++ b/configs/xilinx_zynqmp_kria_defconfig
> @@ -221,6 +221,9 @@ CONFIG_VIRTIO_BLK=y
> CONFIG_BINMAN_DTB="./arch/arm/dts/zynqmp-binman-som.dtb"
> CONFIG_PANIC_HANG=y
> CONFIG_MBEDTLS_LIB=y
> +CONFIG_ECDSA_MBEDTLS=y
> +CONFIG_ECDSA=y
> +CONFIG_ECDSA_VERIFY=y
> CONFIG_TPM=y
> CONFIG_SPL_GZIP=y
> CONFIG_TOOLS_MKFWUMDATA=y
> diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig
> index 1433b63979a..7dd73c48c1b 100644
> --- a/configs/xilinx_zynqmp_virt_defconfig
> +++ b/configs/xilinx_zynqmp_virt_defconfig
> @@ -239,6 +239,9 @@ CONFIG_VIRTIO_BLK=y
> CONFIG_BINMAN_DTB="./arch/arm/dts/zynqmp-binman.dtb"
> CONFIG_PANIC_HANG=y
> CONFIG_MBEDTLS_LIB=y
> +CONFIG_ECDSA_MBEDTLS=y
> +CONFIG_ECDSA=y
> +CONFIG_ECDSA_VERIFY=y
> CONFIG_TPM=y
> CONFIG_SPL_GZIP=y
> CONFIG_TOOLS_MKFWUMDATA=y
> diff --git a/lib/ecdsa/Kconfig b/lib/ecdsa/Kconfig
> index ca13b6bfa1f..dac8bcf23dd 100644
> --- a/lib/ecdsa/Kconfig
> +++ b/lib/ecdsa/Kconfig
> @@ -1,6 +1,7 @@
> config ECDSA
> bool "Enable ECDSA support"
> depends on DM
> + select ASN1_DECODER
> help
> This enables the ECDSA (elliptic curve signature) algorithm for FIT
> image verification in U-Boot. The ECDSA algorithm is implemented
> diff --git a/lib/mbedtls/Kconfig b/lib/mbedtls/Kconfig
> index 789721ee6cd..e948a8876f6 100644
> --- a/lib/mbedtls/Kconfig
> +++ b/lib/mbedtls/Kconfig
> @@ -247,6 +247,9 @@ config MBEDTLS_LIB_X509
>
> if MBEDTLS_LIB_X509
>
> +config BIGNUM_MBEDTLS
> + bool
> +
> config ASN1_DECODER_MBEDTLS
> bool "ASN1 decoder with MbedTLS certificate library"
> depends on MBEDTLS_LIB_X509 && ASN1_DECODER
> @@ -264,6 +267,7 @@ config RSA_PUBLIC_KEY_PARSER_MBEDTLS
> bool "RSA public key parser with MbedTLS certificate library"
> depends on ASYMMETRIC_PUBLIC_KEY_MBEDTLS
> select ASN1_DECODER_MBEDTLS
> + select BIGNUM_MBEDTLS
> help
> This option chooses MbedTLS certificate library for RSA public key
> parser.
> @@ -292,6 +296,15 @@ config MSCODE_PARSER_MBEDTLS
> This option chooses MbedTLS certificate library for MS authenticode
> parser.
>
> +config ECDSA_MBEDTLS
> + bool "Enable ECDSA support with MbedTLS certificate library"
> + depends on MBEDTLS_LIB_X509 && ECDSA_VERIFY
> + select ASN1_DECODER_MBEDTLS if ASN1_DECODER
> + select BIGNUM_MBEDTLS
> + help
> + This option enables support of ECDSA with the MbedTLS certificate
> + library.
> +
> endif # MBEDTLS_LIB_X509
>
> config MBEDTLS_LIB_TLS
> @@ -300,6 +313,7 @@ config MBEDTLS_LIB_TLS
> depends on X509_CERTIFICATE_PARSER_MBEDTLS
> depends on ASYMMETRIC_PUBLIC_KEY_MBEDTLS
> depends on ASN1_DECODER_MBEDTLS
> + depends on ECDSA_MBEDTLS
ecdsa is not mandatory for TLS. so this dependency is not correct.
Regards,
Raymond
> depends on MBEDTLS_LIB
> help
> Enable MbedTLS TLS library. Required for HTTPs support
> diff --git a/lib/mbedtls/Makefile b/lib/mbedtls/Makefile
> index c5b445bd85c..a24c8389744 100644
> --- a/lib/mbedtls/Makefile
> +++ b/lib/mbedtls/Makefile
> @@ -39,13 +39,20 @@ mbedtls_lib_crypto-$(CONFIG_$(PHASE_)HKDF_MBEDTLS) += \
> # MbedTLS X509 library
> obj-$(CONFIG_$(XPL_)MBEDTLS_LIB_X509) += mbedtls_lib_x509.o
> mbedtls_lib_x509-y := $(MBEDTLS_LIB_DIR)/x509.o
> +mbedtls_lib_x509-$(CONFIG_$(PHASE_)ECDSA_MBEDTLS) += \
> + $(MBEDTLS_LIB_DIR)/ecdsa.o \
> + $(MBEDTLS_LIB_DIR)/ecp.o \
> + $(MBEDTLS_LIB_DIR)/ecp_curves.o \
> + $(MBEDTLS_LIB_DIR)/ecp_curves_new.o \
> + $(MBEDTLS_LIB_DIR)/pk_ecc.o
> +mbedtls_lib_x509-$(CONFIG_$(PHASE_)BIGNUM_MBEDTLS) += \
> + $(MBEDTLS_LIB_DIR)/bignum.o \
> + $(MBEDTLS_LIB_DIR)/bignum_core.o
> mbedtls_lib_x509-$(CONFIG_$(PHASE_)ASN1_DECODER_MBEDTLS) += \
> $(MBEDTLS_LIB_DIR)/asn1parse.o \
> $(MBEDTLS_LIB_DIR)/asn1write.o \
> $(MBEDTLS_LIB_DIR)/oid.o
> mbedtls_lib_x509-$(CONFIG_$(PHASE_)RSA_PUBLIC_KEY_PARSER_MBEDTLS) += \
> - $(MBEDTLS_LIB_DIR)/bignum.o \
> - $(MBEDTLS_LIB_DIR)/bignum_core.o \
> $(MBEDTLS_LIB_DIR)/rsa.o \
> $(MBEDTLS_LIB_DIR)/rsa_alt_helpers.o
> mbedtls_lib_x509-$(CONFIG_$(PHASE_)ASYMMETRIC_PUBLIC_KEY_MBEDTLS) += \
> @@ -64,7 +71,6 @@ mbedtls_lib_tls-y := \
> $(MBEDTLS_LIB_DIR)/mps_reader.o \
> $(MBEDTLS_LIB_DIR)/mps_trace.o \
> $(MBEDTLS_LIB_DIR)/net_sockets.o \
> - $(MBEDTLS_LIB_DIR)/pk_ecc.o \
> $(MBEDTLS_LIB_DIR)/ssl_cache.o \
> $(MBEDTLS_LIB_DIR)/ssl_ciphersuites.o \
> $(MBEDTLS_LIB_DIR)/ssl_client.o \
> @@ -82,8 +88,4 @@ mbedtls_lib_tls-y := \
> $(MBEDTLS_LIB_DIR)/cipher.o \
> $(MBEDTLS_LIB_DIR)/cipher_wrap.o \
> $(MBEDTLS_LIB_DIR)/ecdh.o \
> - $(MBEDTLS_LIB_DIR)/ecdsa.o \
> - $(MBEDTLS_LIB_DIR)/ecp.o \
> - $(MBEDTLS_LIB_DIR)/ecp_curves.o \
> - $(MBEDTLS_LIB_DIR)/ecp_curves_new.o \
> $(MBEDTLS_LIB_DIR)/gcm.o \
> diff --git a/lib/mbedtls/mbedtls_def_config.h b/lib/mbedtls/mbedtls_def_config.h
> index dda3f4dd6e4..d1bbcaa0924 100644
> --- a/lib/mbedtls/mbedtls_def_config.h
> +++ b/lib/mbedtls/mbedtls_def_config.h
> @@ -89,6 +89,23 @@
> #define MBEDTLS_ASN1_WRITE_C
> #endif
>
> +#if CONFIG_IS_ENABLED(ECDSA_MBEDTLS)
> +#define MBEDTLS_ECDSA_C
> +#define MBEDTLS_ECP_C
> +#define MBEDTLS_BIGNUM_C
> +#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
> +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
> +#define MBEDTLS_ECP_DP_BP256R1_ENABLED
> +#define MBEDTLS_ECP_DP_BP384R1_ENABLED
> +#define MBEDTLS_ECP_DP_BP512R1_ENABLED
> +#endif
> +
> #endif /* #if CONFIG_IS_ENABLED(MBEDTLS_LIB_X509) */
>
> #if CONFIG_IS_ENABLED(MBEDTLS_LIB_TLS)
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v5 03/15] ecdsa: initial support of ecdsa using mbedtls
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
2026-04-21 21:09 ` [PATCH v5 01/15] ecdsa: fix support of secp521r1 Philippe Reynes
2026-04-21 21:09 ` [PATCH v5 02/15] mbedtls: enable support of ecc Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-22 0:10 ` Simon Glass
2026-04-22 18:17 ` Raymond Mao
2026-04-21 21:09 ` [PATCH v5 04/15] test: lib: ecdsa: add initial test Philippe Reynes
` (13 subsequent siblings)
16 siblings, 2 replies; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes
Adds an initial support of ecdsa verify using mbedtls.
Signed-off-by: Philippe Reynes <philippe.reynes@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
include/crypto/ecdsa-uclass.h | 15 +---
include/crypto/internal/ecdsa.h | 39 +++++++++
lib/mbedtls/Makefile | 3 +
lib/mbedtls/ecdsa.c | 146 ++++++++++++++++++++++++++++++++
4 files changed, 189 insertions(+), 14 deletions(-)
create mode 100644 include/crypto/internal/ecdsa.h
create mode 100644 lib/mbedtls/ecdsa.c
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..fe00797c5b0
--- /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@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/Makefile b/lib/mbedtls/Makefile
index a24c8389744..33698c92282 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
+obj-$(CONFIG_$(PHASE_)ECDSA_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..90c9c37e96e
--- /dev/null
+++ b/lib/mbedtls/ecdsa.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026 Philippe Reynes <philippe.reynes@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)
+ goto out;
+
+ 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++;
+ }
+
+ out:
+ 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 = -1;
+
+ 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 out1;
+ }
+
+ /* 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 out2;
+ }
+ 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 out2;
+ }
+ 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 out2;
+ }
+
+ /* 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 out2;
+ }
+
+ /* 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 out3;
+ }
+
+ /* 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 out4;
+ }
+
+ /* check the signature */
+ err = mbedtls_ecdsa_verify(&grp, hash, hash_len, &Q, &r, &s);
+ if (err)
+ err = -EINVAL;
+
+ out4:
+ mbedtls_mpi_free(&s);
+ out3:
+ mbedtls_mpi_free(&r);
+ out2:
+ mbedtls_ecp_point_free(&Q);
+ out1:
+ mbedtls_ecp_group_free(&grp);
+ out:
+
+ return err;
+}
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [PATCH v5 03/15] ecdsa: initial support of ecdsa using mbedtls
2026-04-21 21:09 ` [PATCH v5 03/15] ecdsa: initial support of ecdsa using mbedtls Philippe Reynes
@ 2026-04-22 0:10 ` Simon Glass
2026-04-22 18:17 ` Raymond Mao
1 sibling, 0 replies; 29+ messages in thread
From: Simon Glass @ 2026-04-22 0:10 UTC (permalink / raw)
To: philippe.reynes
Cc: marko.makela, jonny.green, raymondmaoca, trini, simon.glass,
u-boot
Hi Philippe,
On 2026-04-21T21:09:51, Philippe Reynes <philippe.reynes@softathome.com> wrote:
> ecdsa: initial support of ecdsa using mbedtls
>
> Adds an initial support of ecdsa verify using mbedtls.
>
> Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
>
> include/crypto/ecdsa-uclass.h | 15 +----
> include/crypto/internal/ecdsa.h | 39 +++++++++++
> lib/mbedtls/Makefile | 3 +
> lib/mbedtls/ecdsa.c | 146 ++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 189 insertions(+), 14 deletions(-)
> diff --git a/include/crypto/internal/ecdsa.h b/include/crypto/internal/ecdsa.h
> @@ -0,0 +1,39 @@
> + * @pubkey : ecdsa public key
> + * @hash : Hash
> + * @hash_len : Size of the hash
> + * @signature : Signature
> + * @sig_len : Size of the signature
The kernel-doc style uses no space before the colon. Please can you
use @pubkey: etc.
Regards,
Simon
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v5 03/15] ecdsa: initial support of ecdsa using mbedtls
2026-04-21 21:09 ` [PATCH v5 03/15] ecdsa: initial support of ecdsa using mbedtls Philippe Reynes
2026-04-22 0:10 ` Simon Glass
@ 2026-04-22 18:17 ` Raymond Mao
1 sibling, 0 replies; 29+ messages in thread
From: Raymond Mao @ 2026-04-22 18:17 UTC (permalink / raw)
To: Philippe Reynes; +Cc: marko.makela, jonny.green, trini, simon.glass, u-boot
Hi Philippe,
On Tue, Apr 21, 2026 at 5:10 PM Philippe Reynes
<philippe.reynes@softathome.com> wrote:
>
> Adds an initial support of ecdsa verify using mbedtls.
>
> Signed-off-by: Philippe Reynes <philippe.reynes@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
>
> include/crypto/ecdsa-uclass.h | 15 +---
> include/crypto/internal/ecdsa.h | 39 +++++++++
> lib/mbedtls/Makefile | 3 +
> lib/mbedtls/ecdsa.c | 146 ++++++++++++++++++++++++++++++++
> 4 files changed, 189 insertions(+), 14 deletions(-)
> create mode 100644 include/crypto/internal/ecdsa.h
> create mode 100644 lib/mbedtls/ecdsa.c
>
> 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..fe00797c5b0
> --- /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@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/Makefile b/lib/mbedtls/Makefile
> index a24c8389744..33698c92282 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
> +obj-$(CONFIG_$(PHASE_)ECDSA_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..90c9c37e96e
> --- /dev/null
> +++ b/lib/mbedtls/ecdsa.c
> @@ -0,0 +1,146 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2026 Philippe Reynes <philippe.reynes@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)
> + goto out;
> +
> + 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++;
> + }
> +
> + out:
> + 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 = -1;
> +
> + 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 out1;
> + }
> +
> + /* 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 out2;
> + }
> + 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 out2;
> + }
> + 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 out2;
> + }
> +
> + /* 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 out2;
> + }
> +
> + /* 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 out3;
> + }
> +
> + /* 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 out4;
> + }
> +
> + /* check the signature */
> + err = mbedtls_ecdsa_verify(&grp, hash, hash_len, &Q, &r, &s);
> + if (err)
> + err = -EINVAL;
> +
> + out4:
> + mbedtls_mpi_free(&s);
> + out3:
> + mbedtls_mpi_free(&r);
> + out2:
> + mbedtls_ecp_point_free(&Q);
> + out1:
> + mbedtls_ecp_group_free(&grp);
> + out:
> +
> + return err;
> +}
> --
> 2.43.0
>
Looks good to me.
Reviewed-by: Raymond Mao <raymondmaoca@gmail.com>
Thanks and regards,
Raymond
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v5 04/15] test: lib: ecdsa: add initial test
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (2 preceding siblings ...)
2026-04-21 21:09 ` [PATCH v5 03/15] ecdsa: initial support of ecdsa using mbedtls Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-21 21:09 ` [PATCH v5 05/15] drivers: crypto: add software ecdsa support Philippe Reynes
` (12 subsequent siblings)
16 siblings, 0 replies; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes, Simon Glass
Adds tests to check that the function ecdsa_hash_verify
using mbedtls is valid.
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Raymond Mao <raymondmaoca@gmail.com>
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v2:
- little change to only use test with sha enabled
v3:
- remove useless field *k in struct ecdsa_test_vector_s
- change expected value on error (don't use mbedtls error)
- manage function returns
- update third parameter of sha*_csum_wd
v4:
- define SHA256_DEF_CHUNK_SZ, SHA384_DEF_CHUNK_SZ and SHA512_DEF_CHUNK_SZ
- report skipped tests
- add const on some variables
- code cleanup
v5:
- do not define SHA256_DEF_CHUNK_SZ, SHA384_DEF_CHUNK_SZ and SHA512_DEF_CHUNK_SZ
- use CHUNKSZ_SHA256, CHUNKSZ_SHA384 and CHUNKSZ_SHA521
- do not use 528 to compule ecdsa 521 sig size but compute it
- use ut_reportf instead of ut_failf
test/lib/Makefile | 1 +
test/lib/ecdsa.c | 456 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 457 insertions(+)
create mode 100644 test/lib/ecdsa.c
diff --git a/test/lib/Makefile b/test/lib/Makefile
index f25383a40e5..2ac80afefdb 100644
--- a/test/lib/Makefile
+++ b/test/lib/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_$(PHASE_)UT_COMPRESSION) += compression.o
ifeq ($(CONFIG_XPL_BUILD),)
obj-y += abuf.o
obj-y += alist.o
+obj-$(CONFIG_ECDSA_MBEDTLS) += ecdsa.o
obj-$(CONFIG_EFI_LOADER) += efi_device_path.o efi_memory.o
obj-$(CONFIG_EFI_SECURE_BOOT) += efi_image_region.o
ifdef CONFIG_RISCV
diff --git a/test/lib/ecdsa.c b/test/lib/ecdsa.c
new file mode 100644
index 00000000000..bc7737837e5
--- /dev/null
+++ b/test/lib/ecdsa.c
@@ -0,0 +1,456 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026 Philippe Reynes <philippe.reynes@softathome.com>
+ */
+
+#include <command.h>
+#include <image.h>
+#include <test/lib.h>
+#include <test/test.h>
+#include <test/ut.h>
+#include <crypto/ecdsa-uclass.h>
+#include <crypto/internal/ecdsa.h>
+
+#define ECDSA_POINT_SIZE (DIV_ROUND_UP(521, 8) * 2)
+#define ECDSA_SIGNATURE_SIZE (ECDSA_POINT_SIZE * 2)
+
+struct ecdsa_test_vector_s {
+ const char *test_name;
+ const char *curve_name;
+ const char *x;
+ const char *y;
+ int size_bits;
+ const char *hash_type;
+ const char *hash_message;
+ const char *r;
+ const char *s;
+ int expected;
+};
+
+/*
+ * Those data come from RFC6979
+ */
+
+static const struct ecdsa_test_vector_s ecdsa_test_vector[] = {
+ /*
+ * secp192r1
+ */
+ {
+ .test_name = "secp192r1 sha1",
+ .curve_name = "secp192r1",
+ .x = "AC2C77F529F91689FEA0EA5EFEC7F210D8EEA0B9E047ED56",
+ .y = "3BC723E57670BD4887EBC732C523063D0A7C957BC97C1C43",
+ .size_bits = 192,
+ .hash_type = "sha-1",
+ .hash_message = "sample",
+ .r = "98C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF",
+ .s = "57A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp192r1 sha256",
+ .curve_name = "secp192r1",
+ .x = "AC2C77F529F91689FEA0EA5EFEC7F210D8EEA0B9E047ED56",
+ .y = "3BC723E57670BD4887EBC732C523063D0A7C957BC97C1C43",
+ .size_bits = 192,
+ .hash_type = "sha-256",
+ .hash_message = "sample",
+ .r = "4B0B8CE98A92866A2820E20AA6B75B56382E0F9BFD5ECB55",
+ .s = "CCDB006926EA9565CBADC840829D8C384E06DE1F1E381B85",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp192r1 sha384",
+ .curve_name = "secp192r1",
+ .x = "AC2C77F529F91689FEA0EA5EFEC7F210D8EEA0B9E047ED56",
+ .y = "3BC723E57670BD4887EBC732C523063D0A7C957BC97C1C43",
+ .size_bits = 192,
+ .hash_type = "sha-384",
+ .hash_message = "sample",
+ .r = "DA63BF0B9ABCF948FBB1E9167F136145F7A20426DCC287D5",
+ .s = "C3AA2C960972BD7A2003A57E1C4C77F0578F8AE95E31EC5E",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp192r1 sha512",
+ .curve_name = "secp192r1",
+ .x = "AC2C77F529F91689FEA0EA5EFEC7F210D8EEA0B9E047ED56",
+ .y = "3BC723E57670BD4887EBC732C523063D0A7C957BC97C1C43",
+ .size_bits = 192,
+ .hash_type = "sha-512",
+ .hash_message = "sample",
+ .r = "4D60C5AB1996BD848343B31C00850205E2EA6922DAC2E4B8",
+ .s = "3F6E837448F027A1BF4B34E796E32A811CBB4050908D8F67",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp192r1 sha512 error",
+ .curve_name = "secp192r1",
+ .x = "AC2C77F529F91689FEA0EA5EFEC7F210D8EEA0B9E047ED56",
+ .y = "3BC723E57670BD4887EBC732C523063D0A7C957BC97C1C43",
+ .size_bits = 192,
+ .hash_type = "sha-512",
+ .hash_message = "sample",
+ .r = "4D60C5AB1996BD848343B31C00850205E2EA6922DAC2E4B8",
+ .s = "0F6E837448F027A1BF4B34E796E32A811CBB4050908D8F67",
+ .expected = -EINVAL,
+ },
+ /*
+ * secp224r1
+ */
+ {
+ .test_name = "secp224r1 sha1",
+ .curve_name = "secp224r1",
+ .x = "00CF08DA5AD719E42707FA431292DEA11244D64FC51610D94B130D6C",
+ .y = "EEAB6F3DEBE455E3DBF85416F7030CBD94F34F2D6F232C69F3C1385A",
+ .size_bits = 224,
+ .hash_type = "sha-1",
+ .hash_message = "sample",
+ .r = "22226F9D40A96E19C4A301CE5B74B115303C0F3A4FD30FC257FB57AC",
+ .s = "66D1CDD83E3AF75605DD6E2FEFF196D30AA7ED7A2EDF7AF475403D69",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp224r1 sha256",
+ .curve_name = "secp224r1",
+ .x = "00CF08DA5AD719E42707FA431292DEA11244D64FC51610D94B130D6C",
+ .y = "EEAB6F3DEBE455E3DBF85416F7030CBD94F34F2D6F232C69F3C1385A",
+ .size_bits = 224,
+ .hash_type = "sha-256",
+ .hash_message = "sample",
+ .r = "61AA3DA010E8E8406C656BC477A7A7189895E7E840CDFE8FF42307BA",
+ .s = "BC814050DAB5D23770879494F9E0A680DC1AF7161991BDE692B10101",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp224r1 sha384",
+ .curve_name = "secp224r1",
+ .x = "00CF08DA5AD719E42707FA431292DEA11244D64FC51610D94B130D6C",
+ .y = "EEAB6F3DEBE455E3DBF85416F7030CBD94F34F2D6F232C69F3C1385A",
+ .size_bits = 224,
+ .hash_type = "sha-384",
+ .hash_message = "sample",
+ .r = "0B115E5E36F0F9EC81F1325A5952878D745E19D7BB3EABFABA77E953",
+ .s = "830F34CCDFE826CCFDC81EB4129772E20E122348A2BBD889A1B1AF1D",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp224r1 sha512",
+ .curve_name = "secp224r1",
+ .x = "00CF08DA5AD719E42707FA431292DEA11244D64FC51610D94B130D6C",
+ .y = "EEAB6F3DEBE455E3DBF85416F7030CBD94F34F2D6F232C69F3C1385A",
+ .size_bits = 224,
+ .hash_type = "sha-512",
+ .hash_message = "sample",
+ .r = "074BD1D979D5F32BF958DDC61E4FB4872ADCAFEB2256497CDAC30397",
+ .s = "A4CECA196C3D5A1FF31027B33185DC8EE43F288B21AB342E5D8EB084",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp224r1 sha512 error",
+ .curve_name = "secp224r1",
+ .x = "00CF08DA5AD719E42707FA431292DEA11244D64FC51610D94B130D6C",
+ .y = "EEAB6F3DEBE455E3DBF85416F7030CBD94F34F2D6F232C69F3C1385A",
+ .size_bits = 224,
+ .hash_type = "sha-512",
+ .hash_message = "sample",
+ .r = "074BD1D979D5F32BF958DDC61E4FB4872ADCAFEB2256497CDAC30397",
+ .s = "04CECA196C3D5A1FF31027B33185DC8EE43F288B21AB342E5D8EB084",
+ .expected = -EINVAL,
+ },
+ /*
+ * secp256r1
+ */
+ {
+ .test_name = "secp256r1 sha1",
+ .curve_name = "secp256r1",
+ .x = "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6",
+ .y = "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299",
+ .size_bits = 256,
+ .hash_type = "sha-1",
+ .hash_message = "sample",
+ .r = "61340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D32",
+ .s = "6D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp256r1 sha256",
+ .curve_name = "secp256r1",
+ .x = "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6",
+ .y = "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299",
+ .size_bits = 256,
+ .hash_type = "sha-256",
+ .hash_message = "sample",
+ .r = "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716",
+ .s = "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp256r1 sha384",
+ .curve_name = "secp256r1",
+ .x = "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6",
+ .y = "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299",
+ .size_bits = 256,
+ .hash_type = "sha-384",
+ .hash_message = "sample",
+ .r = "0EAFEA039B20E9B42309FB1D89E213057CBF973DC0CFC8F129EDDDC800EF7719",
+ .s = "4861F0491E6998B9455193E34E7B0D284DDD7149A74B95B9261F13ABDE940954",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp256r1 sha512",
+ .curve_name = "secp256r1",
+ .x = "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6",
+ .y = "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299",
+ .size_bits = 256,
+ .hash_type = "sha-512",
+ .hash_message = "sample",
+ .r = "8496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F00",
+ .s = "2362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp256r1 sha512 error",
+ .curve_name = "secp256r1",
+ .x = "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6",
+ .y = "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299",
+ .size_bits = 256,
+ .hash_type = "sha-512",
+ .hash_message = "sample",
+ .r = "8496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F00",
+ .s = "0362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE",
+ .expected = -EINVAL,
+ },
+ /*
+ * secp384r1
+ */
+ {
+ .test_name = "secp384r1 sha1",
+ .curve_name = "secp384r1",
+ .x = "EC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64DEF8F0EA9055866064A254515480BC13",
+ .y = "8015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1288B231C3AE0D4FE7344FD2533264720",
+ .size_bits = 384,
+ .hash_type = "sha-1",
+ .hash_message = "sample",
+ .r = "EC748D839243D6FBEF4FC5C4859A7DFFD7F3ABDDF72014540C16D73309834FA37B9BA002899F6FDA3A4A9386790D4EB2",
+ .s = "A3BCFA947BEEF4732BF247AC17F71676CB31A847B9FF0CBC9C9ED4C1A5B3FACF26F49CA031D4857570CCB5CA4424A443",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp384r1 sha256",
+ .curve_name = "secp384r1",
+ .x = "EC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64DEF8F0EA9055866064A254515480BC13",
+ .y = "8015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1288B231C3AE0D4FE7344FD2533264720",
+ .size_bits = 384,
+ .hash_type = "sha-256",
+ .hash_message = "sample",
+ .r = "21B13D1E013C7FA1392D03C5F99AF8B30C570C6F98D4EA8E354B63A21D3DAA33BDE1E888E63355D92FA2B3C36D8FB2CD",
+ .s = "F3AA443FB107745BF4BD77CB3891674632068A10CA67E3D45DB2266FA7D1FEEBEFDC63ECCD1AC42EC0CB8668A4FA0AB0",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp384r1 sha384",
+ .curve_name = "secp384r1",
+ .x = "EC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64DEF8F0EA9055866064A254515480BC13",
+ .y = "8015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1288B231C3AE0D4FE7344FD2533264720",
+ .size_bits = 384,
+ .hash_type = "sha-384",
+ .hash_message = "sample",
+ .r = "94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C81A648152E44ACF96E36DD1E80FABE46",
+ .s = "99EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94FA329C145786E679E7B82C71A38628AC8",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp384r1 sha512",
+ .curve_name = "secp384r1",
+ .x = "EC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64DEF8F0EA9055866064A254515480BC13",
+ .y = "8015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1288B231C3AE0D4FE7344FD2533264720",
+ .size_bits = 384,
+ .hash_type = "sha-512",
+ .hash_message = "sample",
+ .r = "ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799CFE30F35CC900056D7C99CD7882433709",
+ .s = "512C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112DC7CC3EF3446DEFCEB01A45C2667FDD5",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp384r1 sha512 error",
+ .curve_name = "secp384r1",
+ .x = "EC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64DEF8F0EA9055866064A254515480BC13",
+ .y = "8015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1288B231C3AE0D4FE7344FD2533264720",
+ .size_bits = 384,
+ .hash_type = "sha-512",
+ .hash_message = "sample",
+ .r = "ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799CFE30F35CC900056D7C99CD7882433709",
+ .s = "012C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112DC7CC3EF3446DEFCEB01A45C2667FDD5",
+ .expected = -EINVAL,
+ },
+ /*
+ * secp521r1
+ */
+ {
+ .test_name = "secp521r1 sha1",
+ .curve_name = "secp521r1",
+ .x = "01894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD371123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F5023A4",
+ .y = "00493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A28A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDFCF5",
+ .size_bits = 521,
+ .hash_type = "sha-1",
+ .hash_message = "sample",
+ .r = "00343B6EC45728975EA5CBA6659BBB6062A5FF89EEA58BE3C80B619F322C87910FE092F7D45BB0F8EEE01ED3F20BABEC079D202AE677B243AB40B5431D497C55D75D",
+ .s = "00E7B0E675A9B24413D448B8CC119D2BF7B2D2DF032741C096634D6D65D0DBE3D5694625FB9E8104D3B842C1B0E2D0B98BEA19341E8676AEF66AE4EBA3D5475D5D16",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp521r1 sha256",
+ .curve_name = "secp521r1",
+ .x = "01894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD371123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F5023A4",
+ .y = "00493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A28A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDFCF5",
+ .size_bits = 521,
+ .hash_type = "sha-256",
+ .hash_message = "sample",
+ .r = "01511BB4D675114FE266FC4372B87682BAECC01D3CC62CF2303C92B3526012659D16876E25C7C1E57648F23B73564D67F61C6F14D527D54972810421E7D87589E1A7",
+ .s = "004A171143A83163D6DF460AAF61522695F207A58B95C0644D87E52AA1A347916E4F7A72930B1BC06DBE22CE3F58264AFD23704CBB63B29B931F7DE6C9D949A7ECFC",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp521r1 sha384",
+ .curve_name = "secp521r1",
+ .x = "01894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD371123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F5023A4",
+ .y = "00493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A28A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDFCF5",
+ .size_bits = 521,
+ .hash_type = "sha-384",
+ .hash_message = "sample",
+ .r = "01EA842A0E17D2DE4F92C15315C63DDF72685C18195C2BB95E572B9C5136CA4B4B576AD712A52BE9730627D16054BA40CC0B8D3FF035B12AE75168397F5D50C67451",
+ .s = "01F21A3CEE066E1961025FB048BD5FE2B7924D0CD797BABE0A83B66F1E35EEAF5FDE143FA85DC394A7DEE766523393784484BDF3E00114A1C857CDE1AA203DB65D61",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp521r1 sha512",
+ .curve_name = "secp521r1",
+ .x = "01894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD371123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F5023A4",
+ .y = "00493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A28A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDFCF5",
+ .size_bits = 521,
+ .hash_type = "sha-512",
+ .hash_message = "sample",
+ .r = "00C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F174E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E377FA",
+ .s = "00617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF282623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A67A",
+ .expected = 0,
+ },
+ {
+ .test_name = "secp521r1 sha512 error",
+ .curve_name = "secp521r1",
+ .x = "01894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD371123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F5023A4",
+ .y = "00493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A28A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDFCF5",
+ .size_bits = 521,
+ .hash_type = "sha-512",
+ .hash_message = "sample",
+ .r = "00C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F174E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E377FA",
+ .s = "00017CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF282623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A67A",
+ .expected = -EINVAL,
+ },
+};
+
+static int ecdsa_test(struct unit_test_state *uts,
+ const struct ecdsa_test_vector_s *tv)
+{
+ struct ecdsa_public_key pubkey;
+ unsigned char x[ECDSA_POINT_SIZE];
+ unsigned char y[ECDSA_POINT_SIZE];
+ unsigned char hash[512 / 8];
+ size_t hash_len;
+ unsigned char signature[ECDSA_SIGNATURE_SIZE];
+ size_t sig_len;
+ int ret;
+
+ sig_len = DIV_ROUND_UP(tv->size_bits, 8);
+
+ pubkey.curve_name = tv->curve_name;
+ ret = hex2bin(x, tv->x, strlen(tv->x) / 2);
+ ut_asserteq(0, ret);
+ pubkey.x = x;
+ ret = hex2bin(y, tv->y, strlen(tv->y) / 2);
+ ut_asserteq(0, ret);
+ pubkey.y = y;
+ pubkey.size_bits = tv->size_bits;
+
+ if (!strcmp(tv->hash_type, "sha-1")) {
+#if CONFIG_IS_ENABLED(SHA1)
+ hash_len = SHA1_SUM_LEN;
+ sha1_csum_wd(tv->hash_message, strlen(tv->hash_message),
+ hash, SHA1_DEF_CHUNK_SZ);
+#else
+ /* sha1 is not supported so we skip this test */
+ ut_reportf("Test %s skipped (sha1 not supported)",
+ tv->test_name);
+ goto out;
+#endif
+ } else if (!strcmp(tv->hash_type, "sha-256")) {
+#if CONFIG_IS_ENABLED(SHA256)
+ hash_len = SHA256_SUM_LEN;
+ sha256_csum_wd(tv->hash_message, strlen(tv->hash_message),
+ hash, CHUNKSZ_SHA256);
+#else
+ /* sha256 is not supported so we skip this test */
+ ut_reportf("Test %s skipped (sha256 not supported)",
+ tv->test_name);
+ goto out;
+#endif
+ } else if (!strcmp(tv->hash_type, "sha-384")) {
+#if CONFIG_IS_ENABLED(SHA384)
+ hash_len = SHA384_SUM_LEN;
+ sha384_csum_wd(tv->hash_message, strlen(tv->hash_message),
+ hash, CHUNKSZ_SHA384);
+#else
+ /* sha384 is not supported so we skip this test */
+ ut_reportf("Test %s skipped (sha384 not supported)",
+ tv->test_name);
+ goto out;
+#endif
+ } else if (!strcmp(tv->hash_type, "sha-512")) {
+#if CONFIG_IS_ENABLED(SHA512)
+ hash_len = SHA512_SUM_LEN;
+ sha512_csum_wd(tv->hash_message, strlen(tv->hash_message),
+ hash, CHUNKSZ_SHA512);
+#else
+ /* sha512 is not supported so we skip this test */
+ ut_reportf("Test %s skipped (sha512 not supported)",
+ tv->test_name);
+ goto out;
+#endif
+ } else {
+ ut_reportf("Unknown hash type (%s)", tv->hash_type);
+ return -EINVAL;
+ }
+
+ ret = hex2bin(signature, tv->r, sig_len);
+ ut_asserteq(0, ret);
+ ret = hex2bin(signature + sig_len, tv->s, sig_len);
+ ut_asserteq(0, ret);
+ sig_len = sig_len * 2;
+
+ ret = ecdsa_hash_verify(&pubkey,
+ hash, hash_len,
+ signature, sig_len);
+ ut_asserteq(tv->expected, ret);
+
+#if !CONFIG_IS_ENABLED(SHA1) || !CONFIG_IS_ENABLED(SHA256) || !CONFIG_IS_ENABLED(SHA384) || !CONFIG_IS_ENABLED(SHA512)
+ out:
+#endif
+
+ return 0;
+}
+
+static int lib_ecdsa(struct unit_test_state *uts)
+{
+ int i, ret;
+ size_t num_test = ARRAY_SIZE(ecdsa_test_vector);
+
+ for (i = 0; i < num_test; i++) {
+ ret = ecdsa_test(uts, &ecdsa_test_vector[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+LIB_TEST(lib_ecdsa, 0);
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [PATCH v5 05/15] drivers: crypto: add software ecdsa support
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (3 preceding siblings ...)
2026-04-21 21:09 ` [PATCH v5 04/15] test: lib: ecdsa: add initial test Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-22 0:12 ` Simon Glass
2026-04-21 21:09 ` [PATCH v5 06/15] test: dm: ecdsa.c: clean this test as software ecdsa is now implemented Philippe Reynes
` (11 subsequent siblings)
16 siblings, 1 reply; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes
Add a software ecdsa driver so it is
now possible to use ecdsa signature on
board without ecdsa hardware support.
Reviewed-by: Raymond Mao <raymondmaoca@gmail.com>
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v2:
- no change
v3:
- add depends on ECDSA_VERIFY to ECDSA_SW
- change sw_ecdsa_verify to ecdsa_hash_verify
- v4
- use ECDSA_MBEDTLS to build the driver
- clean include (change order)
v5:
- use $(PHASE_) in the Makefile for the driver
drivers/crypto/Makefile | 1 +
drivers/crypto/ecdsa/Makefile | 6 ++++++
drivers/crypto/ecdsa/ecdsa-sw.c | 33 +++++++++++++++++++++++++++++++++
3 files changed, 40 insertions(+)
create mode 100644 drivers/crypto/ecdsa/Makefile
create mode 100644 drivers/crypto/ecdsa/ecdsa-sw.c
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index e4a4482b7f3..8170e4cae9c 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -4,6 +4,7 @@
# http://www.samsung.com
obj-$(CONFIG_EXYNOS_ACE_SHA) += ace_sha.o
+obj-$(CONFIG_ECDSA) += ecdsa/
obj-y += aes/
obj-y += rsa_mod_exp/
obj-y += fsl/
diff --git a/drivers/crypto/ecdsa/Makefile b/drivers/crypto/ecdsa/Makefile
new file mode 100644
index 00000000000..1fd873980be
--- /dev/null
+++ b/drivers/crypto/ecdsa/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2026 Philippe Reynes <philippe.reynes@softathome.com>
+#
+
+obj-$(CONFIG_$(PHASE_)ECDSA_MBEDTLS) += ecdsa-sw.o
diff --git a/drivers/crypto/ecdsa/ecdsa-sw.c b/drivers/crypto/ecdsa/ecdsa-sw.c
new file mode 100644
index 00000000000..21dffeddf59
--- /dev/null
+++ b/drivers/crypto/ecdsa/ecdsa-sw.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026 Philippe Reynes <philippe.reynes@softathome.com>
+ */
+#include <crypto/ecdsa-uclass.h>
+#include <crypto/internal/ecdsa.h>
+#include <dm.h>
+#include <linux/types.h>
+#include <u-boot/ecdsa.h>
+
+static int ops_sw_ecdsa_verify(__always_unused struct udevice *dev,
+ const struct ecdsa_public_key *pubkey,
+ const void *hash, size_t hash_len,
+ const void *signature, size_t sig_len)
+{
+ return ecdsa_hash_verify(pubkey, hash, hash_len, signature, sig_len);
+}
+
+static const struct ecdsa_ops sw_ecdsa_ops = {
+ .verify = ops_sw_ecdsa_verify,
+};
+
+U_BOOT_DRIVER(sw_ecdsa) = {
+ .name = "sw_ecdsa",
+ .id = UCLASS_ECDSA,
+ .ops = &sw_ecdsa_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRVINFO(sw_ecdsa) = {
+ .name = "sw_ecdsa",
+};
+
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [PATCH v5 05/15] drivers: crypto: add software ecdsa support
2026-04-21 21:09 ` [PATCH v5 05/15] drivers: crypto: add software ecdsa support Philippe Reynes
@ 2026-04-22 0:12 ` Simon Glass
0 siblings, 0 replies; 29+ messages in thread
From: Simon Glass @ 2026-04-22 0:12 UTC (permalink / raw)
To: philippe.reynes
Cc: marko.makela, jonny.green, raymondmaoca, trini, simon.glass,
u-boot
Hi Philippe,
On 2026-04-21T21:09:51, Philippe Reynes <philippe.reynes@softathome.com> wrote:
> drivers: crypto: add software ecdsa support
>
> Add a software ecdsa driver so it is
> now possible to use ecdsa signature on
> board without ecdsa hardware support.
>
> Reviewed-by: Raymond Mao <raymondmaoca@gmail.com>
> Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
>
> drivers/crypto/Makefile | 1 +
> drivers/crypto/ecdsa/Makefile | 6 ++++++
> drivers/crypto/ecdsa/ecdsa-sw.c | 33 +++++++++++++++++++++++++++++++++
> 3 files changed, 40 insertions(+)
> diff --git a/drivers/crypto/ecdsa/ecdsa-sw.c b/drivers/crypto/ecdsa/ecdsa-sw.c
> @@ -0,0 +1,33 @@
> +#include <crypto/ecdsa-uclass.h>
> +#include <crypto/internal/ecdsa.h>
> +#include <dm.h>
> +#include <linux/types.h>
> +#include <u-boot/ecdsa.h>
The include of u-boot/ecdsa.h does not appear to be needed - this file
only calls ecdsa_hash_verify() which is declared in
crypto/internal/ecdsa.h. I may be missing something though.
Reviewed-by: Simon Glass <sjg@chromium.org>
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v5 06/15] test: dm: ecdsa.c: clean this test as software ecdsa is now implemented
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (4 preceding siblings ...)
2026-04-21 21:09 ` [PATCH v5 05/15] drivers: crypto: add software ecdsa support Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-22 0:12 ` Simon Glass
2026-04-21 21:09 ` [PATCH v5 07/15] test: py: vboot: prepare integration test for ecdsa Philippe Reynes
` (10 subsequent siblings)
16 siblings, 1 reply; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes
The test ecdsa was done when ecdsa was only supported by hardware.
So it wasn't possible to test ecdsa on sandbox, and there is a test
to check that ecdsa is not supported on sandbox.
Now, there is a software implementation of ecdsa. So we remove
this outdated test.
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v2:
- initial version
v3:
- no change
v4:
- add a test that use ecdsa_verify
v5:
- change secp256r1 to ecdsa256
- check that checksum and crypto are not null
test/dm/ecdsa.c | 107 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 97 insertions(+), 10 deletions(-)
diff --git a/test/dm/ecdsa.c b/test/dm/ecdsa.c
index d7eac7115f7..1e9d5148400 100644
--- a/test/dm/ecdsa.c
+++ b/test/dm/ecdsa.c
@@ -3,36 +3,123 @@
#include <crypto/ecdsa-uclass.h>
#include <dm.h>
#include <dm/test.h>
+#include <malloc.h>
#include <test/ut.h>
#include <u-boot/ecdsa.h>
+#define CHECK(op) ({ \
+ int err = op; \
+ if (err < 0) { \
+ printf("%s: %s: %s\n", __func__, #op, \
+ fdt_strerror(err)); \
+ return err; \
+ } \
+ \
+ err; \
+ })
+
+static int set_fdt_ecdsa_point(char *fdt, char *name, const char *data, size_t len)
+{
+ char *value = NULL;
+ int ret = 0;
+
+ if (!fdt || !name || !data) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ value = malloc(len / 2);
+ if (!value) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = hex2bin(value, data, len / 2);
+ if (ret)
+ goto out;
+
+ ret = fdt_property(fdt, name, value, len / 2);
+ if (ret)
+ goto out;
+
+ out:
+ free(value);
+ return ret;
+}
+
+static int create_fdt_with_ecdsa_key(char *fdt, size_t size,
+ const char *name, const char *curve,
+ const char *x, const char *y)
+{
+ CHECK(fdt_create(fdt, size));
+ CHECK(fdt_finish_reservemap(fdt));
+ CHECK(fdt_begin_node(fdt, ""));
+ CHECK(fdt_begin_node(fdt, "signature"));
+ CHECK(fdt_begin_node(fdt, name));
+ CHECK(fdt_property_string(fdt, "algo", "sha256,ecdsa256"));
+ CHECK(set_fdt_ecdsa_point(fdt, "ecdsa,y-point", y, strlen(y)));
+ CHECK(set_fdt_ecdsa_point(fdt, "ecdsa,x-point", x, strlen(x)));
+ CHECK(fdt_property_string(fdt, "ecdsa,curve", curve));
+ CHECK(fdt_property_string(fdt, "key-name-hint", name));
+ CHECK(fdt_end_node(fdt)); /* name */
+ CHECK(fdt_end_node(fdt)); /* "signature" */
+ CHECK(fdt_end_node(fdt)); /* "" */
+ CHECK(fdt_finish(fdt));
+ CHECK(fdt_pack(fdt));
+
+ return 0;
+}
+
/*
* Basic test of the ECDSA uclass and ecdsa_verify()
*
- * ECDSA implementations in u-boot are hardware-dependent. Until we have a
- * software implementation that can be compiled into the sandbox, all we can
- * test is the uclass support.
+ * ECDSA software implementation is tested in another test,
+ * so we only check that the class UCLASS_ECDSA may be used.
*
- * The uclass_get() test is redundant since ecdsa_verify() would also fail. We
- * run both functions in order to isolate the cause more clearly. i.e. is
- * ecdsa_verify() failing because the UCLASS is absent/broken?
+ * The data used in this test come from RFC6979
*/
static int dm_test_ecdsa_verify(struct unit_test_state *uts)
{
struct uclass *ucp;
+ const char *full_name = "sha256,ecdsa256";
+ const char *name = "key-ecdsa-256";
+ const char *curve = "prime256v1";
+ const char *x = "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6";
+ const char *y = "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299";
+ const char *r = "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716";
+ const char *s = "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8";
+ uint8_t sig[64];
+ size_t fdt_size = 512;
+ char fdt[512];
- struct checksum_algo algo = {
- .checksum_len = 256,
+ struct image_region region[] = {
+ {
+ .data = "sample",
+ .size = strlen("sample"),
+ },
};
struct image_sign_info info = {
- .checksum = &algo,
+ .checksum = image_get_checksum_algo(full_name),
+ .crypto = image_get_crypto_algo(full_name),
+ .fdt_blob = fdt,
};
+ ut_assertnonnull(info.checksum);
+ ut_assertnonnull(info.crypto);
+
+ /* create a fdt with the public key */
+ ut_asserteq(0, create_fdt_with_ecdsa_key(fdt, fdt_size, name, curve, x, y));
+
+ /* prepare the signature */
+ ut_asserteq(0, hex2bin(sig + 0, r, strlen(r) / 2));
+ ut_asserteq(0, hex2bin(sig + 32, s, strlen(s) / 2));
+
ut_assertok(uclass_get(UCLASS_ECDSA, &ucp));
ut_assertnonnull(ucp);
- ut_asserteq(-ENODEV, ecdsa_verify(&info, NULL, 0, NULL, 0));
+ ut_asserteq(0, ecdsa_verify(&info, region, 1, sig, sizeof(sig)));
return 0;
}
+
DM_TEST(dm_test_ecdsa_verify, UTF_SCAN_PDATA | UTF_SCAN_FDT);
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [PATCH v5 06/15] test: dm: ecdsa.c: clean this test as software ecdsa is now implemented
2026-04-21 21:09 ` [PATCH v5 06/15] test: dm: ecdsa.c: clean this test as software ecdsa is now implemented Philippe Reynes
@ 2026-04-22 0:12 ` Simon Glass
0 siblings, 0 replies; 29+ messages in thread
From: Simon Glass @ 2026-04-22 0:12 UTC (permalink / raw)
To: philippe.reynes
Cc: marko.makela, jonny.green, raymondmaoca, trini, simon.glass,
u-boot
Hi Philippe,
On 2026-04-21T21:09:51, Philippe Reynes <philippe.reynes@softathome.com> wrote:
> test: dm: ecdsa.c: clean this test as software ecdsa is now implemented
>
> The test ecdsa was done when ecdsa was only supported by hardware.
> So it wasn't possible to test ecdsa on sandbox, and there is a test
> to check that ecdsa is not supported on sandbox.
> Now, there is a software implementation of ecdsa. So we remove
> this outdated test.
>
> Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
>
> test/dm/ecdsa.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++------
> 1 file changed, 97 insertions(+), 10 deletions(-)
> diff --git a/test/dm/ecdsa.c b/test/dm/ecdsa.c
> @@ -3,36 +3,123 @@
The commit message says "we remove this outdated test" but this patch
refactors it to perform actual ECDSA verification. Please can you
rephrase to describe what it actually does.
> diff --git a/test/dm/ecdsa.c b/test/dm/ecdsa.c
> @@ -3,36 +3,123 @@
> +#define CHECK(op) ({ \
> + int err = op; \
> + if (err < 0) { \
> + printf("%s: %s: %s\n", __func__, #op, \
> + fdt_strerror(err)); \
> + return err; \
> + } \
> + \
> + err; \
> + })
hex2bin() returns -1 on error, which is not a valid fdt_strerror()
input. Consider using a more generic error message.
> diff --git a/test/dm/ecdsa.c b/test/dm/ecdsa.c
> @@ -3,36 +3,123 @@
> + value = malloc(len / 2);
> + if (!value) {
> + ret = -EINVAL;
> + goto out;
> + }
We use -ENOMEM when out of malloc() space.
> diff --git a/test/dm/ecdsa.c b/test/dm/ecdsa.c
> @@ -3,36 +3,123 @@
> + size_t fdt_size = 512;
> + char fdt[512];
The value 512 is duplicated. Please can you use a #define for clarity.
Regards,
Simon
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v5 07/15] test: py: vboot: prepare integration test for ecdsa
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (5 preceding siblings ...)
2026-04-21 21:09 ` [PATCH v5 06/15] test: dm: ecdsa.c: clean this test as software ecdsa is now implemented Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-21 21:09 ` [PATCH v5 08/15] test: vboot: add " Philippe Reynes
` (9 subsequent siblings)
16 siblings, 0 replies; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes, Simon Glass
The vboot tests only consider rsa algo for signature.
To prepare the integration of ecdsa test, the signature
algo is now explicit.
Reviewed-by: Simon Glass <simon.glass@canonical.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v2:
- initial version
v3:
- no change
v4:
- no change
v5:
- no change
test/py/tests/test_fit_ecdsa.py | 2 +-
test/py/tests/test_vboot.py | 99 ++++++++++---------
....its => sign-configs-sha1-rsa2048-pss.its} | 0
...sha1.its => sign-configs-sha1-rsa2048.its} | 0
... sign-configs-sha256-rsa2048-pss-prod.its} | 0
...ts => sign-configs-sha256-rsa2048-pss.its} | 0
...56.its => sign-configs-sha256-rsa2048.its} | 0
...84.its => sign-configs-sha384-rsa3072.its} | 0
...s.its => sign-images-sha1-rsa2048-pss.its} | 0
...-sha1.its => sign-images-sha1-rsa2048.its} | 0
...its => sign-images-sha256-rsa2048-pss.its} | 0
...256.its => sign-images-sha256-rsa2048.its} | 0
...384.its => sign-images-sha384-rsa3072.its} | 0
13 files changed, 51 insertions(+), 50 deletions(-)
rename test/py/tests/vboot/{sign-configs-sha1-pss.its => sign-configs-sha1-rsa2048-pss.its} (100%)
rename test/py/tests/vboot/{sign-configs-sha1.its => sign-configs-sha1-rsa2048.its} (100%)
rename test/py/tests/vboot/{sign-configs-sha256-pss-prod.its => sign-configs-sha256-rsa2048-pss-prod.its} (100%)
rename test/py/tests/vboot/{sign-configs-sha256-pss.its => sign-configs-sha256-rsa2048-pss.its} (100%)
rename test/py/tests/vboot/{sign-configs-sha256.its => sign-configs-sha256-rsa2048.its} (100%)
rename test/py/tests/vboot/{sign-configs-sha384.its => sign-configs-sha384-rsa3072.its} (100%)
rename test/py/tests/vboot/{sign-images-sha1-pss.its => sign-images-sha1-rsa2048-pss.its} (100%)
rename test/py/tests/vboot/{sign-images-sha1.its => sign-images-sha1-rsa2048.its} (100%)
rename test/py/tests/vboot/{sign-images-sha256-pss.its => sign-images-sha256-rsa2048-pss.its} (100%)
rename test/py/tests/vboot/{sign-images-sha256.its => sign-images-sha256-rsa2048.its} (100%)
rename test/py/tests/vboot/{sign-images-sha384.its => sign-images-sha384-rsa3072.its} (100%)
diff --git a/test/py/tests/test_fit_ecdsa.py b/test/py/tests/test_fit_ecdsa.py
index 3e816d68eb6..e59390374af 100644
--- a/test/py/tests/test_fit_ecdsa.py
+++ b/test/py/tests/test_fit_ecdsa.py
@@ -102,7 +102,7 @@ def test_fit_ecdsa(ubman):
with open(key_file, 'w') as f:
f.write(key.export_key(format='PEM'))
- assemble_fit_image(fit_file, f'{datadir}/sign-images-sha256.its', tempdir)
+ assemble_fit_image(fit_file, f'{datadir}/sign-images-sha256-rsa2048.its', tempdir)
fit = SignableFitImage(ubman, fit_file)
nodes = fit.find_signable_image_nodes()
diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py
index 55518bed07e..496d314c649 100644
--- a/test/py/tests/test_vboot.py
+++ b/test/py/tests/test_vboot.py
@@ -84,21 +84,21 @@ def make_fit(its, ubman, mkimage, dtc_args, datadir, fit):
# Only run the full suite on a few combinations, since it doesn't add any more
# test coverage.
TESTDATA_IN = [
- ['sha1-basic', 'sha1', '', None, False, True, False, False],
- ['sha1-pad', 'sha1', '', '-E -p 0x10000', False, False, False, False],
- ['sha1-pss', 'sha1', '-pss', None, False, False, False, False],
- ['sha1-pss-pad', 'sha1', '-pss', '-E -p 0x10000', False, False, False, False],
- ['sha256-basic', 'sha256', '', None, False, False, False, False],
- ['sha256-pad', 'sha256', '', '-E -p 0x10000', False, False, False, False],
- ['sha256-pss', 'sha256', '-pss', None, False, False, False, False],
- ['sha256-pss-pad', 'sha256', '-pss', '-E -p 0x10000', False, False, False, False],
- ['sha256-pss-required', 'sha256', '-pss', None, True, False, False, False],
- ['sha256-pss-pad-required', 'sha256', '-pss', '-E -p 0x10000', True, True, False, False],
- ['sha384-basic', 'sha384', '', None, False, False, False, False],
- ['sha384-pad', 'sha384', '', '-E -p 0x10000', False, False, False, False],
- ['algo-arg', 'algo-arg', '', '-o sha256,rsa2048', False, False, True, False],
- ['sha256-global-sign', 'sha256', '', '', False, False, False, True],
- ['sha256-global-sign-pss', 'sha256', '-pss', '', False, False, False, True],
+ ['sha1-basic', 'sha1', '-rsa2048', '', None, False, True, False, False],
+ ['sha1-pad', 'sha1', '-rsa2048', '', '-E -p 0x10000', False, False, False, False],
+ ['sha1-pss', 'sha1', '-rsa2048', '-pss', None, False, False, False, False],
+ ['sha1-pss-pad', 'sha1', '-rsa2048', '-pss', '-E -p 0x10000', False, False, False, False],
+ ['sha256-basic', 'sha256', '-rsa2048', '', None, False, False, False, False],
+ ['sha256-pad', 'sha256', '-rsa2048', '', '-E -p 0x10000', False, False, False, False],
+ ['sha256-pss', 'sha256', '-rsa2048', '-pss', None, False, False, False, False],
+ ['sha256-pss-pad', 'sha256', '-rsa2048', '-pss', '-E -p 0x10000', False, False, False, False],
+ ['sha256-pss-required', 'sha256', '-rsa2048', '-pss', None, True, False, False, False],
+ ['sha256-pss-pad-required', 'sha256', '-rsa2048', '-pss', '-E -p 0x10000', True, True, False, False],
+ ['sha384-basic', 'sha384', '-rsa3072', '', None, False, False, False, False],
+ ['sha384-pad', 'sha384', '-rsa3072', '', '-E -p 0x10000', False, False, False, False],
+ ['algo-arg', 'algo-arg', '', '', '-o sha256,rsa2048', False, False, True, False],
+ ['sha256-global-sign', 'sha256', '-rsa2048', '', '', False, False, False, True],
+ ['sha256-global-sign-pss', 'sha256', '-rsa2048', '-pss', '', False, False, False, True],
]
# Mark all but the first test as slow, so they are not run with '-k not slow'
@@ -111,9 +111,9 @@ TESTDATA += [pytest.param(*v, marks=pytest.mark.slow) for v in TESTDATA_IN[1:]]
@pytest.mark.requiredtool('fdtget')
@pytest.mark.requiredtool('fdtput')
@pytest.mark.requiredtool('openssl')
-@pytest.mark.parametrize("name,sha_algo,padding,sign_options,required,full_test,algo_arg,global_sign",
+@pytest.mark.parametrize("name,sha_algo,sig_algo,padding,sign_options,required,full_test,algo_arg,global_sign",
TESTDATA)
-def test_vboot(ubman, name, sha_algo, padding, sign_options, required,
+def test_vboot(ubman, name, sha_algo, sig_algo, padding, sign_options, required,
full_test, algo_arg, global_sign):
"""Test verified boot signing with mkimage and verification with 'bootm'.
@@ -287,7 +287,7 @@ def test_vboot(ubman, name, sha_algo, padding, sign_options, required,
utils.run_and_log(ubman, 'openssl req -batch -new -x509 -key %s%s.key '
'-out %s%s.crt' % (tmpdir, name, tmpdir, name))
- def test_with_algo(sha_algo, padding, sign_options):
+ def test_with_algo(sha_algo, sig_algo, padding, sign_options):
"""Test verified boot with the given hash algorithm.
This is the main part of the test code. The same procedure is followed
@@ -308,7 +308,7 @@ def test_vboot(ubman, name, sha_algo, padding, sign_options, required,
# Build the FIT, but don't sign anything yet
ubman.log.action('%s: Test FIT with signed images' % sha_algo)
- make_fit('sign-images-%s%s.its' % (sha_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
+ make_fit('sign-images-%s%s%s.its' % (sha_algo, sig_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
run_bootm(sha_algo, 'unsigned images', ' - OK' if algo_arg else 'dev-', True)
# Sign images with our dev keys
@@ -319,7 +319,7 @@ def test_vboot(ubman, name, sha_algo, padding, sign_options, required,
dtc('sandbox-u-boot.dts', ubman, dtc_args, datadir, tmpdir, dtb)
ubman.log.action('%s: Test FIT with signed configuration' % sha_algo)
- make_fit('sign-configs-%s%s.its' % (sha_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
+ make_fit('sign-configs-%s%s%s.its' % (sha_algo, sig_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
run_bootm(sha_algo, 'unsigned config', '%s+ OK' % ('sha256' if algo_arg else sha_algo), True)
# Sign images with our dev keys
@@ -383,7 +383,7 @@ def test_vboot(ubman, name, sha_algo, padding, sign_options, required,
run_bootm(sha_algo, 'evil clone', 'Bad Data Hash', False, efit)
# Create a new properly signed fit and replace header bytes
- make_fit('sign-configs-%s%s.its' % (sha_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
+ make_fit('sign-configs-%s%s%s.its' % (sha_algo, sig_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
sign_fit(sha_algo, sign_options)
bcfg = ubman.config.buildconfig
max_size = int(bcfg.get('config_fit_signature_max_size', 0x10000000), 0)
@@ -415,7 +415,7 @@ def test_vboot(ubman, name, sha_algo, padding, sign_options, required,
ubman, [fit_check_sign, '-f', fit, '-k', dtb],
1, 'Failed to verify required signature')
- def test_required_key(sha_algo, padding, sign_options):
+ def test_required_key(sha_algo, sig_algo, padding, sign_options):
"""Test verified boot with the given hash algorithm.
This function tests if U-Boot rejects an image when a required key isn't
@@ -437,12 +437,12 @@ def test_vboot(ubman, name, sha_algo, padding, sign_options, required,
# Build the FIT with prod key (keys required) and sign it. This puts the
# signature into sandbox-u-boot.dtb, marked 'required'
- make_fit('sign-configs-%s%s-prod.its' % (sha_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
+ make_fit('sign-configs-%s%s%s-prod.its' % (sha_algo, sig_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
sign_fit(sha_algo, sign_options)
# Build the FIT with dev key (keys NOT required). This adds the
# signature into sandbox-u-boot.dtb, NOT marked 'required'.
- make_fit('sign-configs-%s%s.its' % (sha_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
+ make_fit('sign-configs-%s%s%s.its' % (sha_algo, sig_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
sign_fit_norequire(sha_algo, sign_options)
# So now sandbox-u-boot.dtb two signatures, for the prod and dev keys.
@@ -454,7 +454,7 @@ def test_vboot(ubman, name, sha_algo, padding, sign_options, required,
# Build the FIT with dev key (keys required) and sign it. This puts the
# signature into sandbox-u-boot.dtb, marked 'required'.
- make_fit('sign-configs-%s%s.its' % (sha_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
+ make_fit('sign-configs-%s%s%s.its' % (sha_algo, sig_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
sign_fit(sha_algo, sign_options)
# Set the required-mode policy to "any".
@@ -534,8 +534,9 @@ def test_vboot(ubman, name, sha_algo, padding, sign_options, required,
dtb = '%ssandbox-u-boot.dtb' % tmpdir
sig_node = '/configurations/conf-1/signature'
- create_rsa_pair('dev')
- create_rsa_pair('prod')
+ if sig_algo == "-rsa2048" or sig_algo == "-rsa3072" or sig_algo == "":
+ create_rsa_pair('dev')
+ create_rsa_pair('prod')
# Create a number kernel image with zeroes
with open('%stest-kernel.bin' % tmpdir, 'wb') as fd:
@@ -554,9 +555,9 @@ def test_vboot(ubman, name, sha_algo, padding, sign_options, required,
if global_sign:
test_global_sign(sha_algo, padding, sign_options)
elif required:
- test_required_key(sha_algo, padding, sign_options)
+ test_required_key(sha_algo, sig_algo, padding, sign_options)
else:
- test_with_algo(sha_algo, padding, sign_options)
+ test_with_algo(sha_algo, sig_algo, padding, sign_options)
finally:
# Go back to the original U-Boot with the correct dtb.
ubman.config.dtb = old_dtb
@@ -564,21 +565,21 @@ def test_vboot(ubman, name, sha_algo, padding, sign_options, required,
TESTDATA_IN = [
- ['sha1-basic', 'sha1', '', None, False],
- ['sha1-pad', 'sha1', '', '-E -p 0x10000', False],
- ['sha1-pss', 'sha1', '-pss', None, False],
- ['sha1-pss-pad', 'sha1', '-pss', '-E -p 0x10000', False],
- ['sha256-basic', 'sha256', '', None, False],
- ['sha256-pad', 'sha256', '', '-E -p 0x10000', False],
- ['sha256-pss', 'sha256', '-pss', None, False],
- ['sha256-pss-pad', 'sha256', '-pss', '-E -p 0x10000', False],
- ['sha256-pss-required', 'sha256', '-pss', None, False],
- ['sha256-pss-pad-required', 'sha256', '-pss', '-E -p 0x10000', False],
- ['sha384-basic', 'sha384', '', None, False],
- ['sha384-pad', 'sha384', '', '-E -p 0x10000', False],
- ['algo-arg', 'algo-arg', '', '-o sha256,rsa2048', True],
- ['sha256-global-sign', 'sha256', '', '', False],
- ['sha256-global-sign-pss', 'sha256', '-pss', '', False],
+ ['sha1-basic', 'sha1', '-rsa2048', '', None, False],
+ ['sha1-pad', 'sha1', '-rsa2048', '', '-E -p 0x10000', False],
+ ['sha1-pss', 'sha1', '-rsa2048', '-pss', None, False],
+ ['sha1-pss-pad', 'sha1', '-rsa2048', '-pss', '-E -p 0x10000', False],
+ ['sha256-basic', 'sha256', '-rsa2048', '', None, False],
+ ['sha256-pad', 'sha256', '-rsa2048', '', '-E -p 0x10000', False],
+ ['sha256-pss', 'sha256', '-rsa2048', '-pss', None, False],
+ ['sha256-pss-pad', 'sha256', '-rsa2048', '-pss', '-E -p 0x10000', False],
+ ['sha256-pss-required', 'sha256', '-rsa2048', '-pss', None, False],
+ ['sha256-pss-pad-required', 'sha256', '-rsa2048' , '-pss', '-E -p 0x10000', False],
+ ['sha384-basic', 'sha384', '-rsa3072', '', None, False],
+ ['sha384-pad', 'sha384', '-rsa3072', '', '-E -p 0x10000', False],
+ ['algo-arg', 'algo-arg', '', '', '-o sha256,rsa2048', True],
+ ['sha256-global-sign', 'sha256', '-rsa2048', '', '', False],
+ ['sha256-global-sign-pss', 'sha256', '-rsa2048', '-pss', '', False],
]
# Mark all but the first test as slow, so they are not run with '-k not slow'
@@ -589,8 +590,8 @@ TESTDATA += [pytest.param(*v, marks=pytest.mark.slow) for v in TESTDATA_IN[1:]]
@pytest.mark.buildconfigspec('fit_signature')
@pytest.mark.requiredtool('dtc')
@pytest.mark.requiredtool('openssl')
-@pytest.mark.parametrize("name,sha_algo,padding,sign_options,algo_arg", TESTDATA)
-def test_fdt_add_pubkey(ubman, name, sha_algo, padding, sign_options, algo_arg):
+@pytest.mark.parametrize("name,sha_algo,sig_algo,padding,sign_options,algo_arg", TESTDATA)
+def test_fdt_add_pubkey(ubman, name, sha_algo, sig_algo, padding, sign_options, algo_arg):
"""Test fdt_add_pubkey utility with bunch of different algo options."""
def sign_fit(sha_algo, options):
@@ -609,7 +610,7 @@ def test_fdt_add_pubkey(ubman, name, sha_algo, padding, sign_options, algo_arg):
ubman.log.action('%s: Sign images' % sha_algo)
utils.run_and_log(ubman, args)
- def test_add_pubkey(sha_algo, padding, sign_options):
+ def test_add_pubkey(sha_algo, sig_algo, padding, sign_options):
"""Test fdt_add_pubkey utility with given hash algorithm and padding.
This function tests if fdt_add_pubkey utility may add public keys into dtb.
@@ -632,7 +633,7 @@ def test_fdt_add_pubkey(ubman, name, sha_algo, padding, sign_options, algo_arg):
'rsa3072' if sha_algo == 'sha384' else 'rsa2048'),
'-k', tmpdir, '-n', 'dev', '-r', 'conf', dtb])
- make_fit('sign-configs-%s%s.its' % (sha_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
+ make_fit('sign-configs-%s%s%s.its' % (sha_algo, sig_algo, padding), ubman, mkimage, dtc_args, datadir, fit)
# Sign images with our dev keys
sign_fit(sha_algo, sign_options)
@@ -654,4 +655,4 @@ def test_fdt_add_pubkey(ubman, name, sha_algo, padding, sign_options, algo_arg):
# keys created in test_vboot test
- test_add_pubkey(sha_algo, padding, sign_options)
+ test_add_pubkey(sha_algo, sig_algo, padding, sign_options)
diff --git a/test/py/tests/vboot/sign-configs-sha1-pss.its b/test/py/tests/vboot/sign-configs-sha1-rsa2048-pss.its
similarity index 100%
rename from test/py/tests/vboot/sign-configs-sha1-pss.its
rename to test/py/tests/vboot/sign-configs-sha1-rsa2048-pss.its
diff --git a/test/py/tests/vboot/sign-configs-sha1.its b/test/py/tests/vboot/sign-configs-sha1-rsa2048.its
similarity index 100%
rename from test/py/tests/vboot/sign-configs-sha1.its
rename to test/py/tests/vboot/sign-configs-sha1-rsa2048.its
diff --git a/test/py/tests/vboot/sign-configs-sha256-pss-prod.its b/test/py/tests/vboot/sign-configs-sha256-rsa2048-pss-prod.its
similarity index 100%
rename from test/py/tests/vboot/sign-configs-sha256-pss-prod.its
rename to test/py/tests/vboot/sign-configs-sha256-rsa2048-pss-prod.its
diff --git a/test/py/tests/vboot/sign-configs-sha256-pss.its b/test/py/tests/vboot/sign-configs-sha256-rsa2048-pss.its
similarity index 100%
rename from test/py/tests/vboot/sign-configs-sha256-pss.its
rename to test/py/tests/vboot/sign-configs-sha256-rsa2048-pss.its
diff --git a/test/py/tests/vboot/sign-configs-sha256.its b/test/py/tests/vboot/sign-configs-sha256-rsa2048.its
similarity index 100%
rename from test/py/tests/vboot/sign-configs-sha256.its
rename to test/py/tests/vboot/sign-configs-sha256-rsa2048.its
diff --git a/test/py/tests/vboot/sign-configs-sha384.its b/test/py/tests/vboot/sign-configs-sha384-rsa3072.its
similarity index 100%
rename from test/py/tests/vboot/sign-configs-sha384.its
rename to test/py/tests/vboot/sign-configs-sha384-rsa3072.its
diff --git a/test/py/tests/vboot/sign-images-sha1-pss.its b/test/py/tests/vboot/sign-images-sha1-rsa2048-pss.its
similarity index 100%
rename from test/py/tests/vboot/sign-images-sha1-pss.its
rename to test/py/tests/vboot/sign-images-sha1-rsa2048-pss.its
diff --git a/test/py/tests/vboot/sign-images-sha1.its b/test/py/tests/vboot/sign-images-sha1-rsa2048.its
similarity index 100%
rename from test/py/tests/vboot/sign-images-sha1.its
rename to test/py/tests/vboot/sign-images-sha1-rsa2048.its
diff --git a/test/py/tests/vboot/sign-images-sha256-pss.its b/test/py/tests/vboot/sign-images-sha256-rsa2048-pss.its
similarity index 100%
rename from test/py/tests/vboot/sign-images-sha256-pss.its
rename to test/py/tests/vboot/sign-images-sha256-rsa2048-pss.its
diff --git a/test/py/tests/vboot/sign-images-sha256.its b/test/py/tests/vboot/sign-images-sha256-rsa2048.its
similarity index 100%
rename from test/py/tests/vboot/sign-images-sha256.its
rename to test/py/tests/vboot/sign-images-sha256-rsa2048.its
diff --git a/test/py/tests/vboot/sign-images-sha384.its b/test/py/tests/vboot/sign-images-sha384-rsa3072.its
similarity index 100%
rename from test/py/tests/vboot/sign-images-sha384.its
rename to test/py/tests/vboot/sign-images-sha384-rsa3072.its
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [PATCH v5 08/15] test: vboot: add test for ecdsa
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (6 preceding siblings ...)
2026-04-21 21:09 ` [PATCH v5 07/15] test: py: vboot: prepare integration test for ecdsa Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-21 21:09 ` [PATCH v5 09/15] tools: fit_image_setup_sig: set required_keynode to -1 Philippe Reynes
` (8 subsequent siblings)
16 siblings, 0 replies; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes, Simon Glass
This commit adds test case for ecdsa on fit, but not (yet) for
the global image signature (preload).
Reviewed-by: Simon Glass <simon.glass@canonical.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v2:
- initial version
v3:
- no change
v4:
- no change
v5:
- no change
test/py/tests/test_vboot.py | 29 ++++++++++++
.../vboot/sign-configs-sha256-ecdsa256.its | 45 +++++++++++++++++++
.../vboot/sign-configs-sha256-ecdsa384.its | 45 +++++++++++++++++++
.../vboot/sign-configs-sha256-ecdsa521.its | 45 +++++++++++++++++++
.../vboot/sign-images-sha256-ecdsa256.its | 42 +++++++++++++++++
.../vboot/sign-images-sha256-ecdsa384.its | 42 +++++++++++++++++
.../vboot/sign-images-sha256-ecdsa521.its | 42 +++++++++++++++++
7 files changed, 290 insertions(+)
create mode 100644 test/py/tests/vboot/sign-configs-sha256-ecdsa256.its
create mode 100644 test/py/tests/vboot/sign-configs-sha256-ecdsa384.its
create mode 100644 test/py/tests/vboot/sign-configs-sha256-ecdsa521.its
create mode 100644 test/py/tests/vboot/sign-images-sha256-ecdsa256.its
create mode 100644 test/py/tests/vboot/sign-images-sha256-ecdsa384.its
create mode 100644 test/py/tests/vboot/sign-images-sha256-ecdsa521.its
diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py
index 496d314c649..4e4d9529031 100644
--- a/test/py/tests/test_vboot.py
+++ b/test/py/tests/test_vboot.py
@@ -94,6 +94,9 @@ TESTDATA_IN = [
['sha256-pss-pad', 'sha256', '-rsa2048', '-pss', '-E -p 0x10000', False, False, False, False],
['sha256-pss-required', 'sha256', '-rsa2048', '-pss', None, True, False, False, False],
['sha256-pss-pad-required', 'sha256', '-rsa2048', '-pss', '-E -p 0x10000', True, True, False, False],
+ ['sha256-basic-ecdsa256', 'sha256', '-ecdsa256', '', None, False, False, False, False],
+ ['sha256-basic-ecdsa384', 'sha256', '-ecdsa384', '', None, False, False, False, False],
+ ['sha256-basic-ecdsa521', 'sha256', '-ecdsa521', '', None, False, False, False, False],
['sha384-basic', 'sha384', '-rsa3072', '', None, False, False, False, False],
['sha384-pad', 'sha384', '-rsa3072', '', '-E -p 0x10000', False, False, False, False],
['algo-arg', 'algo-arg', '', '', '-o sha256,rsa2048', False, False, True, False],
@@ -287,6 +290,29 @@ def test_vboot(ubman, name, sha_algo, sig_algo, padding, sign_options, required,
utils.run_and_log(ubman, 'openssl req -batch -new -x509 -key %s%s.key '
'-out %s%s.crt' % (tmpdir, name, tmpdir, name))
+ def create_ecdsa_pair(name):
+ """Generate a new ECDSA key pair
+
+ Args:
+ name: Name of the key (e.g. 'dev')
+ """
+
+ if sig_algo == "-ecdsa256":
+ curve_name = "secp256r1"
+ elif sig_algo == "-ecdsa384":
+ curve_name = "secp384r1"
+ elif sig_algo == "-ecdsa521":
+ curve_name = "secp521r1"
+ else:
+ curve_name = "unknownCurve"
+
+ utils.run_and_log(ubman, 'openssl ecparam -name %s -genkey -noout -out %s%s.pem' %
+ (curve_name, tmpdir, name))
+
+ # Create a certificate containing the public key
+ utils.run_and_log(ubman, 'openssl req -batch -new -x509 -key %s%s.pem '
+ '-out %s%s.crt' % (tmpdir, name, tmpdir, name))
+
def test_with_algo(sha_algo, sig_algo, padding, sign_options):
"""Test verified boot with the given hash algorithm.
@@ -537,6 +563,9 @@ def test_vboot(ubman, name, sha_algo, sig_algo, padding, sign_options, required,
if sig_algo == "-rsa2048" or sig_algo == "-rsa3072" or sig_algo == "":
create_rsa_pair('dev')
create_rsa_pair('prod')
+ elif sig_algo == "-ecdsa256" or sig_algo == "-ecdsa384" or sig_algo == "-ecdsa521":
+ create_ecdsa_pair('dev')
+ create_ecdsa_pair('prod')
# Create a number kernel image with zeroes
with open('%stest-kernel.bin' % tmpdir, 'wb') as fd:
diff --git a/test/py/tests/vboot/sign-configs-sha256-ecdsa256.its b/test/py/tests/vboot/sign-configs-sha256-ecdsa256.its
new file mode 100644
index 00000000000..4d0ef903a78
--- /dev/null
+++ b/test/py/tests/vboot/sign-configs-sha256-ecdsa256.its
@@ -0,0 +1,45 @@
+/dts-v1/;
+
+/ {
+ description = "Chrome OS kernel image with one or more FDT blobs";
+ #address-cells = <1>;
+
+ images {
+ kernel {
+ data = /incbin/("test-kernel.bin");
+ type = "kernel_noload";
+ arch = "sandbox";
+ os = "linux";
+ compression = "none";
+ load = <0x4>;
+ entry = <0x8>;
+ kernel-version = <1>;
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ fdt-1 {
+ description = "snow";
+ data = /incbin/("sandbox-kernel.dtb");
+ type = "flat_dt";
+ arch = "sandbox";
+ compression = "none";
+ fdt-version = <1>;
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ };
+ configurations {
+ default = "conf-1";
+ conf-1 {
+ kernel = "kernel";
+ fdt = "fdt-1";
+ signature {
+ algo = "sha256,ecdsa256";
+ key-name-hint = "dev";
+ sign-images = "fdt", "kernel";
+ };
+ };
+ };
+};
diff --git a/test/py/tests/vboot/sign-configs-sha256-ecdsa384.its b/test/py/tests/vboot/sign-configs-sha256-ecdsa384.its
new file mode 100644
index 00000000000..10427b43659
--- /dev/null
+++ b/test/py/tests/vboot/sign-configs-sha256-ecdsa384.its
@@ -0,0 +1,45 @@
+/dts-v1/;
+
+/ {
+ description = "Chrome OS kernel image with one or more FDT blobs";
+ #address-cells = <1>;
+
+ images {
+ kernel {
+ data = /incbin/("test-kernel.bin");
+ type = "kernel_noload";
+ arch = "sandbox";
+ os = "linux";
+ compression = "none";
+ load = <0x4>;
+ entry = <0x8>;
+ kernel-version = <1>;
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ fdt-1 {
+ description = "snow";
+ data = /incbin/("sandbox-kernel.dtb");
+ type = "flat_dt";
+ arch = "sandbox";
+ compression = "none";
+ fdt-version = <1>;
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ };
+ configurations {
+ default = "conf-1";
+ conf-1 {
+ kernel = "kernel";
+ fdt = "fdt-1";
+ signature {
+ algo = "sha256,ecdsa384";
+ key-name-hint = "dev";
+ sign-images = "fdt", "kernel";
+ };
+ };
+ };
+};
diff --git a/test/py/tests/vboot/sign-configs-sha256-ecdsa521.its b/test/py/tests/vboot/sign-configs-sha256-ecdsa521.its
new file mode 100644
index 00000000000..a65593ec64b
--- /dev/null
+++ b/test/py/tests/vboot/sign-configs-sha256-ecdsa521.its
@@ -0,0 +1,45 @@
+/dts-v1/;
+
+/ {
+ description = "Chrome OS kernel image with one or more FDT blobs";
+ #address-cells = <1>;
+
+ images {
+ kernel {
+ data = /incbin/("test-kernel.bin");
+ type = "kernel_noload";
+ arch = "sandbox";
+ os = "linux";
+ compression = "none";
+ load = <0x4>;
+ entry = <0x8>;
+ kernel-version = <1>;
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ fdt-1 {
+ description = "snow";
+ data = /incbin/("sandbox-kernel.dtb");
+ type = "flat_dt";
+ arch = "sandbox";
+ compression = "none";
+ fdt-version = <1>;
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ };
+ configurations {
+ default = "conf-1";
+ conf-1 {
+ kernel = "kernel";
+ fdt = "fdt-1";
+ signature {
+ algo = "sha256,ecdsa521";
+ key-name-hint = "dev";
+ sign-images = "fdt", "kernel";
+ };
+ };
+ };
+};
diff --git a/test/py/tests/vboot/sign-images-sha256-ecdsa256.its b/test/py/tests/vboot/sign-images-sha256-ecdsa256.its
new file mode 100644
index 00000000000..009003bb601
--- /dev/null
+++ b/test/py/tests/vboot/sign-images-sha256-ecdsa256.its
@@ -0,0 +1,42 @@
+/dts-v1/;
+
+/ {
+ description = "Chrome OS kernel image with one or more FDT blobs";
+ #address-cells = <1>;
+
+ images {
+ kernel {
+ data = /incbin/("test-kernel.bin");
+ type = "kernel_noload";
+ arch = "sandbox";
+ os = "linux";
+ compression = "none";
+ load = <0x4>;
+ entry = <0x8>;
+ kernel-version = <1>;
+ signature {
+ algo = "sha256,ecdsa256";
+ key-name-hint = "dev";
+ };
+ };
+ fdt-1 {
+ description = "snow";
+ data = /incbin/("sandbox-kernel.dtb");
+ type = "flat_dt";
+ arch = "sandbox";
+ compression = "none";
+ fdt-version = <1>;
+ signature {
+ algo = "sha256,ecdsa256";
+ key-name-hint = "dev";
+ };
+ };
+ };
+ configurations {
+ default = "conf-1";
+ conf-1 {
+ kernel = "kernel";
+ fdt = "fdt-1";
+ };
+ };
+};
diff --git a/test/py/tests/vboot/sign-images-sha256-ecdsa384.its b/test/py/tests/vboot/sign-images-sha256-ecdsa384.its
new file mode 100644
index 00000000000..567de687a06
--- /dev/null
+++ b/test/py/tests/vboot/sign-images-sha256-ecdsa384.its
@@ -0,0 +1,42 @@
+/dts-v1/;
+
+/ {
+ description = "Chrome OS kernel image with one or more FDT blobs";
+ #address-cells = <1>;
+
+ images {
+ kernel {
+ data = /incbin/("test-kernel.bin");
+ type = "kernel_noload";
+ arch = "sandbox";
+ os = "linux";
+ compression = "none";
+ load = <0x4>;
+ entry = <0x8>;
+ kernel-version = <1>;
+ signature {
+ algo = "sha256,ecdsa384";
+ key-name-hint = "dev";
+ };
+ };
+ fdt-1 {
+ description = "snow";
+ data = /incbin/("sandbox-kernel.dtb");
+ type = "flat_dt";
+ arch = "sandbox";
+ compression = "none";
+ fdt-version = <1>;
+ signature {
+ algo = "sha256,ecdsa384";
+ key-name-hint = "dev";
+ };
+ };
+ };
+ configurations {
+ default = "conf-1";
+ conf-1 {
+ kernel = "kernel";
+ fdt = "fdt-1";
+ };
+ };
+};
diff --git a/test/py/tests/vboot/sign-images-sha256-ecdsa521.its b/test/py/tests/vboot/sign-images-sha256-ecdsa521.its
new file mode 100644
index 00000000000..74ed45b21b8
--- /dev/null
+++ b/test/py/tests/vboot/sign-images-sha256-ecdsa521.its
@@ -0,0 +1,42 @@
+/dts-v1/;
+
+/ {
+ description = "Chrome OS kernel image with one or more FDT blobs";
+ #address-cells = <1>;
+
+ images {
+ kernel {
+ data = /incbin/("test-kernel.bin");
+ type = "kernel_noload";
+ arch = "sandbox";
+ os = "linux";
+ compression = "none";
+ load = <0x4>;
+ entry = <0x8>;
+ kernel-version = <1>;
+ signature {
+ algo = "sha256,ecdsa521";
+ key-name-hint = "dev";
+ };
+ };
+ fdt-1 {
+ description = "snow";
+ data = /incbin/("sandbox-kernel.dtb");
+ type = "flat_dt";
+ arch = "sandbox";
+ compression = "none";
+ fdt-version = <1>;
+ signature {
+ algo = "sha256,ecdsa521";
+ key-name-hint = "dev";
+ };
+ };
+ };
+ configurations {
+ default = "conf-1";
+ conf-1 {
+ kernel = "kernel";
+ fdt = "fdt-1";
+ };
+ };
+};
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [PATCH v5 09/15] tools: fit_image_setup_sig: set required_keynode to -1
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (7 preceding siblings ...)
2026-04-21 21:09 ` [PATCH v5 08/15] test: vboot: add " Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-22 0:13 ` Simon Glass
2026-04-21 21:09 ` [PATCH v5 10/15] tools: mkimage: pre-load: add support of ecdsa Philippe Reynes
` (7 subsequent siblings)
16 siblings, 1 reply; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes
When initializing info about a signature, set required_keynode
to -1 instead of 0, as 0 is a valid keynode offset.
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v5:
- initial version
tools/image-host.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/image-host.c b/tools/image-host.c
index 8b550af0dc1..f5681d6c1f9 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -198,6 +198,7 @@ static int fit_image_setup_sig(struct image_sign_info *info,
info->checksum = image_get_checksum_algo(algo_name);
info->crypto = image_get_crypto_algo(algo_name);
info->padding = image_get_padding_algo(padding_name);
+ info->required_keynode = -1;
info->require_keys = require_keys;
info->engine_id = engine_id;
if (!info->checksum || !info->crypto) {
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [PATCH v5 09/15] tools: fit_image_setup_sig: set required_keynode to -1
2026-04-21 21:09 ` [PATCH v5 09/15] tools: fit_image_setup_sig: set required_keynode to -1 Philippe Reynes
@ 2026-04-22 0:13 ` Simon Glass
0 siblings, 0 replies; 29+ messages in thread
From: Simon Glass @ 2026-04-22 0:13 UTC (permalink / raw)
To: philippe.reynes
Cc: marko.makela, jonny.green, raymondmaoca, trini, simon.glass,
u-boot
On 2026-04-21T21:09:51, Philippe Reynes <philippe.reynes@softathome.com> wrote:
> tools: fit_image_setup_sig: set required_keynode to -1
>
> When initializing info about a signature, set required_keynode
> to -1 instead of 0, as 0 is a valid keynode offset.
>
> Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
>
> tools/image-host.c | 1 +
> 1 file changed, 1 insertion(+)
Reviewed-by: Simon Glass <sjg@chromium.org>
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v5 10/15] tools: mkimage: pre-load: add support of ecdsa
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (8 preceding siblings ...)
2026-04-21 21:09 ` [PATCH v5 09/15] tools: fit_image_setup_sig: set required_keynode to -1 Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-21 21:09 ` [PATCH v5 11/15] tools: binman: " Philippe Reynes
` (6 subsequent siblings)
16 siblings, 0 replies; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes, Simon Glass
Right now, mkimage can only create pre-load header
using rsa. We add the support of ecdsa.
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v3:
- initial version
v4:
- use pre_load_noffset (do not compute it again)
- release memory allocated with strdup
- clean code
v5:
- check checksum and algo before using them
lib/ecdsa/ecdsa-libcrypto.c | 29 +++++++++---
tools/image-host.c | 92 ++++++++++++++++++++++++++++++++-----
2 files changed, 103 insertions(+), 18 deletions(-)
diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c
index 41590d22a51..0c7d1809a05 100644
--- a/lib/ecdsa/ecdsa-libcrypto.c
+++ b/lib/ecdsa/ecdsa-libcrypto.c
@@ -505,14 +505,9 @@ int ecdsa_verify(struct image_sign_info *info,
return ret;
}
-static int do_add(struct signer *ctx, void *fdt, const char *key_node_name,
- struct image_sign_info *info)
+static int search_key_node(void *fdt, const char *key_node_name)
{
- int signature_node, key_node, ret, key_bits;
- const char *curve_name;
- const EC_GROUP *group;
- const EC_POINT *point;
- BIGNUM *x, *y;
+ int signature_node, key_node;
signature_node = fdt_subnode_offset(fdt, 0, FIT_SIG_NODENAME);
if (signature_node == -FDT_ERR_NOTFOUND) {
@@ -547,6 +542,26 @@ static int do_add(struct signer *ctx, void *fdt, const char *key_node_name,
return key_node;
}
+ return key_node;
+}
+
+static int do_add(struct signer *ctx, void *fdt, const char *key_node_name,
+ struct image_sign_info *info)
+{
+ int key_node, ret, key_bits;
+ const char *curve_name;
+ const EC_GROUP *group;
+ const EC_POINT *point;
+ BIGNUM *x, *y;
+
+ if (info->required_keynode >= 0) {
+ key_node = info->required_keynode;
+ } else {
+ key_node = search_key_node(fdt, key_node_name);
+ if (key_node < 0)
+ return key_node;
+ }
+
group = EC_KEY_get0_group(ctx->ecdsa_key);
key_bits = EC_GROUP_order_bits(group);
curve_name = OBJ_nid2sn(EC_GROUP_get_curve_name(group));
diff --git a/tools/image-host.c b/tools/image-host.c
index f5681d6c1f9..ae35a75d5a6 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -13,6 +13,7 @@
#include <fdt_region.h>
#include <image.h>
#include <version.h>
+#include <u-boot/ecdsa.h>
#if CONFIG_IS_ENABLED(FIT_SIGNATURE)
#include <openssl/pem.h>
@@ -1245,13 +1246,74 @@ err_cert:
return ret;
}
+static int fit_pre_load_data_key_rsa(const char *keydir, void *keydest,
+ int pre_load_noffset, const void *key_name)
+{
+ unsigned char *pubkey = NULL;
+ int ret, pubkey_len;
+
+ /* Read public key */
+ ret = read_pub_key(keydir, key_name, &pubkey, &pubkey_len);
+ if (ret < 0)
+ goto out;
+
+ /* Add the public key to the device tree */
+ ret = fdt_setprop(keydest, pre_load_noffset, "public-key",
+ pubkey, pubkey_len);
+ if (ret)
+ fprintf(stderr, "Can't set public-key in node %s (ret = %d)\n",
+ IMAGE_PRE_LOAD_PATH, ret);
+ out:
+ return ret;
+}
+
+static int fit_pre_load_data_key_ecdsa(const char *keydir, void *keydest,
+ int pre_load_noffset, const void *key_name,
+ const void *algo_name)
+{
+ struct image_sign_info info;
+ int node, ret = 0;
+
+ memset(&info, 0, sizeof(info));
+ info.keydir = keydir;
+ info.keyname = strdup(key_name);
+ info.name = strdup(algo_name);
+ info.checksum = image_get_checksum_algo(algo_name);
+ if (!info.checksum) {
+ fprintf(stderr, "Can't find valid checksum from %s\n",
+ (char *)algo_name);
+ ret = -EINVAL;
+ goto out;
+ }
+ info.crypto = image_get_crypto_algo(algo_name);
+ if (!info.crypto) {
+ fprintf(stderr, "Can't find valid crypto from %s\n",
+ (char *)algo_name);
+ ret = -EINVAL;
+ goto out;
+ }
+ info.required_keynode = pre_load_noffset;
+
+ node = ecdsa_add_verify_data(&info, keydest);
+ if (node < 0) {
+ fprintf(stderr, "Can't add verify data: err = %d\n", node);
+ ret = -EIO;
+ }
+
+ out:
+ free((void *)info.keyname);
+ free((void *)info.name);
+
+ return ret;
+}
+
int fit_pre_load_data(const char *keydir, void *keydest, void *fit)
{
int pre_load_noffset;
const void *algo_name;
const void *key_name;
- unsigned char *pubkey = NULL;
- int ret, pubkey_len;
+ char *name;
+ int ret;
if (!keydir || !keydest || !fit)
return 0;
@@ -1278,17 +1340,25 @@ int fit_pre_load_data(const char *keydir, void *keydest, void *fit)
goto out;
}
- /* Read public key */
- ret = read_pub_key(keydir, key_name, &pubkey, &pubkey_len);
- if (ret < 0)
+ /* Is it a RSA or an ECDSA key */
+ name = strchr((const char *)algo_name, ',');
+ if (!name) {
+ fprintf(stderr, "The name of the algo is invalid: %s\n",
+ (char *)algo_name);
+ ret = -EINVAL;
goto out;
+ }
+ name += 1;
- /* Add the public key to the device tree */
- ret = fdt_setprop(keydest, pre_load_noffset, "public-key",
- pubkey, pubkey_len);
- if (ret)
- fprintf(stderr, "Can't set public-key in node %s (ret = %d)\n",
- IMAGE_PRE_LOAD_PATH, ret);
+ if (!strncmp(name, "rsa", 3)) {
+ ret = fit_pre_load_data_key_rsa(keydir, keydest, pre_load_noffset, key_name);
+ } else if (!strncmp(name, "ecdsa", 5)) {
+ ret = fit_pre_load_data_key_ecdsa(keydir, keydest, pre_load_noffset,
+ key_name, algo_name);
+ } else {
+ fprintf(stderr, "The algo %s is not supported\n", (char *)algo_name);
+ ret = -EINVAL;
+ }
out:
return ret;
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [PATCH v5 11/15] tools: binman: pre-load: add support of ecdsa
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (9 preceding siblings ...)
2026-04-21 21:09 ` [PATCH v5 10/15] tools: mkimage: pre-load: add support of ecdsa Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-21 21:09 ` [PATCH v5 12/15] boot: " Philippe Reynes
` (5 subsequent siblings)
16 siblings, 0 replies; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes, Simon Glass
Right now, binman can only create pre-load header
using rsa. We add the support of ecdsa.
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v3:
- initial version
v4:
- merge patch 11 that was adding test for ecdsa pre-load
- add key size check
- use exc instead of simply e
- rename dts filaneme
- add a test to check key size
v5:
- compute ecdsa521 sig instead of using hardcoded value 132
- fix english: don't -> doesn't
- avoid line too long
tools/binman/etype/pre_load.py | 78 ++++++++++++++++---
tools/binman/ftest.py | 52 +++++++++++++
tools/binman/test/ecdsa521.pem | 7 ++
tools/binman/test/security/pre_load_ecdsa.dts | 22 ++++++
.../security/pre_load_ecdsa_invalid_algo.dts | 22 ++++++
.../security/pre_load_ecdsa_invalid_key.dts | 22 ++++++
.../security/pre_load_ecdsa_invalid_sha.dts | 22 ++++++
7 files changed, 216 insertions(+), 9 deletions(-)
create mode 100644 tools/binman/test/ecdsa521.pem
create mode 100644 tools/binman/test/security/pre_load_ecdsa.dts
create mode 100644 tools/binman/test/security/pre_load_ecdsa_invalid_algo.dts
create mode 100644 tools/binman/test/security/pre_load_ecdsa_invalid_key.dts
create mode 100644 tools/binman/test/security/pre_load_ecdsa_invalid_sha.dts
diff --git a/tools/binman/etype/pre_load.py b/tools/binman/etype/pre_load.py
index 00f1a896767..3d4a30391a6 100644
--- a/tools/binman/etype/pre_load.py
+++ b/tools/binman/etype/pre_load.py
@@ -16,8 +16,10 @@ from binman.entry import EntryArg
from Cryptodome.Hash import SHA256, SHA384, SHA512
from Cryptodome.PublicKey import RSA
+from Cryptodome.PublicKey import ECC
from Cryptodome.Signature import pkcs1_15
from Cryptodome.Signature import pss
+from Cryptodome.Signature import DSS
PRE_LOAD_MAGIC = b'UBSH'
@@ -27,6 +29,12 @@ RSAS = {
'rsa4096': 4096 / 8
}
+ECDSAS = {
+ 'ecdsa256': 256 / 8 * 2,
+ 'ecdsa384': 384 / 8 * 2,
+ 'ecdsa521': (521 + 7) / 8 * 2
+}
+
SHAS = {
'sha256': SHA256,
'sha384': SHA384,
@@ -86,24 +94,17 @@ class Entry_pre_load(Entry_collection):
if self.key_path is None:
self.key_path = ''
- def _CreateHeader(self):
- """Create a pre load header"""
- hash_name, sign_name = self.algo_name.split(',')
- padding_name = self.padding_name
- key_name = os.path.join(self.key_path, self.key_name)
-
+ def _CreateHeaderRsa(self, hash_name, sign_name, padding_name, key_name):
# Check hash and signature name/type
if hash_name not in SHAS:
self.Raise(hash_name + " is not supported")
- if sign_name not in RSAS:
- self.Raise(sign_name + " is not supported")
# Read the key
key = RSA.import_key(tools.read_file(key_name))
# Check if the key has the expected size
if key.size_in_bytes() != RSAS[sign_name]:
- self.Raise("The key " + self.key_name + " don't have the expected size")
+ self.Raise("The key " + self.key_name + " doesn't have the expected size")
# Compute the hash
hash_image = SHAS[hash_name].new()
@@ -151,6 +152,65 @@ class Entry_pre_load(Entry_collection):
return data + pad
+ def _CreateHeaderEcdsa(self, hash_name, sign_name, key_name):
+ # Check hash and signature name/type
+ if hash_name not in SHAS:
+ self.Raise(hash_name + " is not supported")
+
+ # Read the key
+ key = ECC.import_key(tools.read_file(key_name))
+
+ # Check if the key has the expected size
+ if key.pointQ.size_in_bytes() * 2 != ECDSAS[sign_name]:
+ self.Raise("The key " + self.key_name + " doesn't have the expected size")
+
+ # Compute the hash
+ hash_image = SHAS[hash_name].new()
+ hash_image.update(self.image)
+
+ # Compute the signature
+ signer = DSS.new(key, 'fips-186-3')
+ sig = signer.sign(hash_image)
+
+ hash_sig = SHA256.new()
+ hash_sig.update(sig)
+
+ version = self.version
+ header_size = self.header_size
+ image_size = len(self.image)
+ ofs_img_sig = 64 + len(sig)
+ flags = 0
+ reserved0 = 0
+ reserved1 = 0
+
+ first_header = struct.pack('>4sIIIIIII32s', PRE_LOAD_MAGIC,
+ version, header_size, image_size,
+ ofs_img_sig, flags, reserved0,
+ reserved1, hash_sig.digest())
+
+ hash_first_header = SHAS[hash_name].new()
+ hash_first_header.update(first_header)
+ sig_first_header = signer.sign(hash_first_header)
+
+ data = first_header + sig_first_header + sig
+ pad = bytearray(self.header_size - len(data))
+
+ return data + pad
+
+ def _CreateHeader(self):
+ """Create a pre load header"""
+ hash_name, sign_name = self.algo_name.split(',')
+ padding_name = self.padding_name
+ key_name = os.path.join(self.key_path, self.key_name)
+
+ if sign_name in RSAS:
+ return self._CreateHeaderRsa(hash_name, sign_name, padding_name, key_name)
+
+ if sign_name in ECDSAS:
+ return self._CreateHeaderEcdsa(hash_name, sign_name, key_name)
+
+ self.Raise(sign_name + " is not supported")
+
def ObtainContents(self):
"""Obtain a placeholder for the header contents"""
# wait that the image is available
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index ca5149ee654..5d5bcb5874f 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -5895,6 +5895,58 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
data = self._DoReadFileDtb('security/pre_load_invalid_key.dts',
entry_args=entry_args)
+ def testPreLoadEcdsa(self):
+ """Test an image with a pre-load header using ecdsa key"""
+ entry_args = {
+ 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
+ }
+ data = self._DoReadFileDtb(
+ 'security/pre_load_ecdsa.dts', entry_args=entry_args,
+ extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
+
+ image_fname = tools.get_output_filename('image.bin')
+ is_signed = self._CheckPreload(image_fname,
+ self.TestFile('ecdsa521.pem'),
+ 'sha256,ecdsa521')
+
+ self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
+ self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
+ self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
+ self.assertEqual(is_signed, True)
+
+ def testPreLoadEcdsaInvalidSha(self):
+ """Test an image with a pre-load ecdsa header with an invalid hash"""
+ entry_args = {
+ 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
+ }
+ with self.assertRaises(ValueError) as exc:
+ self._DoReadFileDtb('security/pre_load_ecdsa_invalid_sha.dts',
+ entry_args=entry_args)
+ self.assertIn("Node '/binman/pre-load': sha2560 is not supported",
+ str(exc.exception))
+
+ def testPreLoadEcdsaInvalidAlgo(self):
+ """Test an image with a pre-load header with an invalid algo"""
+ entry_args = {
+ 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
+ }
+ with self.assertRaises(ValueError) as exc:
+ data = self._DoReadFileDtb('security/pre_load_ecdsa_invalid_algo.dts',
+ entry_args=entry_args)
+ self.assertIn("Node '/binman/pre-load': ecdsa5210 is not supported",
+ str(exc.exception))
+
+ def testPreLoadEcdsaInvalidKey(self):
+ """Test an image with a pre-load header with an invalid key size"""
+ entry_args = {
+ 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
+ }
+ with self.assertRaises(ValueError) as exc:
+ data = self._DoReadFileDtb('security/pre_load_ecdsa_invalid_key.dts',
+ entry_args=entry_args)
+ self.assertIn("Node '/binman/pre-load': The key ecdsa521.pem doesn't have the expected size",
+ str(exc.exception))
+
def _CheckSafeUniqueNames(self, *images):
"""Check all entries of given images for unsafe unique names"""
for image in images:
diff --git a/tools/binman/test/ecdsa521.pem b/tools/binman/test/ecdsa521.pem
new file mode 100644
index 00000000000..ac1904d3955
--- /dev/null
+++ b/tools/binman/test/ecdsa521.pem
@@ -0,0 +1,7 @@
+-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIBM+CNnraGci2/mw1wPq44l2HccHnoBbdP3DiU6zqsBOq8IR8uegz2
+FLzWsjxcW7hwROCdEm6tW99wqsyPE25RZ3egBwYFK4EEACOhgYkDgYYABABu5bWV
+aQ4EgnXFjojX9df3gBEBipphEEFAoG87GuoWBdlimFC8UEEXiKNU37w0wlJn4bG0
+8uOKwDqBk3uF+DrmZwB45lCSKkjdRWsJeDt+iEuFe2O/mbXoL4p5D8MM2OsDV5GT
+srUbxhXq+T/i5lV7XXm2+tT/7zU8ZQce6WRufbd9KQ==
+-----END EC PRIVATE KEY-----
diff --git a/tools/binman/test/security/pre_load_ecdsa.dts b/tools/binman/test/security/pre_load_ecdsa.dts
new file mode 100644
index 00000000000..247b85aad4c
--- /dev/null
+++ b/tools/binman/test/security/pre_load_ecdsa.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pre-load {
+ content = <&image>;
+ algo-name = "sha256,ecdsa521";
+ key-name = "ecdsa521.pem";
+ header-size = <4096>;
+ version = <0x11223344>;
+ };
+
+ image: blob-ext {
+ filename = "refcode.bin";
+ };
+ };
+};
diff --git a/tools/binman/test/security/pre_load_ecdsa_invalid_algo.dts b/tools/binman/test/security/pre_load_ecdsa_invalid_algo.dts
new file mode 100644
index 00000000000..be71edbbdcd
--- /dev/null
+++ b/tools/binman/test/security/pre_load_ecdsa_invalid_algo.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pre-load {
+ content = <&image>;
+ algo-name = "sha256,ecdsa5210";
+ key-name = "ecdsa521.pem";
+ header-size = <4096>;
+ version = <0x11223344>;
+ };
+
+ image: blob-ext {
+ filename = "refcode.bin";
+ };
+ };
+};
diff --git a/tools/binman/test/security/pre_load_ecdsa_invalid_key.dts b/tools/binman/test/security/pre_load_ecdsa_invalid_key.dts
new file mode 100644
index 00000000000..15d71cf0324
--- /dev/null
+++ b/tools/binman/test/security/pre_load_ecdsa_invalid_key.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pre-load {
+ content = <&image>;
+ algo-name = "sha256,ecdsa384";
+ key-name = "ecdsa521.pem";
+ header-size = <4096>;
+ version = <0x11223344>;
+ };
+
+ image: blob-ext {
+ filename = "refcode.bin";
+ };
+ };
+};
diff --git a/tools/binman/test/security/pre_load_ecdsa_invalid_sha.dts b/tools/binman/test/security/pre_load_ecdsa_invalid_sha.dts
new file mode 100644
index 00000000000..1017707375e
--- /dev/null
+++ b/tools/binman/test/security/pre_load_ecdsa_invalid_sha.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pre-load {
+ content = <&image>;
+ algo-name = "sha2560,ecdsa521";
+ key-name = "ecdsa521.pem";
+ header-size = <4096>;
+ version = <0x11223344>;
+ };
+
+ image: blob-ext {
+ filename = "refcode.bin";
+ };
+ };
+};
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [PATCH v5 12/15] boot: pre-load: add support of ecdsa
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (10 preceding siblings ...)
2026-04-21 21:09 ` [PATCH v5 11/15] tools: binman: " Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-21 21:09 ` [PATCH v5 13/15] tools: preload_check_sign: " Philippe Reynes
` (4 subsequent siblings)
16 siblings, 0 replies; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes, Simon Glass
Right now, u-boot can only boot image with a
pre-load header with rsa. We add the support
of ecdsa.
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v3:
- initial version
v4:
- avoid calling image_get_crypto_algo several times
v5:
- simplify the function is_ecdsa
- re-use already computed crypto in function image_pre_load_sig_setup
boot/image-pre-load.c | 53 +++++++++++++++++++++++++++++++++----------
1 file changed, 41 insertions(+), 12 deletions(-)
diff --git a/boot/image-pre-load.c b/boot/image-pre-load.c
index 2f851ebb28c..af72ea6d547 100644
--- a/boot/image-pre-load.c
+++ b/boot/image-pre-load.c
@@ -70,6 +70,12 @@ static int image_pre_load_sig_setup(struct image_sig_info *info)
return 0;
}
#else
+
+static int is_ecdsa(struct crypto_algo *crypto)
+{
+ return crypto && !strncmp(crypto->name, "ecdsa", 5);
+}
+
/*
* This function gathers information about the signature check
* that could be done before launching the image.
@@ -86,6 +92,7 @@ static int image_pre_load_sig_setup(struct image_sig_info *info)
int key_len;
int node, ret = 0;
char *sig_info_path = NULL;
+ struct crypto_algo *crypto;
if (!info) {
log_err("ERROR: info is NULL for image pre-load sig check\n");
@@ -114,11 +121,24 @@ static int image_pre_load_sig_setup(struct image_sig_info *info)
goto out;
}
- padding_name = fdt_getprop(gd_fdt_blob(), node,
- IMAGE_PRE_LOAD_PROP_PADDING_NAME, NULL);
- if (!padding_name) {
- log_info("INFO: no padding_name provided, so using pkcs-1.5\n");
- padding_name = "pkcs-1.5";
+ crypto = image_get_crypto_algo(algo_name);
+ if (!crypto) {
+ printf("ERROR: can't find a valid crypto algo from %s\n",
+ (char *)algo_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (is_ecdsa(crypto)) {
+ padding_name = NULL;
+ } else {
+ padding_name = fdt_getprop(gd_fdt_blob(), node,
+ IMAGE_PRE_LOAD_PROP_PADDING_NAME,
+ NULL);
+ if (!padding_name) {
+ log_info("INFO: no padding_name provided, so using pkcs-1.5\n");
+ padding_name = "pkcs-1.5";
+ }
}
sig_size = fdt_getprop(gd_fdt_blob(), node,
@@ -129,12 +149,17 @@ static int image_pre_load_sig_setup(struct image_sig_info *info)
goto out;
}
- key = fdt_getprop(gd_fdt_blob(), node,
- IMAGE_PRE_LOAD_PROP_PUBLIC_KEY, &key_len);
- if (!key) {
- log_err("ERROR: no key for image pre-load sig check\n");
- ret = -EINVAL;
- goto out;
+ if (is_ecdsa(crypto)) {
+ key = NULL;
+ key_len = 0;
+ } else {
+ key = fdt_getprop(gd_fdt_blob(), node,
+ IMAGE_PRE_LOAD_PROP_PUBLIC_KEY, &key_len);
+ if (!key) {
+ log_err("ERROR: no key for image pre-load sig check\n");
+ ret = -EINVAL;
+ goto out;
+ }
}
info->algo_name = (char *)algo_name;
@@ -152,9 +177,13 @@ static int image_pre_load_sig_setup(struct image_sig_info *info)
info->sig_info.name = info->algo_name;
info->sig_info.padding = image_get_padding_algo(info->padding_name);
info->sig_info.checksum = image_get_checksum_algo(info->sig_info.name);
- info->sig_info.crypto = image_get_crypto_algo(info->sig_info.name);
+ info->sig_info.crypto = crypto;
info->sig_info.key = info->key;
info->sig_info.keylen = info->key_len;
+ if (is_ecdsa(crypto)) {
+ info->sig_info.required_keynode = node;
+ info->sig_info.fdt_blob = gd_fdt_blob();
+ }
out:
return ret;
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [PATCH v5 13/15] tools: preload_check_sign: add support of ecdsa
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (11 preceding siblings ...)
2026-04-21 21:09 ` [PATCH v5 12/15] boot: " Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-21 21:09 ` [PATCH v5 14/15] test: py: vboot: prepare test for global signature with ecdsa Philippe Reynes
` (3 subsequent siblings)
16 siblings, 0 replies; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes, Simon Glass
right now, the tool preload_check_sign may only
checks an image with a pre-load header with rsa.
We add the support of pre-load header with ecdsa.
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v3:
- initial version
v4:
- free key to avoid mem leak
- fix error management (set ret before goto out)
v5:
- add include ec.h, evp.h, err.h and image.h
tools/preload_check_sign.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/tools/preload_check_sign.c b/tools/preload_check_sign.c
index ebead459273..d94f0509e74 100644
--- a/tools/preload_check_sign.c
+++ b/tools/preload_check_sign.c
@@ -8,9 +8,13 @@
* complete file. The tool preload_check_sign allows to verify and authenticate
* a file starting with a preload header.
*/
+
+#define OPENSSL_API_COMPAT 0x10101000L
+
#include <stdio.h>
#include <unistd.h>
#include <openssl/pem.h>
+#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <image.h>
@@ -144,6 +148,32 @@ int main(int argc, char **argv)
info.sig_info.key = info.key;
info.sig_info.keylen = info.key_len;
+ /* For ecdsa key, we have to update some values */
+ if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) {
+ EC_KEY *ecdsa_key;
+ const EC_GROUP *group;
+
+ ecdsa_key = EVP_PKEY_get1_EC_KEY(pkey);
+ if (!ecdsa_key) {
+ fprintf(stderr, "Can not extract ECDSA key\n");
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ group = EC_KEY_get0_group(ecdsa_key);
+ if (!group) {
+ fprintf(stderr, "Can not extract ECDSA group\n");
+ EC_KEY_free(ecdsa_key);
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ info.sig_info.keyfile = keyfile;
+ info.sig_size = (EC_GROUP_order_bits(group) + 7) / 8 * 2;
+
+ EC_KEY_free(ecdsa_key);
+ }
+
/* Check the signature */
image_pre_load_sig_set_info(&info);
ret = image_pre_load_sig((ulong)buffer);
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [PATCH v5 14/15] test: py: vboot: prepare test for global signature with ecdsa
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (12 preceding siblings ...)
2026-04-21 21:09 ` [PATCH v5 13/15] tools: preload_check_sign: " Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-21 21:09 ` [PATCH v5 15/15] test: py: vboot: add " Philippe Reynes
` (2 subsequent siblings)
16 siblings, 0 replies; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes, Simon Glass
The vboot tests only consider rsa for test with global signature.
To prepare the integration of test with ecdsa test, the signature
algo is now explicit.
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v3:
- initial version
v4:
- no change
v5:
- no change
test/py/tests/test_vboot.py | 12 ++++++------
...binman-pss.dts => sandbox-binman-rsa2048-pss.dts} | 0
...sandbox-binman.dts => sandbox-binman-rsa2048.dts} | 0
...pss.dts => sandbox-u-boot-global-rsa2048-pss.dts} | 0
...-global.dts => sandbox-u-boot-global-rsa2048.dts} | 0
5 files changed, 6 insertions(+), 6 deletions(-)
rename test/py/tests/vboot/{sandbox-binman-pss.dts => sandbox-binman-rsa2048-pss.dts} (100%)
rename test/py/tests/vboot/{sandbox-binman.dts => sandbox-binman-rsa2048.dts} (100%)
rename test/py/tests/vboot/{sandbox-u-boot-global-pss.dts => sandbox-u-boot-global-rsa2048-pss.dts} (100%)
rename test/py/tests/vboot/{sandbox-u-boot-global.dts => sandbox-u-boot-global-rsa2048.dts} (100%)
diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py
index 4e4d9529031..22865f653c5 100644
--- a/test/py/tests/test_vboot.py
+++ b/test/py/tests/test_vboot.py
@@ -503,7 +503,7 @@ def test_vboot(ubman, name, sha_algo, sig_algo, padding, sign_options, required,
dtb)
run_bootm(sha_algo, 'multi required key', '', False)
- def test_global_sign(sha_algo, padding, sign_options):
+ def test_global_sign(sha_algo, sig_algo, padding, sign_options):
"""Test global image signature with the given hash algorithm and padding.
Args:
@@ -512,14 +512,14 @@ def test_vboot(ubman, name, sha_algo, sig_algo, padding, sign_options, required,
rsa signature algorithm.
"""
- dtb = '%ssandbox-u-boot-global%s.dtb' % (tmpdir, padding)
+ dtb = '%ssandbox-u-boot-global%s%s.dtb' % (tmpdir, sig_algo, padding)
ubman.config.dtb = dtb
# Compile our device tree files for kernel and U-Boot. These are
# regenerated here since mkimage will modify them (by adding a
# public key) below.
dtc('sandbox-kernel.dts', ubman, dtc_args, datadir, tmpdir, dtb)
- dtc_options('sandbox-u-boot-global%s.dts' % padding, '-p 1024')
+ dtc_options('sandbox-u-boot-global%s%s.dts' % (sig_algo, padding), '-p 1024')
# Build the FIT with dev key (keys NOT required). This adds the
# signature into sandbox-u-boot.dtb, NOT marked 'required'.
@@ -528,11 +528,11 @@ def test_vboot(ubman, name, sha_algo, sig_algo, padding, sign_options, required,
# Build the dtb for binman that define the pre-load header
# with the global sigature.
- dtc('sandbox-binman%s.dts' % padding, ubman, dtc_args, datadir, tmpdir, dtb)
+ dtc('sandbox-binman%s%s.dts' % (sig_algo, padding), ubman, dtc_args, datadir, tmpdir, dtb)
# Run binman to create the final image with the not signed fit
# and the pre-load header that contains the global signature.
- run_binman('sandbox-binman%s.dtb' % padding)
+ run_binman('sandbox-binman%s%s.dtb' % (sig_algo, padding))
# Check that the signature is correctly verified by u-boot
run_bootm(sha_algo, 'global image signature',
@@ -582,7 +582,7 @@ def test_vboot(ubman, name, sha_algo, sig_algo, padding, sign_options, required,
try:
ubman.config.dtb = dtb
if global_sign:
- test_global_sign(sha_algo, padding, sign_options)
+ test_global_sign(sha_algo, sig_algo, padding, sign_options)
elif required:
test_required_key(sha_algo, sig_algo, padding, sign_options)
else:
diff --git a/test/py/tests/vboot/sandbox-binman-pss.dts b/test/py/tests/vboot/sandbox-binman-rsa2048-pss.dts
similarity index 100%
rename from test/py/tests/vboot/sandbox-binman-pss.dts
rename to test/py/tests/vboot/sandbox-binman-rsa2048-pss.dts
diff --git a/test/py/tests/vboot/sandbox-binman.dts b/test/py/tests/vboot/sandbox-binman-rsa2048.dts
similarity index 100%
rename from test/py/tests/vboot/sandbox-binman.dts
rename to test/py/tests/vboot/sandbox-binman-rsa2048.dts
diff --git a/test/py/tests/vboot/sandbox-u-boot-global-pss.dts b/test/py/tests/vboot/sandbox-u-boot-global-rsa2048-pss.dts
similarity index 100%
rename from test/py/tests/vboot/sandbox-u-boot-global-pss.dts
rename to test/py/tests/vboot/sandbox-u-boot-global-rsa2048-pss.dts
diff --git a/test/py/tests/vboot/sandbox-u-boot-global.dts b/test/py/tests/vboot/sandbox-u-boot-global-rsa2048.dts
similarity index 100%
rename from test/py/tests/vboot/sandbox-u-boot-global.dts
rename to test/py/tests/vboot/sandbox-u-boot-global-rsa2048.dts
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [PATCH v5 15/15] test: py: vboot: add test for global signature with ecdsa
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (13 preceding siblings ...)
2026-04-21 21:09 ` [PATCH v5 14/15] test: py: vboot: prepare test for global signature with ecdsa Philippe Reynes
@ 2026-04-21 21:09 ` Philippe Reynes
2026-04-22 14:54 ` [PATCH v5 00/15] add software ecdsa support Raymond Mao
2026-05-16 17:22 ` Marko Mäkelä
16 siblings, 0 replies; 29+ messages in thread
From: Philippe Reynes @ 2026-04-21 21:09 UTC (permalink / raw)
To: marko.makela, jonny.green, raymondmaoca, trini, simon.glass
Cc: u-boot, Philippe Reynes, Simon Glass
As now u-boot supports pre-load header with ecdsa, we
add some tests to vboot with ecdsa pre-load header.
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
v3:
- initial version
v4:
- no change
v5:
- no change
test/py/tests/test_vboot.py | 3 +++
.../tests/vboot/sandbox-binman-ecdsa256.dts | 24 +++++++++++++++++
.../tests/vboot/sandbox-binman-ecdsa384.dts | 24 +++++++++++++++++
.../tests/vboot/sandbox-binman-ecdsa521.dts | 24 +++++++++++++++++
.../vboot/sandbox-u-boot-global-ecdsa256.dts | 27 +++++++++++++++++++
.../vboot/sandbox-u-boot-global-ecdsa384.dts | 27 +++++++++++++++++++
.../vboot/sandbox-u-boot-global-ecdsa521.dts | 27 +++++++++++++++++++
7 files changed, 156 insertions(+)
create mode 100644 test/py/tests/vboot/sandbox-binman-ecdsa256.dts
create mode 100644 test/py/tests/vboot/sandbox-binman-ecdsa384.dts
create mode 100644 test/py/tests/vboot/sandbox-binman-ecdsa521.dts
create mode 100644 test/py/tests/vboot/sandbox-u-boot-global-ecdsa256.dts
create mode 100644 test/py/tests/vboot/sandbox-u-boot-global-ecdsa384.dts
create mode 100644 test/py/tests/vboot/sandbox-u-boot-global-ecdsa521.dts
diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py
index 22865f653c5..e0366e06ddb 100644
--- a/test/py/tests/test_vboot.py
+++ b/test/py/tests/test_vboot.py
@@ -102,6 +102,9 @@ TESTDATA_IN = [
['algo-arg', 'algo-arg', '', '', '-o sha256,rsa2048', False, False, True, False],
['sha256-global-sign', 'sha256', '-rsa2048', '', '', False, False, False, True],
['sha256-global-sign-pss', 'sha256', '-rsa2048', '-pss', '', False, False, False, True],
+ ['sha256-global-sign-ecdsa256', 'sha256', '-ecdsa256', '', '', False, False, False, True],
+ ['sha256-global-sign-ecdsa384', 'sha256', '-ecdsa384', '', '', False, False, False, True],
+ ['sha256-global-sign-ecdsa521', 'sha256', '-ecdsa521', '', '', False, False, False, True],
]
# Mark all but the first test as slow, so they are not run with '-k not slow'
diff --git a/test/py/tests/vboot/sandbox-binman-ecdsa256.dts b/test/py/tests/vboot/sandbox-binman-ecdsa256.dts
new file mode 100644
index 00000000000..0e84b81078b
--- /dev/null
+++ b/test/py/tests/vboot/sandbox-binman-ecdsa256.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ filename = "sandbox.img";
+
+ pre-load {
+ content = <&image>;
+ algo-name = "sha256,ecdsa256";
+ key-name = "dev.pem";
+ header-size = <4096>;
+ version = <1>;
+ };
+
+ image: blob-ext {
+ filename = "test.fit";
+ };
+ };
+};
diff --git a/test/py/tests/vboot/sandbox-binman-ecdsa384.dts b/test/py/tests/vboot/sandbox-binman-ecdsa384.dts
new file mode 100644
index 00000000000..56faf67fe57
--- /dev/null
+++ b/test/py/tests/vboot/sandbox-binman-ecdsa384.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ filename = "sandbox.img";
+
+ pre-load {
+ content = <&image>;
+ algo-name = "sha256,ecdsa384";
+ key-name = "dev.pem";
+ header-size = <4096>;
+ version = <1>;
+ };
+
+ image: blob-ext {
+ filename = "test.fit";
+ };
+ };
+};
diff --git a/test/py/tests/vboot/sandbox-binman-ecdsa521.dts b/test/py/tests/vboot/sandbox-binman-ecdsa521.dts
new file mode 100644
index 00000000000..8e2fc3de31d
--- /dev/null
+++ b/test/py/tests/vboot/sandbox-binman-ecdsa521.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ filename = "sandbox.img";
+
+ pre-load {
+ content = <&image>;
+ algo-name = "sha256,ecdsa521";
+ key-name = "dev.pem";
+ header-size = <4096>;
+ version = <1>;
+ };
+
+ image: blob-ext {
+ filename = "test.fit";
+ };
+ };
+};
diff --git a/test/py/tests/vboot/sandbox-u-boot-global-ecdsa256.dts b/test/py/tests/vboot/sandbox-u-boot-global-ecdsa256.dts
new file mode 100644
index 00000000000..f15ada3987c
--- /dev/null
+++ b/test/py/tests/vboot/sandbox-u-boot-global-ecdsa256.dts
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ model = "Sandbox Verified Boot Test";
+ compatible = "sandbox";
+
+ binman {
+ };
+
+ reset@0 {
+ compatible = "sandbox,reset";
+ };
+
+ image {
+ pre-load {
+ sig {
+ algo-name = "sha256,ecdsa256";
+ signature-size = <64>;
+ mandatory = "yes";
+
+ key-name = "dev";
+ };
+ };
+ };
+};
diff --git a/test/py/tests/vboot/sandbox-u-boot-global-ecdsa384.dts b/test/py/tests/vboot/sandbox-u-boot-global-ecdsa384.dts
new file mode 100644
index 00000000000..24540ace249
--- /dev/null
+++ b/test/py/tests/vboot/sandbox-u-boot-global-ecdsa384.dts
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ model = "Sandbox Verified Boot Test";
+ compatible = "sandbox";
+
+ binman {
+ };
+
+ reset@0 {
+ compatible = "sandbox,reset";
+ };
+
+ image {
+ pre-load {
+ sig {
+ algo-name = "sha256,ecdsa384";
+ signature-size = <96>;
+ mandatory = "yes";
+
+ key-name = "dev";
+ };
+ };
+ };
+};
diff --git a/test/py/tests/vboot/sandbox-u-boot-global-ecdsa521.dts b/test/py/tests/vboot/sandbox-u-boot-global-ecdsa521.dts
new file mode 100644
index 00000000000..72fa3b2c790
--- /dev/null
+++ b/test/py/tests/vboot/sandbox-u-boot-global-ecdsa521.dts
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ model = "Sandbox Verified Boot Test";
+ compatible = "sandbox";
+
+ binman {
+ };
+
+ reset@0 {
+ compatible = "sandbox,reset";
+ };
+
+ image {
+ pre-load {
+ sig {
+ algo-name = "sha256,ecdsa521";
+ signature-size = <132>;
+ mandatory = "yes";
+
+ key-name = "dev";
+ };
+ };
+ };
+};
--
2.43.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [PATCH v5 00/15] add software ecdsa support
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (14 preceding siblings ...)
2026-04-21 21:09 ` [PATCH v5 15/15] test: py: vboot: add " Philippe Reynes
@ 2026-04-22 14:54 ` Raymond Mao
2026-05-16 17:22 ` Marko Mäkelä
16 siblings, 0 replies; 29+ messages in thread
From: Raymond Mao @ 2026-04-22 14:54 UTC (permalink / raw)
To: Philippe Reynes; +Cc: marko.makela, jonny.green, trini, simon.glass, u-boot
Hi Philippe,
On Tue, Apr 21, 2026 at 5:10 PM Philippe Reynes
<philippe.reynes@softathome.com> wrote:
>
> This series adds the support of ecdsa with software
> using mbedtls. So boards without ecdsa hardware may
> also use signature with ecdsa.
>
> To add the support of ecdsa with mbedtls, I have:
> - enabled ecdsa in mbedtls
> - add a function sw_ecdsa_verify that uses mbedtls
> - add a driver sw_ecdsa that call sw_ecdsa_verify
>
> I have tested this code with sandbox, and I have
> followed those steps:
>
> 0) build u-boot using sandbox_defconfig and adding those options:
>
> CONFIG_ECDSA_MBEDTLS=y
> CONFIG_ECDSA=y
> CONFIG_ECDSA_VERIFY=y
>
> 1) add a signature node to an its file
> signature-256 {
> algo = "sha256,ecdsa256";
> key-name-hint = "private-key-256";
> };
>
> 2) generate an ecdsa key
> openssl ecparam -name prime256v1 -genkey -noout -out private-key-256.pem
>
> 3) create the itb file
> ./tools/mkimage -f <file.its> -k . -K arch/sandbox/dts/test.dtb <file.itb>
>
> 4) launch sandbox u-boot
>
> ./u-boot -d arch/sandbox/dts/test.dtb
>
> 5) on sandbox u-boot prompt, load the itb and launch bootm on it
>
> => host load hostfs - 1000000 uboot-ecdsa.itb
> 4628674 bytes read in 1 ms (4.3 GiB/s)
> => bootm 1000000
> ...
> ...
> Verifying Hash Integrity ... sha256,ecdsa256:private-key-256+ OK
>
>
>
>
>
> Changes in v2:
> - move ECDSA_MBEDTLS to MBEDTLS_LIB_X509
> - rename lib/mbedtls/sw_ecdsa.c to lib/mbedtls/ecdsa.c
> - enhance dependancies for ECDSA_MBEDTLS
s/dependancies/dependencies
Regards,
Raymond
> - fix support of ecdsa521/secp521r1
> - add vboot test using ecdsa
>
> Changes in v3:
> - do not use _MBEDTLS in mbedtls_def_config.h
> - check returns and remove mem leak in lib/mbedtls/ecdsa.c
> - remove useless field *k in struct ecdsa_test_vector_s
> - check returns in test/lib/ecdsa.c
> - fix third parameter when calling sha*_csum_wd()
> - add support of ecdsa in pre-load header
>
> Changes in v4:
> - change some dependencies to enable ecc
> - use ECDSA_MBEDTLS to build the ecdsa driver
> - support ecdsa521 and secp521r1
> - add a test calling ecdsa_verify for the ecdsa class
> - merge patch 10 and 11 (support ecdsa pre-load for binman and tests)
> - several code cleanup
>
> Change in v5:
> - fix ecdsa 521 in the first patch (instead of the 5th patch)
> - mbedtls: ecdsa is only compiled when ECDSA_MBEDTLS is enabled
> - fit_image_setup_sig: required_keynode is initiazed to -1 instead of 0
> - avoid hardcoded value for ecdsa sig and point size
> - check pointer before using them
> - free ecdsa keys when key are not found/used
>
>
> Philippe Reynes (15):
> ecdsa: fix support of secp521r1
> mbedtls: enable support of ecc
> ecdsa: initial support of ecdsa using mbedtls
> test: lib: ecdsa: add initial test
> drivers: crypto: add software ecdsa support
> test: dm: ecdsa.c: clean this test as software ecdsa is now
> implemented
> test: py: vboot: prepare integration test for ecdsa
> test: vboot: add test for ecdsa
> tools: fit_image_setup_sig: set required_keynode to -1
> tools: mkimage: pre-load: add support of ecdsa
> tools: binman: pre-load: add support of ecdsa
> boot: pre-load: add support of ecdsa
> tools: preload_check_sign: add support of ecdsa
> test: py: vboot: prepare test for global signature with ecdsa
> test: py: vboot: add test for global signature with ecdsa
>
> boot/image-pre-load.c | 53 +-
> configs/amd_versal2_virt_defconfig | 3 +
> configs/qemu_arm64_lwip_defconfig | 3 +
> configs/sandbox_defconfig | 1 +
> configs/starfive_visionfive2_defconfig | 3 +
> configs/xilinx_versal_net_virt_defconfig | 3 +
> configs/xilinx_versal_virt_defconfig | 3 +
> configs/xilinx_zynqmp_kria_defconfig | 3 +
> configs/xilinx_zynqmp_virt_defconfig | 3 +
> drivers/crypto/Makefile | 1 +
> drivers/crypto/ecdsa/Makefile | 6 +
> drivers/crypto/ecdsa/ecdsa-sw.c | 33 ++
> include/crypto/ecdsa-uclass.h | 15 +-
> include/crypto/internal/ecdsa.h | 39 ++
> lib/ecdsa/Kconfig | 1 +
> lib/ecdsa/ecdsa-libcrypto.c | 92 +++-
> lib/ecdsa/ecdsa-verify.c | 75 ++-
> lib/fdt-libcrypto.c | 2 +-
> lib/mbedtls/Kconfig | 14 +
> lib/mbedtls/Makefile | 19 +-
> lib/mbedtls/ecdsa.c | 146 ++++++
> lib/mbedtls/mbedtls_def_config.h | 17 +
> test/dm/ecdsa.c | 107 +++-
> test/lib/Makefile | 1 +
> test/lib/ecdsa.c | 456 ++++++++++++++++++
> test/py/tests/test_fit_ecdsa.py | 2 +-
> test/py/tests/test_vboot.py | 143 +++---
> .../tests/vboot/sandbox-binman-ecdsa256.dts | 24 +
> .../tests/vboot/sandbox-binman-ecdsa384.dts | 24 +
> .../tests/vboot/sandbox-binman-ecdsa521.dts | 24 +
> ...pss.dts => sandbox-binman-rsa2048-pss.dts} | 0
> ...-binman.dts => sandbox-binman-rsa2048.dts} | 0
> .../vboot/sandbox-u-boot-global-ecdsa256.dts | 27 ++
> .../vboot/sandbox-u-boot-global-ecdsa384.dts | 27 ++
> .../vboot/sandbox-u-boot-global-ecdsa521.dts | 27 ++
> ... => sandbox-u-boot-global-rsa2048-pss.dts} | 0
> ....dts => sandbox-u-boot-global-rsa2048.dts} | 0
> ....its => sign-configs-sha1-rsa2048-pss.its} | 0
> ...sha1.its => sign-configs-sha1-rsa2048.its} | 0
> .../vboot/sign-configs-sha256-ecdsa256.its | 45 ++
> .../vboot/sign-configs-sha256-ecdsa384.its | 45 ++
> .../vboot/sign-configs-sha256-ecdsa521.its | 45 ++
> ... sign-configs-sha256-rsa2048-pss-prod.its} | 0
> ...ts => sign-configs-sha256-rsa2048-pss.its} | 0
> ...56.its => sign-configs-sha256-rsa2048.its} | 0
> ...84.its => sign-configs-sha384-rsa3072.its} | 0
> ...s.its => sign-images-sha1-rsa2048-pss.its} | 0
> ...-sha1.its => sign-images-sha1-rsa2048.its} | 0
> .../vboot/sign-images-sha256-ecdsa256.its | 42 ++
> .../vboot/sign-images-sha256-ecdsa384.its | 42 ++
> .../vboot/sign-images-sha256-ecdsa521.its | 42 ++
> ...its => sign-images-sha256-rsa2048-pss.its} | 0
> ...256.its => sign-images-sha256-rsa2048.its} | 0
> ...384.its => sign-images-sha384-rsa3072.its} | 0
> tools/binman/etype/pre_load.py | 78 ++-
> tools/binman/ftest.py | 52 ++
> tools/binman/test/ecdsa521.pem | 7 +
> tools/binman/test/security/pre_load_ecdsa.dts | 22 +
> .../security/pre_load_ecdsa_invalid_algo.dts | 22 +
> .../security/pre_load_ecdsa_invalid_key.dts | 22 +
> .../security/pre_load_ecdsa_invalid_sha.dts | 22 +
> tools/image-host.c | 93 +++-
> tools/image-sig-host.c | 7 +
> tools/preload_check_sign.c | 30 ++
> 64 files changed, 1877 insertions(+), 136 deletions(-)
> create mode 100644 drivers/crypto/ecdsa/Makefile
> create mode 100644 drivers/crypto/ecdsa/ecdsa-sw.c
> create mode 100644 include/crypto/internal/ecdsa.h
> create mode 100644 lib/mbedtls/ecdsa.c
> create mode 100644 test/lib/ecdsa.c
> create mode 100644 test/py/tests/vboot/sandbox-binman-ecdsa256.dts
> create mode 100644 test/py/tests/vboot/sandbox-binman-ecdsa384.dts
> create mode 100644 test/py/tests/vboot/sandbox-binman-ecdsa521.dts
> rename test/py/tests/vboot/{sandbox-binman-pss.dts => sandbox-binman-rsa2048-pss.dts} (100%)
> rename test/py/tests/vboot/{sandbox-binman.dts => sandbox-binman-rsa2048.dts} (100%)
> create mode 100644 test/py/tests/vboot/sandbox-u-boot-global-ecdsa256.dts
> create mode 100644 test/py/tests/vboot/sandbox-u-boot-global-ecdsa384.dts
> create mode 100644 test/py/tests/vboot/sandbox-u-boot-global-ecdsa521.dts
> rename test/py/tests/vboot/{sandbox-u-boot-global-pss.dts => sandbox-u-boot-global-rsa2048-pss.dts} (100%)
> rename test/py/tests/vboot/{sandbox-u-boot-global.dts => sandbox-u-boot-global-rsa2048.dts} (100%)
> rename test/py/tests/vboot/{sign-configs-sha1-pss.its => sign-configs-sha1-rsa2048-pss.its} (100%)
> rename test/py/tests/vboot/{sign-configs-sha1.its => sign-configs-sha1-rsa2048.its} (100%)
> create mode 100644 test/py/tests/vboot/sign-configs-sha256-ecdsa256.its
> create mode 100644 test/py/tests/vboot/sign-configs-sha256-ecdsa384.its
> create mode 100644 test/py/tests/vboot/sign-configs-sha256-ecdsa521.its
> rename test/py/tests/vboot/{sign-configs-sha256-pss-prod.its => sign-configs-sha256-rsa2048-pss-prod.its} (100%)
> rename test/py/tests/vboot/{sign-configs-sha256-pss.its => sign-configs-sha256-rsa2048-pss.its} (100%)
> rename test/py/tests/vboot/{sign-configs-sha256.its => sign-configs-sha256-rsa2048.its} (100%)
> rename test/py/tests/vboot/{sign-configs-sha384.its => sign-configs-sha384-rsa3072.its} (100%)
> rename test/py/tests/vboot/{sign-images-sha1-pss.its => sign-images-sha1-rsa2048-pss.its} (100%)
> rename test/py/tests/vboot/{sign-images-sha1.its => sign-images-sha1-rsa2048.its} (100%)
> create mode 100644 test/py/tests/vboot/sign-images-sha256-ecdsa256.its
> create mode 100644 test/py/tests/vboot/sign-images-sha256-ecdsa384.its
> create mode 100644 test/py/tests/vboot/sign-images-sha256-ecdsa521.its
> rename test/py/tests/vboot/{sign-images-sha256-pss.its => sign-images-sha256-rsa2048-pss.its} (100%)
> rename test/py/tests/vboot/{sign-images-sha256.its => sign-images-sha256-rsa2048.its} (100%)
> rename test/py/tests/vboot/{sign-images-sha384.its => sign-images-sha384-rsa3072.its} (100%)
> create mode 100644 tools/binman/test/ecdsa521.pem
> create mode 100644 tools/binman/test/security/pre_load_ecdsa.dts
> create mode 100644 tools/binman/test/security/pre_load_ecdsa_invalid_algo.dts
> create mode 100644 tools/binman/test/security/pre_load_ecdsa_invalid_key.dts
> create mode 100644 tools/binman/test/security/pre_load_ecdsa_invalid_sha.dts
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 29+ messages in thread* Re: [PATCH v5 00/15] add software ecdsa support
2026-04-21 21:09 [PATCH v5 00/15] add software ecdsa support Philippe Reynes
` (15 preceding siblings ...)
2026-04-22 14:54 ` [PATCH v5 00/15] add software ecdsa support Raymond Mao
@ 2026-05-16 17:22 ` Marko Mäkelä
16 siblings, 0 replies; 29+ messages in thread
From: Marko Mäkelä @ 2026-05-16 17:22 UTC (permalink / raw)
To: Philippe Reynes; +Cc: jonny.green, raymondmaoca, trini, simon.glass, u-boot
Hi Philippe, all,
Tue, Apr 21, 2026 at 11:09:39PM +0200, Philippe Reynes wrote:
>This series adds the support of ecdsa with software
>using mbedtls. So boards without ecdsa hardware may
>also use signature with ecdsa.
Today, I finally tested this patch series on top of Robert Nelson's
u-boot v2026.01 based fork for BeagleBoard PocketBeagle 2:
https://github.com/beagleboard/u-boot/commit/ef03e35488377a32cdd4f76d1a03ef7f60c798ef
The only conflicts were for copyright comments in some files.
I used the following configuration; this platform enables CONFIG_FIT and
CONFIG_FIT_VERIFY by default:
make am62_pocketbeagle2_a53_defconfig
scripts/config -e ASYMMETRIC_KEY_TYPE -e ASYMMETRIC_PUBLIC_KEY_SUBTYPE \
-d LEGACY_HASHING_AND_CRYPTO -e MBEDTLS_LIB -e MBEDTLS_LIB_CRYPTO \
-e ECDSA -e ECDSA_MBEDTLS -e ECDSA_VERIFY \
-d MD5_MBEDTLS -d HKDF_MBEDTLS -e SHA256_SMALLER -e SHA512_SMALLER \
-d RSA_PUBLIC_KEY_PARSER -d RSA_PUBLIC_KEY_PARSER_MBEDTLS \
-d SPL_ECDSA_VERIFY \
-d SPL_ASYMMETRIC_KEY_TYPE -d SPL_ASYMMETRIC_PUBLIC_KEY_SUBTYPE \
-d SPL_RSA_PUBLIC_KEY_PARSER \
-d PKCS7_MESSAGE_PARSER -d PKCS7_MESSAGE_PARSER_MBEDTLS \
-e X509_CERTIFICATE_PARSER -d MSCODE_PARSER
I used these settings also for the 32-bit
am62_pocketbeagle2_r5_defconfig which loads the 64-bit u-boot.img.
I tested this build with an ARMv8 "defconfig" of
https://github.com/torvalds/linux tag v7.0. An image that was signed
with a different private key was rejected:
=> load mmc 1 $loadaddr fitImage
15013689 bytes read in 180 ms (79.5 MiB/s)
=> source
## Executing script at 82000000
sha256,ecdsa256:dev- error!
Verification failed for '<NULL>' hash node in 'conf-1' config node
Failed to verify required signature 'dev'
=> bootm
## Loading kernel (any) from FIT Image at 82000000 ...
Using 'conf-1' configuration
Verifying Hash Integrity ... sha256,ecdsa256:dev- error!
Verification failed for '<NULL>' hash node in 'conf-1' config node
Failed to verify required signature 'dev'
Bad Data Hash
ERROR -2: can't get kernel image!
A correctly signed image passed the verification:
=> load mmc 1 $loadaddr fitImage
15013689 bytes read in 179 ms (80 MiB/s)
=> bootm
## Loading kernel (any) from FIT Image at 82000000 ...
[snip]
Loading fdt from 0x82e430d4 to 0x88000000
Booting using the fdt blob at 0x88000000
Working FDT set to 88000000
Uncompressing Kernel Image to 82000000
Error: inflate() returned -3
gzip compressed: uncompress error -3
Must RESET board to recover
Resetting the board...
U-Boot SPL 2026.01 (May 16 2026 - 16:42:03 +0000)
I think that this can be declared as a success for this patch series,
even though my kernel load address is causing trouble.
With best regards,
Marko
^ permalink raw reply [flat|nested] 29+ messages in thread