[PATCH v6 14/16] test: py: vboot: add test for global image signature

Simon Glass sjg at chromium.org
Thu Mar 3 04:37:09 CET 2022


Hi Philippe,

On Fri, 25 Feb 2022 at 07:58, Philippe Reynes
<philippe.reynes at softathome.com> wrote:
>
> 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                   | 125 +++++++++++++++---
>  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 |  28 ++++
>  test/py/tests/vboot/sandbox-u-boot-global.dts |  27 ++++
>  test/py/tests/vboot/simple-images.its         |  36 +++++
>  6 files changed, 249 insertions(+), 16 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 ac8ed9f114..a4a2bb2955 100644
> --- a/test/py/tests/test_vboot.py
> +++ b/test/py/tests/test_vboot.py
> @@ -35,19 +35,21 @@ import vboot_evil

please add to the comment at the top of the file since you have added a new way

>  # 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, 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],
> -    ['sha384-basic', 'sha384', '', None, False, False, False],
> -    ['sha384-pad', 'sha384', '', '-E -p 0x10000', False, False, False],
> -    ['algo-arg', 'algo-arg', '', '-o sha256,rsa2048', False, False, True],
> +    ['sha1-basic', 'sha1', '', None, False, True, False, False],
> +    ['sha1-pad', 'sha1', '', '-E -p 0x10000', False, False, False, False],
> +    ['sha1-pss', 'sha1', '-pss', None, False, False, False, False],
> +    ['sha1-pss-pad', 'sha1', '-pss', '-E -p 0x10000', False, False, False, False],
> +    ['sha256-basic', 'sha256', '', None, False, False, False, False],
> +    ['sha256-pad', 'sha256', '', '-E -p 0x10000', False, False, False, False],
> +    ['sha256-pss', 'sha256', '-pss', None, False, False, False, False],
> +    ['sha256-pss-pad', 'sha256', '-pss', '-E -p 0x10000', False, False, False, False],
> +    ['sha256-pss-required', 'sha256', '-pss', None, True, False, False, False],
> +    ['sha256-pss-pad-required', 'sha256', '-pss', '-E -p 0x10000', True, True, False, False],
> +    ['sha384-basic', 'sha384', '', None, False, False, False, False],
> +    ['sha384-pad', 'sha384', '', '-E -p 0x10000', False, False, False, False],
> +    ['algo-arg', 'algo-arg', '', '-o sha256,rsa2048', False, False, True, False],
> +    ['sha256-global-sign', 'sha256', '', '', False, False, False, True],
> +    ['sha256-global-sign-pss', 'sha256', '-pss', '', False, False, False, True],
>  ]
>
>  @pytest.mark.boardspec('sandbox')
> @@ -56,10 +58,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,algo_arg",
> + at pytest.mark.parametrize("name,sha_algo,padding,sign_options,required,full_test,algo_arg,global_sign",
>                           TESTDATA)
>  def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required,
> -               full_test, algo_arg):
> +               full_test, algo_arg, 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
> @@ -81,6 +83,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.
>
> @@ -139,6 +164,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
>
> @@ -176,6 +218,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):

spaces after ,

also please comment the function

> +        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
>
> @@ -374,6 +421,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)

make sure to wrap to 80 chars

> +
> +        # 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):
> @@ -381,6 +471,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
> @@ -403,7 +494,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)

do you not want to also test the normal signature?

> +        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..56e3a42fa6
> --- /dev/null

[..]

Regards,
Simon


More information about the U-Boot mailing list