Merge branch '2024-12-19-assorted-tooling-updates' into next

This brings in assortment of updates to our python tooling, from Paul
HENRYS <paul.henrys_ext@softathome.com>
diff --git a/include/image.h b/include/image.h
index 9be5acd..cfe3c97 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1788,6 +1788,21 @@
 		       const unsigned char *data, int data_len,
 		       unsigned char **cipher, int *cipher_len);
 
+	/**
+	 * add_cipher_data() - Add cipher data to the FIT and device tree
+	 *
+	 * This is used to add the ciphered data to the FIT and other cipher
+	 * related information (key and initialization vector) to a device tree.
+	 *
+	 * @info: Pointer to image cipher information.
+	 * @keydest: Pointer to a device tree where the key and IV can be
+	 *           stored. keydest can be NULL when the key is retrieved at
+	 *           runtime by another mean.
+	 * @fit: Pointer to the FIT image.
+	 * @node_noffset: Offset where the cipher information are stored in the
+	 *                FIT.
+	 * return: 0 on success, a negative error code otherwise.
+	 */
 	int (*add_cipher_data)(struct image_cipher_info *info,
 			       void *keydest, void *fit, int node_noffset);
 
diff --git a/lib/aes/aes-encrypt.c b/lib/aes/aes-encrypt.c
index e74e35e..90e1407 100644
--- a/lib/aes/aes-encrypt.c
+++ b/lib/aes/aes-encrypt.c
@@ -84,6 +84,13 @@
 	char name[128];
 	int ret = 0;
 
+	if (!keydest && !info->ivname) {
+		/* At least, store the IV in the FIT image */
+		ret = fdt_setprop(fit, node_noffset, "iv",
+				  info->iv, info->cipher->iv_len);
+		goto done;
+	}
+
 	/* Either create or overwrite the named cipher node */
 	parent = fdt_subnode_offset(keydest, 0, FIT_CIPHER_NODENAME);
 	if (parent == -FDT_ERR_NOTFOUND) {
diff --git a/tools/binman/btool/mkimage.py b/tools/binman/btool/mkimage.py
index 78d3301..3f84220 100644
--- a/tools/binman/btool/mkimage.py
+++ b/tools/binman/btool/mkimage.py
@@ -22,7 +22,7 @@
 
     # pylint: disable=R0913
     def run(self, reset_timestamp=False, output_fname=None, external=False,
-            pad=None, align=None, priv_keys_dir=None):
+            pad=None, align=None, keys_dir=None):
         """Run mkimage
 
         Args:
@@ -34,7 +34,7 @@
                 other things to be easily added later, if required, such as
                 signatures
             align: Bytes to use for alignment of the FIT and its external data
-            priv_keys_dir: Path to directory containing private keys
+            keys_dir: Path to directory containing private and encryption keys
             version: True to get the mkimage version
         """
         args = []
@@ -46,8 +46,8 @@
             args += ['-B', f'{align:x}']
         if reset_timestamp:
             args.append('-t')
-        if priv_keys_dir:
-            args += ['-k', f'{priv_keys_dir}']
+        if keys_dir:
+            args += ['-k', f'{keys_dir}']
         if output_fname:
             args += ['-F', output_fname]
         return self.run_cmd(*args)
diff --git a/tools/binman/control.py b/tools/binman/control.py
index 542c2b4..e73c598 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -526,7 +526,7 @@
         if node.name.startswith('template'):
             node.Delete()
 
