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 <[email protected]> --- 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

