binman: add tests for sign option
Add the test which provides sequence of actions:
1. create the image from binman dts
2. create public and private keys
3. add public key into dtb with fdt_add_pubkey
4. 1. sign FIT container with new sign option with extracting from
image
2. sign exact FIT container with replacing of it in image
5. check with fit_check_sign
Signed-off-by: Ivan Mikhaylov <fr0st61te@gmail.com>
Renumber test file from 277 to 280;
Move UpdateSignatures() to Entry base class;
Don't allow missing mkimage as it doesn't make sense;
Propagate --toolpath for CI;
Call mark_build_done() to avoid regenerating FIT:
Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/tools/binman/control.py b/tools/binman/control.py
index cf2c91f..0febcb7 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -464,6 +464,8 @@
image_fname = os.path.abspath(image_fname)
image = Image.FromFile(image_fname)
+ image.mark_build_done()
+
BeforeReplace(image, allow_resize=True)
for entry_path in entry_paths:
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index b10a433..3945690 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -1378,3 +1378,6 @@
if entries:
for entry in entries.values():
entry.mark_build_done()
+
+ def UpdateSignatures(self, privatekey_fname, algo, input_fname):
+ self.Raise('Updating signatures is not supported with this entry type')
diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py
index 3aea986..c395706 100644
--- a/tools/binman/etype/fit.py
+++ b/tools/binman/etype/fit.py
@@ -847,9 +847,7 @@
args.append(fname)
if self.mkimage.run_cmd(*args) is None:
- # Bintool is missing; just use empty data as the output
- self.record_missing_bintool(self.mkimage)
- return
+ self.Raise("Missing tool: 'mkimage'")
data = tools.read_file(fname)
self.WriteData(data)
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
index e87009d..c36edd1 100644
--- a/tools/binman/etype/section.py
+++ b/tools/binman/etype/section.py
@@ -1014,6 +1014,3 @@
for entry in entries.values():
return entry.read_elf_segments()
return None
-
- def UpdateSignatures(self, privatekey_fname, algo, input_fname):
- self.Raise('Updating signatures is not supported with this entry type')
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index f1e14c6..9862e23 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -707,6 +707,14 @@
AddNode(dtb.GetRoot(), '')
return tree
+ def _CheckSign(self, fit, key):
+ try:
+ tools.run('fit_check_sign', '-k', key, '-f', fit)
+ except:
+ self.fail('Expected signed FIT container')
+ return False
+ return True
+
def testRun(self):
"""Test a basic run with valid args"""
result = self._RunBinman('-h')
@@ -6565,6 +6573,91 @@
err = stderr.getvalue()
self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
+ def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
+ """Prepare sign environment
+
+ Create private and public keys, add pubkey into dtb.
+
+ Returns:
+ Tuple:
+ FIT container
+ Image name
+ Private key
+ DTB
+ """
+
+ data = self._DoReadFileRealDtb(dts)
+ updated_fname = tools.get_output_filename('image-updated.bin')
+ tools.write_file(updated_fname, data)
+ dtb = tools.get_output_filename('source.dtb')
+ private_key = tools.get_output_filename('test_key.key')
+ public_key = tools.get_output_filename('test_key.crt')
+ fit = tools.get_output_filename('fit.fit')
+ key_dir = tools.get_output_dir()
+
+ tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
+ '-sha256', '-new', '-nodes', '-x509', '-keyout',
+ private_key, '-out', public_key)
+ tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
+ '-n', 'test_key', '-r', 'conf', dtb)
+
+ return fit, updated_fname, private_key, dtb
+
+ def testSignSimple(self):
+ """Test that a FIT container can be signed in image"""
+ is_signed = False
+ fit, fname, private_key, dtb = self._PrepareSignEnv()
+
+ # do sign with private key
+ control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
+ ['fit'])
+ is_signed = self._CheckSign(fit, dtb)
+
+ self.assertEqual(is_signed, True)
+
+ def testSignExactFIT(self):
+ """Test that a FIT container can be signed and replaced in image"""
+ is_signed = False
+ fit, fname, private_key, dtb = self._PrepareSignEnv()
+
+ # Make sure we propagate the toolpath, since mkimage may not be on PATH
+ args = []
+ if self.toolpath:
+ for path in self.toolpath:
+ args += ['--toolpath', path]
+
+ # do sign with private key
+ self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
+ 'sha256,rsa4096', '-f', fit, 'fit')
+ is_signed = self._CheckSign(fit, dtb)
+
+ self.assertEqual(is_signed, True)
+
+ def testSignNonFit(self):
+ """Test a non-FIT entry cannot be signed"""
+ is_signed = False
+ fit, fname, private_key, _ = self._PrepareSignEnv(
+ '281_sign_non_fit.dts')
+
+ # do sign with private key
+ with self.assertRaises(ValueError) as e:
+ self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
+ 'sha256,rsa4096', '-f', fit, 'u-boot')
+ self.assertIn(
+ "Node '/u-boot': Updating signatures is not supported with this entry type",
+ str(e.exception))
+
+ def testSignMissingMkimage(self):
+ """Test that FIT signing handles a missing mkimage tool"""
+ fit, fname, private_key, _ = self._PrepareSignEnv()
+
+ # try to sign with a missing mkimage tool
+ bintool.Bintool.set_missing_list(['mkimage'])
+ with self.assertRaises(ValueError) as e:
+ control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
+ ['fit'])
+ self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
+
if __name__ == "__main__":
unittest.main()
diff --git a/tools/binman/test/280_fit_sign.dts b/tools/binman/test/280_fit_sign.dts
new file mode 100644
index 0000000..b9f17dc
--- /dev/null
+++ b/tools/binman/test/280_fit_sign.dts
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ size = <0x100000>;
+ allow-repack;
+
+ fit {
+ description = "U-Boot";
+ offset = <0x10000>;
+ images {
+ u-boot-1 {
+ description = "U-Boot";
+ type = "standalone";
+ arch = "arm64";
+ os = "u-boot";
+ compression = "none";
+ hash-1 {
+ algo = "sha256";
+ };
+ u-boot {
+ };
+ };
+
+ fdt-1 {
+ description = "test.dtb";
+ type = "flat_dt";
+ arch = "arm64";
+ compression = "none";
+ hash-1 {
+ algo = "sha256";
+ };
+ u-boot-spl-dtb {
+ };
+ };
+
+ };
+
+ configurations {
+ default = "conf-1";
+ conf-1 {
+ description = "u-boot with fdt";
+ firmware = "u-boot-1";
+ fdt = "fdt-1";
+ signature-1 {
+ algo = "sha256,rsa4096";
+ key-name-hint = "test_key";
+ sign-images = "firmware", "fdt";
+ };
+
+ };
+ };
+ };
+
+ fdtmap {
+ };
+ };
+};
diff --git a/tools/binman/test/281_sign_non_fit.dts b/tools/binman/test/281_sign_non_fit.dts
new file mode 100644
index 0000000..e16c954
--- /dev/null
+++ b/tools/binman/test/281_sign_non_fit.dts
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ size = <0x100000>;
+ allow-repack;
+
+ u-boot {
+ };
+ fit {
+ description = "U-Boot";
+ offset = <0x10000>;
+ images {
+ u-boot-1 {
+ description = "U-Boot";
+ type = "standalone";
+ arch = "arm64";
+ os = "u-boot";
+ compression = "none";
+ hash-1 {
+ algo = "sha256";
+ };
+ u-boot {
+ };
+ };
+
+ fdt-1 {
+ description = "test.dtb";
+ type = "flat_dt";
+ arch = "arm64";
+ compression = "none";
+ hash-1 {
+ algo = "sha256";
+ };
+ u-boot-spl-dtb {
+ };
+ };
+
+ };
+
+ configurations {
+ default = "conf-1";
+ conf-1 {
+ description = "u-boot with fdt";
+ firmware = "u-boot-1";
+ fdt = "fdt-1";
+ signature-1 {
+ algo = "sha256,rsa4096";
+ key-name-hint = "test_key";
+ sign-images = "firmware", "fdt";
+ };
+
+ };
+ };
+ };
+
+ fdtmap {
+ };
+ };
+};