-def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded):
+def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded, indir):
     """Prepare the images to be processed and select the device tree
 
     This function:
@@ -543,6 +543,7 @@
         use_expanded: True to use expanded versions of entries, if available.
             So if 'u-boot' is called for, we use 'u-boot-expanded' instead. This
             is needed if update_fdt is True (although tests may disable it)
+        indir: List of directories where input files can be found
 
     Returns:
         OrderedDict of images:
@@ -558,7 +559,9 @@
     # Get the device tree ready by compiling it and copying the compiled
     # output into a file in our output directly. Then scan it for use
     # in binman.
-    dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
+    if indir is None:
+        indir = []
+    dtb_fname = fdt_util.EnsureCompiled(dtb_fname, indir=indir)
     fname = tools.get_output_filename('u-boot.dtb.out')
     tools.write_file(fname, tools.read_file(dtb_fname))
     dtb = fdt.FdtScan(fname)
@@ -846,7 +849,7 @@
             state.SetThreads(args.threads)
 
             images = PrepareImagesAndDtbs(dtb_fname, args.image,
-                                          args.update_fdt, use_expanded)
+                                          args.update_fdt, use_expanded, args.indir)
 
             if args.test_section_timeout:
                 # Set the first image to timeout, used in testThreadTimeout()
diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst
index e918162..83068ba 100644
--- a/tools/binman/entries.rst
+++ b/tools/binman/entries.rst
@@ -871,6 +871,13 @@
         -k flag. All the keys required for signing FIT must be available at
         time of signing and must be located in single include 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.
+
 Substitutions
 ~~~~~~~~~~~~~
 
@@ -892,6 +899,9 @@
     Sequence number of the default fdt, as provided by the 'default-dt'
     entry argument
 
+DEFAULT-NAME:
+    Name of the default fdt, as provided by the 'default-dt' entry argument
+
 Available operations
 ~~~~~~~~~~~~~~~~~~~~
 
@@ -953,6 +963,21 @@
 This tells binman to create nodes `config-1` and `config-2`, i.e. a config
 for each of your two files.
 
+It is also possible to use NAME in the node names so that the FDT files name
+will be used instead of the sequence number. This can be useful to identify
+easily at runtime in U-Boot, the config to be used::
+
+    configurations {
+        default = "@config-DEFAULT-NAME";
+        @config-NAME {
+            description = "NAME";
+            firmware = "atf";
+            loadables = "uboot";
+            fdt = "fdt-NAME";
+            fit,compatible;    // optional
+        };
+    };
+
 Note that if no devicetree files are provided (with '-a of-list' as above)
 then no nodes will be generated.
 
diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py
index b5afbda..803fb66 100644
--- a/tools/binman/etype/fit.py
+++ b/tools/binman/etype/fit.py
@@ -110,6 +110,13 @@
             available at time of signing and must be located in single include
             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.
+
     Substitutions
     ~~~~~~~~~~~~~
 
@@ -131,6 +138,9 @@
         Sequence number of the default fdt, as provided by the 'default-dt'
         entry argument
 
+    DEFAULT-NAME:
+        Name of the default fdt, as provided by the 'default-dt' entry argument
+
     Available operations
     ~~~~~~~~~~~~~~~~~~~~
 
@@ -192,6 +202,21 @@
     This tells binman to create nodes `config-1` and `config-2`, i.e. a config
     for each of your two files.
 
+    It is also possible to use NAME in the node names so that the FDT files name
+    will be used instead of the sequence number. This can be useful to identify
+    easily at runtime in U-Boot, the config to be used::
+
+        configurations {
+            default = "@config-DEFAULT-NAME";
+            @config-NAME {
+                description = "NAME";
+                firmware = "atf";
+                loadables = "uboot";
+                fdt = "fdt-NAME";
+                fit,compatible;    // optional
+            };
+        };
+
     Note that if no devicetree files are provided (with '-a of-list' as above)
     then no nodes will be generated.
 
@@ -452,6 +477,8 @@
             self._fdt_dir = fdt_util.GetString(self._node, 'fit,fdt-list-dir')
             if self._fdt_dir:
                 indir = tools.get_input_filename(self._fdt_dir)
+                if indir:
+                    tools.append_input_dirs(indir)
                 fdts = glob.glob('*.dtb', root_dir=indir)
                 self._fdts = [os.path.splitext(f)[0] for f in sorted(fdts)]
             else:
@@ -518,14 +545,14 @@
         # are removed from self._entries later.
         self._priv_entries = dict(self._entries)
 
-    def _get_priv_keys_dir(self, data):
-        """Detect private keys path among binman include directories
+    def _get_keys_dir(self, data):
+        """Detect private and encryption keys path among binman include directories
 
         Args:
             data: FIT image in binary format
 
         Returns:
-            str: Single path containing all private keys found or None
+            str: Single path containing all keys found or None
 
         Raises:
             ValueError: Filename 'rsa2048.key' not found in input path
@@ -533,11 +560,14 @@
         """
         def _find_keys_dir(node):
             for subnode in node.subnodes:
