[Buildroot] [git commit] package/uboot-tools: fix host FIT signature support

Julien Olivain via buildroot <[email protected]> Wed, 29 Jul 2026 20:38:07 +0200
Newsgroups net.busybox.buildroot
Message-ID <[email protected]>
commit: https://gitlab.com/buildroot.org/buildroot/-/commit/928cc5dc5cb82e6f2cb43f853488309eb806ef89
branch: https://gitlab.com/buildroot.org/buildroot/-/tree/master

U-Boot host tools use the tools configuration namespace when code calls
CONFIG_IS_ENABLED(). With USE_HOSTCC, CONFIG_IS_ENABLED(FIT_SIGNATURE)
resolves to CONFIG_TOOLS_FIT_SIGNATURE, while
CONFIG_VAL(FIT_SIGNATURE_MAX_SIZE) resolves to
CONFIG_TOOLS_FIT_SIGNATURE_MAX_SIZE.

The host-uboot-tools package only generates the old CONFIG_FIT_SIGNATURE
define. This makes tools/Makefile include fit_check_sign, but the host code
sees FIT signature support as disabled and the OpenSSL-backed signing and
verification objects are omitted. As a result, mkimage accepts a signature
node without writing its value or injecting a required public key.
fit_check_sign then has no required key and reports success without
checking the configuration signature.

A FIT-support-only configuration never exercises this path, which is why
the existing hash-only runtime test still passes.

Generate the tools FIT signature options needed by the host code and pass
CONFIG_TOOLS_LIBCRYPTO=y so the OpenSSL-backed signing, verification and
cipher objects are selected. Keep CONFIG_FIT_SIGNATURE=y in the make
options because U-Boot tools/Makefile still uses it to build
fit_check_sign.

Extend TestHostUbootTools to create an RSA-signed FIT, require a 256-byte
configuration signature and a required public key, verify the FIT, corrupt
the signature, and require verification to fail.

Signed-off-by: James Hilliard <[email protected]>
[Julien: add comments in runtime test]
Signed-off-by: Julien Olivain <[email protected]>
---
 package/uboot-tools/uboot-tools.mk                 |  7 ++-
 support/testing/tests/package/test_uboot_tools.py  | 71 ++++++++++++++++++++++
 .../testing/tests/package/test_uboot_tools/key.dts |  7 +++
 .../tests/package/test_uboot_tools/signed.its      | 38 ++++++++++++
 4 files changed, 121 insertions(+), 2 deletions(-)

diff --git a/package/uboot-tools/uboot-tools.mk b/package/uboot-tools/uboot-tools.mk
index 6b5554da9b..ef8bcabbd9 100644
--- a/package/uboot-tools/uboot-tools.mk
+++ b/package/uboot-tools/uboot-tools.mk
@@ -126,7 +126,10 @@ define HOST_UBOOT_TOOLS_CONFIGURE_CMDS
 	mkdir -p $(@D)/include/generated
 	$(if $(BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SUPPORT),$(UBOOT_TOOLS_ENABLE_HASH_ALGOS))
 	$(if $(BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SUPPORT),echo '#define CONFIG_TOOLS_FIT_PRINT 1' >> $(@D)/include/generated/autoconf.h)
-	echo $(if $(BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT),'#define CONFIG_FIT_SIGNATURE 1') >> $(@D)/include/generated/autoconf.h
+	$(if $(BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT),echo '#define CONFIG_TOOLS_IMAGE_PRE_LOAD 1' >> $(@D)/include/generated/autoconf.h)
+	$(if $(BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT),echo '#define CONFIG_TOOLS_RSASSA_PSS 1' >> $(@D)/include/generated/autoconf.h)
+	$(if $(BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT),echo '#define CONFIG_TOOLS_FIT_SIGNATURE 1' >> $(@D)/include/generated/autoconf.h)
+	$(if $(BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT),echo '#define CONFIG_TOOLS_FIT_SIGNATURE_MAX_SIZE 0x10000000' >> $(@D)/include/generated/autoconf.h)
 	mkdir -p $(@D)/include/asm
 	touch $(@D)/include/asm/linkage.h
 endef
@@ -142,7 +145,7 @@ HOST_UBOOT_TOOLS_DEPENDENCIES += host-dtc
 endif
 
 ifeq ($(BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT),y)
-HOST_UBOOT_TOOLS_MAKE_OPTS += CONFIG_FIT_SIGNATURE=y CONFIG_FIT_SIGNATURE_MAX_SIZE=0x10000000
+HOST_UBOOT_TOOLS_MAKE_OPTS += CONFIG_TOOLS_LIBCRYPTO=y CONFIG_FIT_SIGNATURE=y
 HOST_UBOOT_TOOLS_DEPENDENCIES += host-openssl
 define HOST_UBOOT_TOOLS_INSTALL_FIT_CHECK_SIGN
 	$(INSTALL) -m 0755 -D $(@D)/tools/fit_check_sign $(HOST_DIR)/bin/fit_check_sign
diff --git a/support/testing/tests/package/test_uboot_tools.py b/support/testing/tests/package/test_uboot_tools.py
index 5e5b44af30..8cff6fda21 100644
--- a/support/testing/tests/package/test_uboot_tools.py
+++ b/support/testing/tests/package/test_uboot_tools.py
@@ -1,11 +1,14 @@
 import hashlib
 import re
+import subprocess
 import zlib
 from pathlib import Path
 
 import infra.basetest
 
 EXAMPLE_ITS = Path(__file__).parent / "test_uboot_tools/example.its"
