[PATCH v2] tools: binman: pass KEYDIR to FIT entries

James Hilliard james.hilliard1 at gmail.com
Thu Jul 9 04:29:00 CEST 2026


U-Boot's Makefile passes KEYDIR to direct mkimage invocations, but
internal binman FIT builds only receive the generic BINMAN_INDIRS search
path. Adding KEYDIR to BINMAN_INDIRS treats it as one more input-file
search path: FIT entries still auto-detect a key directory from all
include directories, so an explicit KEYDIR may not be the directory that
gets passed to mkimage. It also makes a key-only directory part of the
generic blob lookup path.

Forward KEYDIR as a binman entry argument named keydir, matching the
existing entry-argument mechanism used for BL31, TEE, of-list and other
U-Boot build inputs. FIT entries use that directory directly for
mkimage -k when fit,sign or fit,encrypt is enabled, falling back to the
include-directory autodetection when keydir is not provided.

Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
---
Changes v1 -> v2:
  - Use the existing EntryArg mechanism instead of adding a binman build
    -k/--keydir option and global state
  - Explain why KEYDIR should not just be added to BINMAN_INDIRS
  - Clarify KEYDIR documentation as a Makefile-forwarded EntryArg
---
 Makefile                  |  1 +
 tools/binman/binman.rst   |  5 +++++
 tools/binman/etype/fit.py | 28 +++++++++++++++------------
 tools/binman/ftest.py     | 40 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 62 insertions(+), 12 deletions(-)

diff --git a/Makefile b/Makefile
index d8287323c43..c8ac56d36e4 100644
--- a/Makefile
+++ b/Makefile
@@ -1689,6 +1689,7 @@ cmd_binman = $(srctree)/tools/binman/binman $(if $(BINMAN_DEBUG),-D) \
 		-I . -I $(srctree)/board/$(BOARDDIR) -I $(srctree) \
 		$(foreach f,$(of_list_dirs),-I $(f)) -a of-list=$(of_list) \
 		$(foreach f,$(BINMAN_INDIRS),-I $(f)) \
+		$(if $(KEYDIR),-a keydir=$(KEYDIR)) \
 		-a atf-bl1-path=${BL1} \
 		-a atf-bl31-path=${BL31} \
 		-a tee-os-path=${TEE} \
diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst
index 366491089ad..3a860421a69 100644
--- a/tools/binman/binman.rst
+++ b/tools/binman/binman.rst
@@ -2161,6 +2161,11 @@ BINMAN_INDIRS
     Sets the search path for input files used by binman by adding one or more
     `-I` arguments. See :ref:`External blobs`.
 
+KEYDIR
+    Sets the key directory passed to FIT entries by adding a
+    `-a keydir=$(KEYDIR)` argument. FIT entries use this directory for
+    mkimage's `-k` argument when `fit,sign` or `fit,encrypt` is enabled.
+
 BINMAN_TOOLPATHS
     Sets the search path for external tool used by binman by adding one or more
     `--toolpath` arguments. See :ref:`External tools`.
diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py
index f28b1e6b4cb..32caa03a7e1 100644
--- a/tools/binman/etype/fit.py
+++ b/tools/binman/etype/fit.py
@@ -105,18 +105,20 @@ class Entry_fit(Entry_section):
         fit,sign
             Enable signing FIT images via mkimage as described in
             verified-boot.rst.
-            If the property is found and fit,engine is not set, the private
-            keys path is detected among binman include directories and passed to
-            mkimage via -k flag. All the keys required for signing FIT must be
-            available at time of signing and must be located in single include
-            directory.
+            If the property is found and fit,engine is not set, the `keydir`
+            entry argument is passed to mkimage via the -k flag. If no key
+            directory is provided, the private keys path is detected among
+            binman include directories. All the keys required for signing FIT
+            must be available at time of signing and must be located in a
+            single directory.
 
         fit,encrypt
             Enable data encryption in FIT images via mkimage. If the property
-            is found, the keys path is detected among binman include
-            directories and passed to mkimage via  -k flag. All the keys
-            required for encrypting the FIT must be available at the time of
-            encrypting and must be located in a single include directory.
+            is found, the `keydir` entry argument is passed to mkimage via the
+            -k flag. If no key directory is provided, the keys path is detected
+            among binman include directories. All the keys required for
+            encrypting the FIT must be available at the time of encrypting and
+            must be located in a single directory.
 
             Incompatible with fit,engine.
 