-                if subnode.name.startswith('signature'):
+                if (subnode.name.startswith('signature') or
+                    subnode.name.startswith('cipher')):
                     if subnode.props.get('key-name-hint') is None:
                         continue
                     hint = subnode.props['key-name-hint'].value
-                    name = tools.get_input_filename(f"{hint}.key")
+                    name = tools.get_input_filename(
+                        f"{hint}.key" if subnode.name.startswith('signature')
+                        else f"{hint}.bin")
                     path = os.path.dirname(name)
                     if path not in paths:
                         paths.append(path)
@@ -587,8 +617,9 @@
         align = self._fit_props.get('fit,align')
         if align is not None:
             args.update({'align': fdt_util.fdt32_to_cpu(align.value)})
-        if self._fit_props.get('fit,sign') is not None:
-            args.update({'priv_keys_dir': self._get_priv_keys_dir(data)})
+        if (self._fit_props.get('fit,sign') is not None or
+            self._fit_props.get('fit,encrypt') is not None):
+            args.update({'keys_dir': self._get_keys_dir(data)})
         if self.mkimage.run(reset_timestamp=True, output_fname=output_fname,
                             **args) is None:
             if not self.GetAllowMissing():
@@ -663,6 +694,7 @@
                                 f"not found in fdt list: {', '.join(self._fdts)}")
                     seq = self._fdts.index(default_dt)
                     val = val[1:].replace('DEFAULT-SEQ', str(seq + 1))
+                    val = val.replace('DEFAULT-NAME', self._fit_default_dt)
                     fsw.property_string(pname, val)
                     return
             elif pname.startswith('fit,'):
@@ -729,6 +761,7 @@
                 # Generate nodes for each FDT
                 for seq, fdt_fname in enumerate(self._fdts):
                     node_name = node.name[1:].replace('SEQ', str(seq + 1))
+                    node_name = node_name.replace('NAME', fdt_fname)
                     if self._fdt_dir:
                         fname = os.path.join(self._fdt_dir, fdt_fname + '.dtb')
                     else:
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 156567a..a553ca9 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -4233,56 +4233,69 @@
         self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
 
     def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
-                    default_dt=None):
+                    default_dt=None, use_seq_num=True):
         """Check an image with an FIT with multiple FDT images"""
-        def _CheckFdt(seq, expected_data):
+        def _CheckFdt(val, expected_data):
             """Check the FDT nodes
 
             Args:
-                seq: Sequence number to check (0 or 1)
+                val: Sequence number to check (0 or 1) or fdt name
                 expected_data: Expected contents of 'data' property
             """
-            name = 'fdt-%d' % seq
+            name = 'fdt-%s' % val
             fnode = dtb.GetNode('/images/%s' % name)
             self.assertIsNotNone(fnode)
             self.assertEqual({'description','type', 'compression', 'data'},
                              set(fnode.props.keys()))
             self.assertEqual(expected_data, fnode.props['data'].bytes)
-            self.assertEqual('fdt-test-fdt%d.dtb' % seq,
-                             fnode.props['description'].value)
+            description = (
+                'fdt-test-fdt%s.dtb' % val if len(val) == 1 else
+                'fdt-%s.dtb' % val
+            )
+            self.assertEqual(description, fnode.props['description'].value)
             self.assertEqual(fnode.subnodes[0].name, 'hash')
 
-        def _CheckConfig(seq, expected_data):
+        def _CheckConfig(val, expected_data):
             """Check the configuration nodes
 
             Args:
-                seq: Sequence number to check (0 or 1)
+                val: Sequence number to check (0 or 1) or fdt name
                 expected_data: Expected contents of 'data' property
             """
             cnode = dtb.GetNode('/configurations')
             self.assertIn('default', cnode.props)