+KEY_DTS = Path(__file__).parent / "test_uboot_tools/key.dts"
+SIGNED_ITS = Path(__file__).parent / "test_uboot_tools/signed.its"
 
 
 def get_hashes(output: str) -> dict[str, str]:
@@ -72,6 +75,7 @@ class TestHostUbootTools(infra.basetest.BRHostPkgTest):
         """
         BR2_PACKAGE_HOST_UBOOT_TOOLS=y
         BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SUPPORT=y
+        BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y
         """
 
     def test_run(self):
@@ -86,3 +90,70 @@ class TestHostUbootTools(infra.basetest.BRHostPkgTest):
                 self.assertEqual(expected[h], reported[h])
         # Python does not have built-in CRC16 support, just check it is present
         self.assertIn("crc16-ccitt", reported)
+
+        # See U-Boot FIT Signature Verification documentation:
+        # https://source.denx.de/u-boot/u-boot/-/blob/v2026.07/doc/usage/fit/signature.rst
+        keydir = Path(self.builddir) / "keys"
+        keydir.mkdir(exist_ok=True)
+
+        # We generate a prublic/private key pair to sign the image.
+        cmd = [
+            "host/bin/openssl", "req", "-batch", "-new", "-x509", "-nodes",
+            "-newkey", "rsa:2048", "-keyout", str(keydir / "dev.key"),
+            "-out", str(keydir / "dev.crt"), "-subj", "/CN=Buildroot FIT test",
+        ]
+        infra.run_cmd_on_host(self.builddir, cmd)
+
+        # We compile the empty dtb that will be used to store the
+        # public key.
+        cmd = [
+            "host/bin/dtc", "-I", "dts", "-O", "dtb", "-p", "0x1000",
+            "-o", "test-key.dtb", str(KEY_DTS),
+        ]
+        infra.run_cmd_on_host(self.builddir, cmd)
+
+        # We sign the image and write the public key in our key
+        # storage dtb.
+        cmd = [
+            "host/bin/mkimage", "-f", str(SIGNED_ITS), "-k", str(keydir),
+            "-K", "test-key.dtb", "-r", "signed.fit",
+        ]
+        infra.run_cmd_on_host(self.builddir, cmd)
+
+        # We check there is a signature present in the FIT image.
+        cmd = [
+            "host/bin/fdtget", "-t", "bx", "signed.fit",
+            "/configurations/config-1/signature-1", "value",
+        ]
+        signature = infra.run_cmd_on_host(self.builddir, cmd).split()
+        self.assertEqual(len(signature), 256)
+
+        # We check the key is marked as required for the configuration.
+        cmd = [
+            "host/bin/fdtget", "-t", "s", "test-key.dtb",
+            "/signature/key-dev", "required",
+        ]
+        required = infra.run_cmd_on_host(self.builddir, cmd).strip()
+        self.assertEqual(required, "conf")
+
+        # We actually check the signature is valid.
+        cmd = [
+            "host/bin/fit_check_sign", "-f", "signed.fit",
+            "-k", "test-key.dtb",
+        ]
+        infra.run_cmd_on_host(self.builddir, cmd)
+
+        # We "corrupt" the signature, by setting it to zero.
+        cmd = [
+            "host/bin/fdtput", "-t", "bx", "signed.fit",
+            "/configurations/config-1/signature-1", "value", "00",
+        ]
+        infra.run_cmd_on_host(self.builddir, cmd)
+
+        # We check again the siganute, and expect a failure.
+        cmd = [
+            "host/bin/fit_check_sign", "-f", "signed.fit",
+            "-k", "test-key.dtb",
+        ]
+        with self.assertRaises(subprocess.CalledProcessError):
+            infra.run_cmd_on_host(self.builddir, cmd)
diff --git a/support/testing/tests/package/test_uboot_tools/key.dts b/support/testing/tests/package/test_uboot_tools/key.dts
new file mode 100644
index 0000000000..c7a686c720
--- /dev/null
+++ b/support/testing/tests/package/test_uboot_tools/key.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+/* This empty dts will be used for storing the public key.
+ * The dtb is populated later by the "mkimage -K" command. */
+
+/ {
+};
diff --git a/support/testing/tests/package/test_uboot_tools/signed.its b/support/testing/tests/package/test_uboot_tools/signed.its
new file mode 100644
index 0000000000..25128cbbda
--- /dev/null
+++ b/support/testing/tests/package/test_uboot_tools/signed.its
@@ -0,0 +1,38 @@
+/dts-v1/;
+
+/ {
+	description = "Signed test FIT";
+	#address-cells = <1>;
+
+	images {
+		kernel {
+			description = "This file, pretending to be a kernel";
+			data = /incbin/("example.its");
+			type = "kernel";
+			arch = "arm64";
+			os = "linux";
+			compression = "none";
+			load = <0x40400000>;
+			entry = <0x40400000>;
+
+			hash-1 {
+				algo = "sha256";
+			};
+		};
+	};
+
+	configurations {
+		default = "config-1";
+
+		config-1 {
+			description = "Signed test entry";
+			kernel = "kernel";
+
+			signature-1 {
+				algo = "sha256,rsa2048";
+				key-name-hint = "dev";
+				sign-images = "kernel";
+			};
+		};
+	};
+};
_______________________________________________
buildroot mailing list
[email protected]
https://lists.buildroot.org/mailman/listinfo/buildroot