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>
This commit is contained in:
Ivan Mikhaylov 2023-03-08 01:13:40 +00:00 committed by Simon Glass
parent 4023dc9c95
commit 5b34efe865
7 changed files with 227 additions and 6 deletions

View file

@ -464,6 +464,8 @@ def SignEntries(image_fname, input_fname, privatekey_fname, algo, entry_paths,
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:

View file

@ -1378,3 +1378,6 @@ features to produce new behaviours.
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')

View file

@ -847,9 +847,7 @@ class Entry_fit(Entry_section):
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)

View file

@ -1014,6 +1014,3 @@ class Entry_section(Entry):
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')

View file

@ -707,6 +707,14 @@ class TestFunctional(unittest.TestCase):
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 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
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()

View file

@ -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 {
};
};
};

View file

@ -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 {
};
};
};