-            self.assertEqual('config-2', cnode.props['default'].value)
+            default = (
+                'config-2' if len(val) == 1 else
+                'config-test-fdt2'
+            )
+            self.assertEqual(default, cnode.props['default'].value)
 
-            name = 'config-%d' % seq
+            name = 'config-%s' % val
             fnode = dtb.GetNode('/configurations/%s' % name)
             self.assertIsNotNone(fnode)
             self.assertEqual({'description','firmware', 'loadables', 'fdt'},
                              set(fnode.props.keys()))
-            self.assertEqual('conf-test-fdt%d.dtb' % seq,
-                             fnode.props['description'].value)
-            self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
+            description = (
+                'conf-test-fdt%s.dtb' % val if len(val) == 1 else
+                'conf-%s.dtb' % val
+            )
+            self.assertEqual(description, fnode.props['description'].value)
+            self.assertEqual('fdt-%s' % val, fnode.props['fdt'].value)
 
         entry_args = {
             'default-dt': 'test-fdt2',
         }
+        extra_indirs = None
         if use_fdt_list:
             entry_args['of-list'] = 'test-fdt1 test-fdt2'
         if default_dt:
             entry_args['default-dt'] = default_dt
+        if use_fdt_list:
+            extra_indirs = [os.path.join(self._indir, TEST_FDT_SUBDIR)]
         data = self._DoReadFileDtb(
             dts,
             entry_args=entry_args,
-            extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
+            extra_indirs=extra_indirs)[0]
         self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
         fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
 
@@ -4291,13 +4304,22 @@
         fnode = dtb.GetNode('/images/kernel')
         self.assertIn('data', fnode.props)
 
-        # Check all the properties in fdt-1 and fdt-2
-        _CheckFdt(1, TEST_FDT1_DATA)
-        _CheckFdt(2, TEST_FDT2_DATA)
+        if use_seq_num == True:
+            # Check all the properties in fdt-1 and fdt-2
+            _CheckFdt('1', TEST_FDT1_DATA)
+            _CheckFdt('2', TEST_FDT2_DATA)
 
-        # Check configurations
-        _CheckConfig(1, TEST_FDT1_DATA)
-        _CheckConfig(2, TEST_FDT2_DATA)
+            # Check configurations
+            _CheckConfig('1', TEST_FDT1_DATA)
+            _CheckConfig('2', TEST_FDT2_DATA)
+        else:
+            # Check all the properties in fdt-1 and fdt-2
+            _CheckFdt('test-fdt1', TEST_FDT1_DATA)
+            _CheckFdt('test-fdt2', TEST_FDT2_DATA)
+
+            # Check configurations
+            _CheckConfig('test-fdt1', TEST_FDT1_DATA)
+            _CheckConfig('test-fdt2', TEST_FDT2_DATA)
 
     def testFitFdt(self):
         """Test an image with an FIT with multiple FDT images"""
@@ -7899,6 +7921,55 @@
             entry_args=entry_args,
             extra_indirs=[test_subdir])[0]
 
