From: Philippe Reynes <philippe.reynes@softathome.com>
To: marko.makela@iki.fi, jonny.green@keytechinc.com,
raymondmaoca@gmail.com, trini@konsulko.com,
simon.glass@canonical.com
Cc: u-boot@lists.u-boot-project.org,
Philippe Reynes <philippe.reynes@softathome.com>,
Simon Glass <sjg@chromium.org>
Subject: [PATCH v9 11/15] tools: binman: pre-load: add support of ecdsa
Date: Thu, 3 Sep 2026 10:17:01 +0200 [thread overview]
Message-ID: <20260903081705.12894-12-philippe.reynes@softathome.com> (raw)
In-Reply-To: <20260903081705.12894-1-philippe.reynes@softathome.com>
Right now, binman can only create pre-load header
using rsa. We add the support of ecdsa.
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Raymond Mao <raymondmaoca@gmail.com>
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
v6:
- no change
v7:
- no change
v8:
- no change
v9:
- no change
tools/binman/etype/pre_load.py | 78 ++++++++++++++++---
tools/binman/ftest.py | 50 ++++++++++++
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, 214 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 0d953cb258e..7890c1c62a8 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):
"""Create a placeholder for the header"""
self.SetContents(tools.get_bytes(0, self.header_size))
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 5f0de4c74a7..a3209bb1595 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -5925,12 +5925,62 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
image_fname = tools.get_output_filename('image.bin')
is_signed = self._CheckPreload(image_fname, self.TestFile("dev.key"))
+ 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 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
next prev parent reply other threads:[~2026-09-03 8:17 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-03 8:16 [PATCH v9 00/15] add software ecdsa support Philippe Reynes
2026-09-03 8:16 ` [PATCH v9 01/15] ecdsa: fix support of secp521r1 Philippe Reynes
2026-09-03 14:30 ` Raymond Mao
2026-09-03 8:16 ` [PATCH v9 02/15] mbedtls: enable support of ecc Philippe Reynes
2026-09-03 14:31 ` Raymond Mao
2026-09-03 8:16 ` [PATCH v9 03/15] ecdsa: initial support of ecdsa using mbedtls Philippe Reynes
2026-09-03 14:31 ` Raymond Mao
2026-09-03 8:16 ` [PATCH v9 04/15] test: lib: ecdsa: add initial test Philippe Reynes
2026-09-03 14:32 ` Raymond Mao
2026-09-03 8:16 ` [PATCH v9 05/15] drivers: crypto: add software ecdsa support Philippe Reynes
2026-09-03 14:32 ` Raymond Mao
2026-09-03 15:33 ` Raymond Mao
2026-09-03 18:33 ` Tom Rini
2026-09-03 8:16 ` [PATCH v9 06/15] test: dm: ecdsa.c: clean this test as software ecdsa is now implemented Philippe Reynes
2026-09-03 14:33 ` Raymond Mao
2026-09-03 8:16 ` [PATCH v9 07/15] test: py: vboot: prepare integration test for ecdsa Philippe Reynes
2026-09-03 15:42 ` Raymond Mao
2026-09-03 8:16 ` [PATCH v9 08/15] test: vboot: add " Philippe Reynes
2026-09-03 15:43 ` Raymond Mao
2026-09-03 8:16 ` [PATCH v9 09/15] tools: fit_image_setup_sig: set required_keynode to -1 Philippe Reynes
2026-09-03 14:34 ` Raymond Mao
2026-09-03 8:17 ` [PATCH v9 10/15] tools: mkimage: pre-load: add support of ecdsa Philippe Reynes
2026-09-03 14:36 ` Raymond Mao
2026-09-03 8:17 ` Philippe Reynes [this message]
2026-09-03 14:37 ` [PATCH v9 11/15] tools: binman: " Raymond Mao
2026-09-03 8:17 ` [PATCH v9 12/15] boot: " Philippe Reynes
2026-09-03 14:38 ` Raymond Mao
2026-09-03 8:17 ` [PATCH v9 13/15] tools: preload_check_sign: " Philippe Reynes
2026-09-03 14:39 ` Raymond Mao
2026-09-03 8:17 ` [PATCH v9 14/15] test: py: vboot: prepare test for global signature with ecdsa Philippe Reynes
2026-09-03 14:40 ` Raymond Mao
2026-09-03 8:17 ` [PATCH v9 15/15] test: py: vboot: add " Philippe Reynes
2026-09-03 14:41 ` Raymond Mao
2026-09-03 18:35 ` [PATCH v9 00/15] add software ecdsa support Tom Rini
2026-09-04 8:10 ` Philippe Reynes
2026-09-04 14:32 ` Tom Rini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260903081705.12894-12-philippe.reynes@softathome.com \
--to=philippe.reynes@softathome.com \
--cc=jonny.green@keytechinc.com \
--cc=marko.makela@iki.fi \
--cc=raymondmaoca@gmail.com \
--cc=simon.glass@canonical.com \
--cc=sjg@chromium.org \
--cc=trini@konsulko.com \
--cc=u-boot@lists.u-boot-project.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.