@@ -485,6 +487,7 @@ class Entry_fit(Entry_section):
                 includes 'generator' entries which are used to create the FIT,
                 but should not be processed as real entries. This is set up once
                 we have the entries
+            _keydir (str): Key directory from the keydir EntryArg, if provided
             _loadables (list of str): List of generated split-elf nodes, each
                 a node name
             _remove_props (list of str): Value of of-spl-remove-props EntryArg,
@@ -502,8 +505,9 @@ class Entry_fit(Entry_section):
         self._priv_entries = {}
         self._loadables = []
         self._remove_props = []
-        props = self.GetEntryArgsOrProps(
-            [EntryArg('of-spl-remove-props', str)], required=False)[0]
+        props, self._keydir = self.GetEntryArgsOrProps(
+            [EntryArg('of-spl-remove-props', str),
+             EntryArg('keydir', str)], required=False)
         if props:
             self._remove_props = props.split()
         self.mkimage = None
@@ -701,7 +705,7 @@ class Entry_fit(Entry_section):
             args.update({'engine': engine})
             # If no engine, keys must exist locally, find them
             if engine is None:
-                keydir = self._get_keys_dir(data)
+                keydir = self._keydir or self._get_keys_dir(data)
             elif self._fit_props.get('fit,encrypt') is not None:
                 self.Raise('fit,engine currently does not support encryption')
 
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index bf98b268ac1..7b84d79eec0 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -8167,6 +8167,31 @@ fdt         fdtmap                Extract the devicetree blob from the fdtmap
             self.assertIsNotNone(signature)
             self.assertIsNotNone(signature.props.get('value'))
 
+    def testFitSignKeydir(self):
+        """Test that the keydir EntryArg is passed to mkimage"""
+        if not elf.ELF_TOOLS:
+            self.skipTest('Python elftools not available')
+        data = tools.read_file(self.TestFile("fit/rsa2048.key"))
+        self._MakeInputFile("keys/rsa2048.key", data)
+
+        test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
+        keys_subdir = os.path.join(self._indir, "keys")
+        entry_args = {
+            'of-list': 'test-fdt1',
+            'default-dt': 'test-fdt1',
+            'atf-bl31-path': 'bl31.elf',
+            'keydir': keys_subdir,
+        }
+        data = self._DoReadFileDtb(
+            'fit/signature.dts',
+            entry_args=entry_args,
+            extra_indirs=[test_subdir])[0]
+
+        dtb = fdt.Fdt.FromData(data)
+        dtb.Scan()
+        signature = dtb.GetNode('/configurations/conf-uboot-1/signature')
+        self.assertIsNotNone(signature.props.get('value'))
+
     def testFitSignEngineSimple(self):
         """Test that image with FIT and signature nodes can be signed with an
            OpenSSL Engine"""
@@ -8507,6 +8532,21 @@ fdt         fdtmap                Extract the devicetree blob from the fdtmap
             dec_data = file.read()
         self.assertEqual(U_BOOT_NODTB_DATA, dec_data.encode('ascii'))
 
+    def testSimpleFitEncryptedDataKeydir(self):
+        """Test that encrypted FIT data uses the keydir EntryArg"""
+        data = tools.read_file(self.TestFile("fit/aes256.bin"))
+        self._MakeInputFile("keys/aes256.bin", data)
+
+        keys_subdir = os.path.join(self._indir, "keys")
+        data = self._DoReadFileDtb(
+            'fit/encrypt_data.dts',
+            entry_args={'keydir': keys_subdir})[0]
+
+        fit = fdt.Fdt.FromData(data)
+        fit.Scan()
+        node = fit.GetNode('/images/u-boot')
+        self.assertIn('data-size-unciphered', fit.GetProps(node))
+
     def testSimpleFitEncryptedDataMissingKey(self):
         """Test an image with a FIT containing data to be encrypted but with a missing key"""
         with self.assertRaises(ValueError) as e:
-- 
2.53.0



More information about the U-Boot mailing list