+
+    def testSimpleFitEncryptedData(self):
+        """Test an image with a FIT containing data to be encrypted"""
+        data = tools.read_file(self.TestFile("aes256.bin"))
+        self._MakeInputFile("keys/aes256.bin", data)
+
+        keys_subdir = os.path.join(self._indir, "keys")
+        data = self._DoReadFileDtb(
+            '343_fit_encrypt_data.dts',
+            extra_indirs=[keys_subdir])[0]
+
+        fit = fdt.Fdt.FromData(data)
+        fit.Scan()
+
+        # Extract the encrypted data and the Initialization Vector from the FIT
+        node = fit.GetNode('/images/u-boot')
+        subnode = fit.GetNode('/images/u-boot/cipher')
+        data_size_unciphered = int.from_bytes(fit.GetProps(node)['data-size-unciphered'].bytes,
+                                              byteorder='big')
+        self.assertEqual(data_size_unciphered, len(U_BOOT_NODTB_DATA))
+
+        # Retrieve the key name from the FIT removing any null byte
+        key_name = fit.GetProps(subnode)['key-name-hint'].bytes.replace(b'\x00', b'')
+        with open(self.TestFile(key_name.decode('ascii') + '.bin'), 'rb') as file:
+            key = file.read()
+        iv = fit.GetProps(subnode)['iv'].bytes.hex()
+        enc_data = fit.GetProps(node)['data'].bytes
+        outdir = tools.get_output_dir()
+        enc_data_file = os.path.join(outdir, 'encrypted_data.bin')
+        tools.write_file(enc_data_file, enc_data)
+        data_file = os.path.join(outdir, 'data.bin')
+
+        # Decrypt the encrypted data from the FIT and compare the data
+        tools.run('openssl', 'enc', '-aes-256-cbc', '-nosalt', '-d', '-in',
+                  enc_data_file, '-out', data_file, '-K', key.hex(), '-iv', iv)
+        with open(data_file, 'r') as file:
+            dec_data = file.read()
+        self.assertEqual(U_BOOT_NODTB_DATA, dec_data.encode('ascii'))
+
+    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:
+            self._DoReadFile('344_fit_encrypt_data_no_key.dts')
+
+        self.assertIn("Filename 'aes256.bin' not found in input path", str(e.exception))
+
+    def testFitFdtName(self):
+        """Test an image with an FIT with multiple FDT images using NAME"""
+        self.CheckFitFdt('345_fit_fdt_name.dts', use_seq_num=False)
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/343_fit_encrypt_data.dts b/tools/binman/test/343_fit_encrypt_data.dts
new file mode 100644
index 0000000..d70de34
--- /dev/null
+++ b/tools/binman/test/343_fit_encrypt_data.dts
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		fit {
+			fit,encrypt;
+			description = "Test a FIT with encrypted data";
+			#address-cells = <1>;
+
+			images {
+				u-boot {
+					description = "U-Boot";
+					type = "firmware";
+					arch = "arm64";
+					os = "U-Boot";
+					compression = "none";
+					load = <00000000>;
+					entry = <00000000>;
+					cipher {
+						algo = "aes256";
+						key-name-hint = "aes256";
+					};
+					u-boot-nodtb {
+					};
+				};
+				fdt-1 {
+					description = "Flattened Device Tree blob";
+					type = "flat_dt";
+					arch = "arm64";
+					compression = "none";
+					cipher {
+						algo = "aes256";
+						key-name-hint = "aes256";
+					};
+				};
+			};
+
+			configurations {
+				default = "conf-1";
+				conf-1 {
+					description = "Boot U-Boot with FDT blob";
+					firmware = "u-boot";
+					fdt = "fdt-1";
+				};
+			};
+		};
+	};
+};
diff --git a/tools/binman/test/344_fit_encrypt_data_no_key.dts b/tools/binman/test/344_fit_encrypt_data_no_key.dts
new file mode 100644
index 0000000..d70de34
--- /dev/null
+++ b/tools/binman/test/344_fit_encrypt_data_no_key.dts
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		fit {
+			fit,encrypt;
+			description = "Test a FIT with encrypted data";
+			#address-cells = <1>;
+
+			images {
+				u-boot {
+					description = "U-Boot";
+					type = "firmware";
+					arch = "arm64";
+					os = "U-Boot";
+					compression = "none";
+					load = <00000000>;
+					entry = <00000000>;
+					cipher {
+						algo = "aes256";
+						key-name-hint = "aes256";
+					};
+					u-boot-nodtb {
+					};
+				};
+				fdt-1 {
+					description = "Flattened Device Tree blob";
+					type = "flat_dt";
+					arch = "arm64";
+					compression = "none";
+					cipher {
+						algo = "aes256";
+						key-name-hint = "aes256";
+					};
+				};
+			};
+
+			configurations {
+				default = "conf-1";
+				conf-1 {
+					description = "Boot U-Boot with FDT blob";
+					firmware = "u-boot";
+					fdt = "fdt-1";
+				};
+			};
+		};
+	};
+};
diff --git a/tools/binman/test/345_fit_fdt_name.dts b/tools/binman/test/345_fit_fdt_name.dts
new file mode 100644
index 0000000..631a8e5
--- /dev/null
+++ b/tools/binman/test/345_fit_fdt_name.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		u-boot {
+		};
+		fit {
+			description = "test-desc";
+			#address-cells = <1>;
+			fit,fdt-list = "of-list";
+
+			images {
+				kernel {
+					description = "Vanilla Linux kernel";
+					type = "kernel";
+					arch = "ppc";
+					os = "linux";
+					compression = "gzip";
+					load = <00000000>;
+					entry = <00000000>;
+					hash-1 {
+						algo = "crc32";
+					};
+					hash-2 {
+						algo = "sha1";
+					};
+					u-boot {
+					};
+				};
+				@fdt-NAME {
+					description = "fdt-NAME.dtb";
+					type = "flat_dt";
+					compression = "none";
+					hash {
+						algo = "sha256";
+					};
+				};
+			};
+
+			configurations {
+				default = "@config-DEFAULT-NAME";
+				@config-NAME {
+					description = "conf-NAME.dtb";
+					firmware = "uboot";
+					loadables = "atf";
+					fdt = "fdt-NAME";
+				};
+			};
+		};
+		u-boot-nodtb {
+		};
+	};
+};
diff --git a/tools/binman/test/aes256.bin b/tools/binman/test/aes256.bin
new file mode 100644
index 0000000..09b8bf6
--- /dev/null
+++ b/tools/binman/test/aes256.bin
@@ -0,0 +1 @@
+1234567890abcdefghijklmnopqrstuv
\ No newline at end of file
diff --git a/tools/dtoc/fdt_util.py b/tools/dtoc/fdt_util.py
index f1f7056..d5ecc42 100644
--- a/tools/dtoc/fdt_util.py
+++ b/tools/dtoc/fdt_util.py
@@ -55,7 +55,7 @@
         out = out << 32 | fdt32_to_cpu(val[1])
     return out
 
