[PATCH v4 16/18] test: py: vboot: add test for global image signature
Philippe Reynes
philippe.reynes at softathome.com
Mon Jan 31 15:55:56 CET 2022
Adds test units for the pre-load header signature.
Signed-off-by: Philippe Reynes <philippe.reynes at softathome.com>
---
test/py/tests/test_vboot.py | 119 ++++++++++++++++--
test/py/tests/vboot/sandbox-binman-pss.dts | 25 ++++
test/py/tests/vboot/sandbox-binman.dts | 24 ++++
.../tests/vboot/sandbox-u-boot-global-pss.dts | 25 ++++
test/py/tests/vboot/sandbox-u-boot-global.dts | 24 ++++
test/py/tests/vboot/simple-images.its | 36 ++++++
6 files changed, 240 insertions(+), 13 deletions(-)
create mode 100644 test/py/tests/vboot/sandbox-binman-pss.dts
create mode 100644 test/py/tests/vboot/sandbox-binman.dts
create mode 100644 test/py/tests/vboot/sandbox-u-boot-global-pss.dts
create mode 100644 test/py/tests/vboot/sandbox-u-boot-global.dts
create mode 100644 test/py/tests/vboot/simple-images.its
diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py
index 095e00cce3..501caa3a50 100644
--- a/test/py/tests/test_vboot.py
+++ b/test/py/tests/test_vboot.py
@@ -35,16 +35,18 @@ import vboot_evil
# Only run the full suite on a few combinations, since it doesn't add any more
# test coverage.
TESTDATA = [
- ['sha1-basic', 'sha1', '', None, False, True],
- ['sha1-pad', 'sha1', '', '-E -p 0x10000', False, False],
- ['sha1-pss', 'sha1', '-pss', None, False, False],
- ['sha1-pss-pad', 'sha1', '-pss', '-E -p 0x10000', False, False],
- ['sha256-basic', 'sha256', '', None, False, False],
- ['sha256-pad', 'sha256', '', '-E -p 0x10000', False, False],
- ['sha256-pss', 'sha256', '-pss', None, False, False],
- ['sha256-pss-pad', 'sha256', '-pss', '-E -p 0x10000', False, False],
- ['sha256-pss-required', 'sha256', '-pss', None, True, False],
- ['sha256-pss-pad-required', 'sha256', '-pss', '-E -p 0x10000', True, True],
+ ['sha1-basic', 'sha1', '', None, False, True, False],
+ ['sha1-pad', 'sha1', '', '-E -p 0x10000', False, False, False],
+ ['sha1-pss', 'sha1', '-pss', None, False, False, False],
+ ['sha1-pss-pad', 'sha1', '-pss', '-E -p 0x10000', False, False, False],
+ ['sha256-basic', 'sha256', '', None, False, False, False],
+ ['sha256-pad', 'sha256', '', '-E -p 0x10000', False, False, False],
+ ['sha256-pss', 'sha256', '-pss', None, False, False, False],
+ ['sha256-pss-pad', 'sha256', '-pss', '-E -p 0x10000', False, False, False],
+ ['sha256-pss-required', 'sha256', '-pss', None, True, False, False],
+ ['sha256-pss-pad-required', 'sha256', '-pss', '-E -p 0x10000', True, True, False],
+ ['sha256-global-sign', 'sha256', '', '', False, False, True],
+ ['sha256-global-sign-pss', 'sha256', '-pss', '', False, False, True],
]
@pytest.mark.boardspec('sandbox')
@@ -53,10 +55,10 @@ TESTDATA = [
@pytest.mark.requiredtool('fdtget')
@pytest.mark.requiredtool('fdtput')
@pytest.mark.requiredtool('openssl')
- at pytest.mark.parametrize("name,sha_algo,padding,sign_options,required,full_test",
+ at pytest.mark.parametrize("name,sha_algo,padding,sign_options,required,full_test,global_sign",
TESTDATA)
def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required,
- full_test):
+ full_test,global_sign):
"""Test verified boot signing with mkimage and verification with 'bootm'.
This works using sandbox only as it needs to update the device tree used
@@ -78,6 +80,29 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required,
util.run_and_log(cons, 'dtc %s %s%s -O dtb '
'-o %s%s' % (dtc_args, datadir, dts, tmpdir, dtb))
+ def dtc_options(dts, options):
+ """Run the device tree compiler to compile a .dts file
+
+ The output file will be the same as the input file but with a .dtb
+ extension.
+
+ Args:
+ dts: Device tree file to compile.
+ options: Options provided to the compiler.
+ """
+ dtb = dts.replace('.dts', '.dtb')
+ util.run_and_log(cons, 'dtc %s %s%s -O dtb '
+ '-o %s%s %s' % (dtc_args, datadir, dts, tmpdir, dtb, options))
+
+ def run_binman(dtb):
+ """Run binman to build an image
+
+ Args:
+ dtb: Device tree file used as input file.
+ """
+ util.run_and_log(cons, [binman, 'build', '-d', "%s/%s" % (tmpdir,dtb),
+ '-a', "key-path=%s" % tmpdir, '-O', tmpdir, '-I', tmpdir])
+
def run_bootm(sha_algo, test_type, expect_string, boots, fit=None):
"""Run a 'bootm' command U-Boot.
@@ -136,6 +161,23 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required,
cons.log.action('%s: Sign images' % sha_algo)
util.run_and_log(cons, args)
+ def sign_fit_dtb(sha_algo, options, dtb):
+ """Sign the FIT
+
+ Signs the FIT and writes the signature into it. It also writes the
+ public key into the dtb.
+
+ Args:
+ sha_algo: Either 'sha1' or 'sha256', to select the algorithm to
+ use.
+ options: Options to provide to mkimage.
+ """
+ args = [mkimage, '-F', '-k', tmpdir, '-K', dtb, '-r', fit]
+ if options:
+ args += options.split(' ')
+ cons.log.action('%s: Sign images' % sha_algo)
+ util.run_and_log(cons, args)
+
def sign_fit_norequire(sha_algo, options):
"""Sign the FIT
@@ -173,6 +215,11 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required,
handle.write(struct.pack(">I", size))
return struct.unpack(">I", total_size)[0]
+ def corrupt_file(fit,offset,value):
+ with open(fit, 'r+b') as handle:
+ handle.seek(offset)
+ handle.write(struct.pack(">I", value))
+
def create_rsa_pair(name):
"""Generate a new RSA key paid and certificate
@@ -365,6 +412,49 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required,
(dtb))
run_bootm(sha_algo, 'multi required key', '', False)
+ def test_global_sign(sha_algo, padding, sign_options):
+ """Test global image signature with the given hash algorithm and padding.
+
+ Args:
+ sha_algo: Either 'sha1' or 'sha256', to select the algorithm to use
+ padding: Either '' or '-pss', to select the padding to use for the
+ rsa signature algorithm.
+ """
+
+ dtb = '%ssandbox-u-boot-global%s.dtb' % (tmpdir, padding)
+ cons.config.dtb = dtb
+
+ # Compile our device tree files for kernel and U-Boot. These are
+ # regenerated here since mkimage will modify them (by adding a
+ # public key) below.
+ dtc('sandbox-kernel.dts')
+ dtc_options('sandbox-u-boot-global%s.dts' % padding, '-p 1024')
+
+ # Build the FIT with dev key (keys NOT required). This adds the
+ # signature into sandbox-u-boot.dtb, NOT marked 'required'.
+ make_fit('simple-images.its')
+ sign_fit_dtb(sha_algo, '', dtb)
+
+ # Build the dtb for binman that define the pre-load header
+ # with the global sigature.
+ dtc('sandbox-binman%s.dts' % padding)
+
+ # Run binman to create the final image with the not signed fit
+ # and the pre-load header that contains the global signature.
+ run_binman('sandbox-binman%s.dtb' % padding)
+
+ # Check that the signature is correctly verified by u-boot
+ run_bootm(sha_algo, 'global image signature', 'signature check has succeed', True, "%ssandbox.img" % tmpdir)
+
+ # Corrupt the image (just one byte after the pre-load header)
+ corrupt_file("%ssandbox.img" % tmpdir, 4096, 255);
+
+ # Check that the signature verification fails
+ run_bootm(sha_algo, 'global image signature', 'signature check has failed', False, "%ssandbox.img" % tmpdir)
+
+ # Check that the boot fails if the global signature is not provided
+ run_bootm(sha_algo, 'global image signature', 'signature is mandatory', False)
+
cons = u_boot_console
tmpdir = os.path.join(cons.config.result_dir, name) + '/'
if not os.path.exists(tmpdir):
@@ -372,6 +462,7 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required,
datadir = cons.config.source_dir + '/test/py/tests/vboot/'
fit = '%stest.fit' % tmpdir
mkimage = cons.config.build_dir + '/tools/mkimage'
+ binman = cons.config.source_dir + '/tools/binman/binman'
fit_check_sign = cons.config.build_dir + '/tools/fit_check_sign'
dtc_args = '-I dts -O dtb -i %s' % tmpdir
dtb = '%ssandbox-u-boot.dtb' % tmpdir
@@ -394,7 +485,9 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required,
# afterwards.
old_dtb = cons.config.dtb
cons.config.dtb = dtb
- if required:
+ if global_sign:
+ test_global_sign(sha_algo, padding, sign_options)
+ elif required:
test_required_key(sha_algo, padding, sign_options)
else:
test_with_algo(sha_algo, padding, sign_options)
diff --git a/test/py/tests/vboot/sandbox-binman-pss.dts b/test/py/tests/vboot/sandbox-binman-pss.dts
new file mode 100644
index 0000000000..54f82f1df5
--- /dev/null
+++ b/test/py/tests/vboot/sandbox-binman-pss.dts
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ filename = "sandbox.img";
+
+ pre-load {
+ image = "test.fit";
+ algo-name = "sha256,rsa2048";
+ padding-name = "pss";
+ key-name = "dev.key";
+ header-size = <4096>;
+ version = <1>;
+ };
+
+ blob-ext {
+ filename = "test.fit";
+ };
+ };
+};
diff --git a/test/py/tests/vboot/sandbox-binman.dts b/test/py/tests/vboot/sandbox-binman.dts
new file mode 100644
index 0000000000..56d835a938
--- /dev/null
+++ b/test/py/tests/vboot/sandbox-binman.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ filename = "sandbox.img";
+
+ pre-load {
+ image = "test.fit";
+ algo-name = "sha256,rsa2048";
+ key-name = "dev.key";
+ header-size = <4096>;
+ version = <1>;
+ };
+
+ blob-ext {
+ filename = "test.fit";
+ };
+ };
+};
diff --git a/test/py/tests/vboot/sandbox-u-boot-global-pss.dts b/test/py/tests/vboot/sandbox-u-boot-global-pss.dts
new file mode 100644
index 0000000000..4c5404842f
--- /dev/null
+++ b/test/py/tests/vboot/sandbox-u-boot-global-pss.dts
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ model = "Sandbox Verified Boot Test";
+ compatible = "sandbox";
+
+ reset at 0 {
+ compatible = "sandbox,reset";
+ };
+
+ image {
+ pre-load {
+ sig {
+ algo-name = "sha256,rsa2048";
+ padding-name = "pss";
+ signature-size = <256>;
+ mandatory = "yes";
+
+ key-name = "dev";
+ };
+ };
+ };
+};
diff --git a/test/py/tests/vboot/sandbox-u-boot-global.dts b/test/py/tests/vboot/sandbox-u-boot-global.dts
new file mode 100644
index 0000000000..fe9a99f963
--- /dev/null
+++ b/test/py/tests/vboot/sandbox-u-boot-global.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ model = "Sandbox Verified Boot Test";
+ compatible = "sandbox";
+
+ reset at 0 {
+ compatible = "sandbox,reset";
+ };
+
+ image {
+ pre-load {
+ sig {
+ algo-name = "sha256,rsa2048";
+ signature-size = <256>;
+ mandatory = "yes";
+
+ key-name = "dev";
+ };
+ };
+ };
+};
diff --git a/test/py/tests/vboot/simple-images.its b/test/py/tests/vboot/simple-images.its
new file mode 100644
index 0000000000..f62786456b
--- /dev/null
+++ b/test/py/tests/vboot/simple-images.its
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ description = "Chrome OS kernel image with one or more FDT blobs";
+ #address-cells = <1>;
+
+ images {
+ kernel {
+ data = /incbin/("test-kernel.bin");
+ type = "kernel_noload";
+ arch = "sandbox";
+ os = "linux";
+ compression = "none";
+ load = <0x4>;
+ entry = <0x8>;
+ kernel-version = <1>;
+ };
+ fdt-1 {
+ description = "snow";
+ data = /incbin/("sandbox-kernel.dtb");
+ type = "flat_dt";
+ arch = "sandbox";
+ compression = "none";
+ fdt-version = <1>;
+ };
+ };
+ configurations {
+ default = "conf-1";
+ conf-1 {
+ kernel = "kernel";
+ fdt = "fdt-1";
+ };
+ };
+};
--
2.17.1
More information about the U-Boot
mailing list