[RFC PATCH v2 5/9] ecdsa: fix support of secp521r1

Philippe Reynes philippe.reynes at softathome.com
Thu Feb 19 14:25:48 CET 2026


Current implementation of ecdsa only supports key len aligned on
8 bits. But the curve secp521r1 use a key of 521 bits which is not
aligned on 8 bits. In this commit, we update the key management
for ecdsa to support key of any lenght.

Signed-off-by: Philippe Reynes <philippe.reynes at softathome.com>
---
v2:
- intitial version

 lib/ecdsa/ecdsa-libcrypto.c | 21 +++++++++++++++++++--
 lib/ecdsa/ecdsa-verify.c    | 24 ++++++++++++++++++++++--
 lib/fdt-libcrypto.c         |  2 +-
 tools/image-sig-host.c      |  2 +-
 4 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c
index c4bfb2cec61..6f25ccc783d 100644
--- a/lib/ecdsa/ecdsa-libcrypto.c
+++ b/lib/ecdsa/ecdsa-libcrypto.c
@@ -45,6 +45,7 @@ static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node)
 {
 	int x_len;
 	int y_len;
+	int expected_len;
 
 	key->curve_name = fdt_getprop(fdt, node, "ecdsa,curve", NULL);
 	if (!key->curve_name)
@@ -54,6 +55,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,7 +66,19 @@ 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 if
+	 * 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 = (key->size_bits + 7) / 8;
+	if (x_len > expected_len)
+		key->x += x_len - expected_len;
+	if (y_len > expected_len)
+		key->y += y_len - expected_len;
+
+	if (x_len < expected_len || y_len < expected_len)
 		return -EINVAL;
 
 	return 0;
@@ -89,6 +104,8 @@ 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);
 		return -EINVAL;
@@ -111,7 +128,7 @@ static int read_key_from_fdt(struct signer *ctx, const void *fdt, int node)
 		return -ENOMEM;
 	}
 
-	len = pubkey.size_bits / 8;
+	len = (pubkey.size_bits + 7) / 8;
 
 	uint8_t buf[1 + len * 2];
 
diff --git a/lib/ecdsa/ecdsa-verify.c b/lib/ecdsa/ecdsa-verify.c
index 629b662cf6c..d87d95a5002 100644
--- a/lib/ecdsa/ecdsa-verify.c
+++ b/lib/ecdsa/ecdsa-verify.c
@@ -24,13 +24,15 @@ 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;
 
 	key->curve_name = fdt_getprop(fdt, node, "ecdsa,curve", NULL);
 	if (!key->curve_name) {
@@ -50,7 +52,19 @@ 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 if
+	 * 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 = (key->size_bits + 7) / 8;
+	if (x_len > expected_len)
+		key->x += x_len - expected_len;
+	if (y_len > expected_len)
+		key->y += y_len - expected_len;
+
+	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;
@@ -135,6 +149,12 @@ U_BOOT_CRYPTO_ALGO(ecdsa384) = {
 	.verify = ecdsa_verify,
 };
 
+U_BOOT_CRYPTO_ALGO(ecdsa521) = {
+	.name = "ecdsa521",
+	.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..a2272b196e7 100644
--- a/tools/image-sig-host.c
+++ b/tools/image-sig-host.c
@@ -84,7 +84,7 @@ struct crypto_algo crypto_algos[] = {
 		.verify = ecdsa_verify,
 	},
 	{
-		.name = "secp521r1",
+		.name = "ecdsa521",
 		.key_len = ECDSA521_BYTES,
 		.sign = ecdsa_sign,
 		.add_verify_data = ecdsa_add_verify_data,
-- 
2.43.0



More information about the U-Boot mailing list