-def EnsureCompiled(fname, tmpdir=None, capture_stderr=False):
+def EnsureCompiled(fname, tmpdir=None, capture_stderr=False, indir=None):
     """Compile an fdt .dts source file into a .dtb binary blob if needed.
 
     Args:
@@ -63,6 +63,7 @@
             left alone
         tmpdir: Temporary directory for output files, or None to use the
             tools-module output directory
+        indir: List of directories where input files can be found
 
     Returns:
         Filename of resulting .dtb file
@@ -79,6 +80,8 @@
         dtb_output = tools.get_output_filename('source.dtb')
 
     search_paths = [os.path.join(os.getcwd(), 'include')]
+    if indir is not None:
+        search_paths += indir
     root, _ = os.path.splitext(fname)
     cc, args = tools.get_target_compile_tool('cc')
     args += ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__']
diff --git a/tools/image-host.c b/tools/image-host.c
index 5e01b85..16389bd 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -535,7 +535,7 @@
 	 * size values
 	 * And, if needed, write the iv in the FIT file
 	 */
-	if (keydest) {
+	if (keydest || (!keydest && !info.ivname)) {
 		ret = info.cipher->add_cipher_data(&info, keydest, fit, node_noffset);
 		if (ret) {
 			fprintf(stderr,
diff --git a/tools/u_boot_pylib/tools.py b/tools/u_boot_pylib/tools.py
index 187725b..0499a75 100644
--- a/tools/u_boot_pylib/tools.py
+++ b/tools/u_boot_pylib/tools.py
@@ -123,6 +123,22 @@
     indir = dirname
     tout.debug("Using input directories %s" % indir)
 
+def append_input_dirs(dirname):
+    """Append a list of input directories to the current list of input
+    directories
+
+    Args:
+        dirname: a list of paths to input directories to use for obtaining
+                files needed by binman to place in the image.
+    """
+    global indir
+
+    for dir in dirname:
+        if dirname not in indir:
+            indir.append(dirname)
+
+    tout.debug("Updated input directories %s" % indir)
+
 def get_input_filename(fname, allow_missing=False):
     """Return a filename for use as input.