xref: /rk3399_rockchip-uboot/test/py/tests/test_vboot.py (revision 04a4786c7c3907a8e0cf271c02a437858a3ea96d)
18729d582SSimon Glass# Copyright (c) 2013, Google Inc.
28729d582SSimon Glass#
38729d582SSimon Glass# SPDX-License-Identifier:	GPL-2.0+
48729d582SSimon Glass#
58729d582SSimon Glass# U-Boot Verified Boot Test
68729d582SSimon Glass
78729d582SSimon Glass"""
88729d582SSimon GlassThis tests verified boot in the following ways:
98729d582SSimon Glass
108729d582SSimon GlassFor image verification:
118729d582SSimon Glass- Create FIT (unsigned) with mkimage
128729d582SSimon Glass- Check that verification shows that no keys are verified
138729d582SSimon Glass- Sign image
148729d582SSimon Glass- Check that verification shows that a key is now verified
158729d582SSimon Glass
168729d582SSimon GlassFor configuration verification:
178729d582SSimon Glass- Corrupt signature and check for failure
188729d582SSimon Glass- Create FIT (with unsigned configuration) with mkimage
198729d582SSimon Glass- Check that image veriication works
208729d582SSimon Glass- Sign the FIT and mark the key as 'required' for verification
218729d582SSimon Glass- Check that image verification works
228729d582SSimon Glass- Corrupt the signature
238729d582SSimon Glass- Check that image verification no-longer works
248729d582SSimon Glass
258729d582SSimon GlassTests run with both SHA1 and SHA256 hashing.
268729d582SSimon Glass"""
278729d582SSimon Glass
288729d582SSimon Glassimport pytest
298729d582SSimon Glassimport sys
308729d582SSimon Glassimport u_boot_utils as util
318729d582SSimon Glass
32*04a4786cSMichal Simek@pytest.mark.boardspec('sandbox')
338729d582SSimon Glass@pytest.mark.buildconfigspec('fit_signature')
348729d582SSimon Glassdef test_vboot(u_boot_console):
358729d582SSimon Glass    """Test verified boot signing with mkimage and verification with 'bootm'.
368729d582SSimon Glass
378729d582SSimon Glass    This works using sandbox only as it needs to update the device tree used
388729d582SSimon Glass    by U-Boot to hold public keys from the signing process.
398729d582SSimon Glass
408729d582SSimon Glass    The SHA1 and SHA256 tests are combined into a single test since the
418729d582SSimon Glass    key-generation process is quite slow and we want to avoid doing it twice.
428729d582SSimon Glass    """
438729d582SSimon Glass    def dtc(dts):
448729d582SSimon Glass        """Run the device-tree compiler to compile a .dts file
458729d582SSimon Glass
468729d582SSimon Glass        The output file will be the same as the input file but with a .dtb
478729d582SSimon Glass        extension.
488729d582SSimon Glass
498729d582SSimon Glass        Args:
508729d582SSimon Glass            dts: Device tree file to compile.
518729d582SSimon Glass        """
528729d582SSimon Glass        dtb = dts.replace('.dts', '.dtb')
538729d582SSimon Glass        util.cmd(cons, 'dtc %s %s%s -O dtb '
548729d582SSimon Glass                       '-o %s%s' % (dtc_args, datadir, dts, tmpdir, dtb))
558729d582SSimon Glass
568729d582SSimon Glass    def run_bootm(test_type, expect_string):
578729d582SSimon Glass        """Run a 'bootm' command U-Boot.
588729d582SSimon Glass
598729d582SSimon Glass        This always starts a fresh U-Boot instance since the device tree may
608729d582SSimon Glass        contain a new public key.
618729d582SSimon Glass
628729d582SSimon Glass        Args:
638729d582SSimon Glass            test_type: A string identifying the test type
648729d582SSimon Glass            expect_string: A string which is expected in the output
658729d582SSimon Glass        """
668729d582SSimon Glass        cons.cleanup_spawn()
678729d582SSimon Glass        cons.ensure_spawned()
688729d582SSimon Glass        cons.log.action('%s: Test Verified Boot Run: %s' % (algo, test_type))
698729d582SSimon Glass        output = cons.run_command_list(
708729d582SSimon Glass            ['sb load hostfs - 100 %stest.fit' % tmpdir,
718729d582SSimon Glass             'fdt addr 100',
728729d582SSimon Glass             'bootm 100'])
738729d582SSimon Glass        assert(expect_string in output)
748729d582SSimon Glass
758729d582SSimon Glass    def make_fit(its):
768729d582SSimon Glass        """Make a new FIT from the .its source file
778729d582SSimon Glass
788729d582SSimon Glass        This runs 'mkimage -f' to create a new FIT.
798729d582SSimon Glass
808729d582SSimon Glass        Args:
818729d582SSimon Glass            its: Filename containing .its source
828729d582SSimon Glass        """
838729d582SSimon Glass        util.run_and_log(cons, [mkimage, '-D', dtc_args, '-f',
848729d582SSimon Glass                                '%s%s' % (datadir, its), fit])
858729d582SSimon Glass
868729d582SSimon Glass    def sign_fit():
878729d582SSimon Glass        """Sign the FIT
888729d582SSimon Glass
898729d582SSimon Glass        Signs the FIT and writes the signature into it. It also writes the
908729d582SSimon Glass        public key into the dtb.
918729d582SSimon Glass        """
928729d582SSimon Glass        cons.log.action('%s: Sign images' % algo)
938729d582SSimon Glass        util.run_and_log(cons, [mkimage, '-F', '-k', tmpdir, '-K', dtb,
948729d582SSimon Glass                                '-r', fit])
958729d582SSimon Glass
968729d582SSimon Glass    def test_with_algo(sha):
978729d582SSimon Glass        """Test verified boot with the given hash algorithm
988729d582SSimon Glass
998729d582SSimon Glass        This is the main part of the test code. The same procedure is followed
1008729d582SSimon Glass        for both hashing algorithms.
1018729d582SSimon Glass
1028729d582SSimon Glass        Args:
1038729d582SSimon Glass            sha: Either 'sha1' or 'sha256', to select the algorithm to use
1048729d582SSimon Glass        """
1058729d582SSimon Glass        global algo
1068729d582SSimon Glass
1078729d582SSimon Glass        algo = sha
1088729d582SSimon Glass
1098729d582SSimon Glass        # Compile our device tree files for kernel and U-Boot
1108729d582SSimon Glass        dtc('sandbox-kernel.dts')
1118729d582SSimon Glass        dtc('sandbox-u-boot.dts')
1128729d582SSimon Glass
1138729d582SSimon Glass        # Build the FIT, but don't sign anything yet
1148729d582SSimon Glass        cons.log.action('%s: Test FIT with signed images' % algo)
1158729d582SSimon Glass        make_fit('sign-images-%s.its' % algo)
1168729d582SSimon Glass        run_bootm('unsigned images', 'dev-')
1178729d582SSimon Glass
1188729d582SSimon Glass        # Sign images with our dev keys
1198729d582SSimon Glass        sign_fit()
1208729d582SSimon Glass        run_bootm('signed images', 'dev+')
1218729d582SSimon Glass
1228729d582SSimon Glass        # Create a fresh .dtb without the public keys
1238729d582SSimon Glass        dtc('sandbox-u-boot.dts')
1248729d582SSimon Glass
1258729d582SSimon Glass        cons.log.action('%s: Test FIT with signed configuration' % algo)
1268729d582SSimon Glass        make_fit('sign-configs-%s.its' % algo)
1278729d582SSimon Glass        run_bootm('unsigned config', '%s+ OK' % algo)
1288729d582SSimon Glass
1298729d582SSimon Glass        # Sign images with our dev keys
1308729d582SSimon Glass        sign_fit()
1318729d582SSimon Glass        run_bootm('signed config', 'dev+')
1328729d582SSimon Glass
1338729d582SSimon Glass        cons.log.action('%s: Check signed config on the host' % algo)
1348729d582SSimon Glass
1358729d582SSimon Glass        util.run_and_log(cons, [fit_check_sign, '-f', fit, '-k', tmpdir,
1368729d582SSimon Glass                                '-k', dtb])
1378729d582SSimon Glass
1388729d582SSimon Glass        # Increment the first byte of the signature, which should cause failure
1398729d582SSimon Glass        sig = util.cmd(cons, 'fdtget -t bx %s %s value' % (fit, sig_node))
1408729d582SSimon Glass        byte_list = sig.split()
1418729d582SSimon Glass        byte = int(byte_list[0], 16)
1428729d582SSimon Glass        byte_list = ['%x' % (byte + 1)] + byte_list[1:]
1438729d582SSimon Glass        sig = ' '.join(byte_list)
1448729d582SSimon Glass        util.cmd(cons, 'fdtput -t bx %s %s value %s' % (fit, sig_node, sig))
1458729d582SSimon Glass
1468729d582SSimon Glass        run_bootm('Signed config with bad hash', 'Bad Data Hash')
1478729d582SSimon Glass
1488729d582SSimon Glass        cons.log.action('%s: Check bad config on the host' % algo)
1498729d582SSimon Glass        util.run_and_log_expect_exception(cons, [fit_check_sign, '-f', fit,
1508729d582SSimon Glass                '-k', dtb], 1, 'Failed to verify required signature')
1518729d582SSimon Glass
1528729d582SSimon Glass    cons = u_boot_console
1538729d582SSimon Glass    tmpdir = cons.config.result_dir + '/'
1548729d582SSimon Glass    tmp = tmpdir + 'vboot.tmp'
155c9ba60c4SStephen Warren    datadir = cons.config.source_dir + '/test/py/tests/vboot/'
1568729d582SSimon Glass    fit = '%stest.fit' % tmpdir
1578729d582SSimon Glass    mkimage = cons.config.build_dir + '/tools/mkimage'
1588729d582SSimon Glass    fit_check_sign = cons.config.build_dir + '/tools/fit_check_sign'
1598729d582SSimon Glass    dtc_args = '-I dts -O dtb -i %s' % tmpdir
1608729d582SSimon Glass    dtb = '%ssandbox-u-boot.dtb' % tmpdir
1618729d582SSimon Glass    sig_node = '/configurations/conf@1/signature@1'
1628729d582SSimon Glass
1638729d582SSimon Glass    # Create an RSA key pair
1648729d582SSimon Glass    public_exponent = 65537
1658729d582SSimon Glass    util.cmd(cons, 'openssl genpkey -algorithm RSA -out %sdev.key '
1668729d582SSimon Glass                   '-pkeyopt rsa_keygen_bits:2048 '
1678729d582SSimon Glass                   '-pkeyopt rsa_keygen_pubexp:%d '
1688729d582SSimon Glass                   '2>/dev/null'  % (tmpdir, public_exponent))
1698729d582SSimon Glass
1708729d582SSimon Glass    # Create a certificate containing the public key
1718729d582SSimon Glass    util.cmd(cons, 'openssl req -batch -new -x509 -key %sdev.key -out '
1728729d582SSimon Glass                   '%sdev.crt' % (tmpdir, tmpdir))
1738729d582SSimon Glass
1748729d582SSimon Glass    # Create a number kernel image with zeroes
1758729d582SSimon Glass    with open('%stest-kernel.bin' % tmpdir, 'w') as fd:
1768729d582SSimon Glass        fd.write(5000 * chr(0))
1778729d582SSimon Glass
1788729d582SSimon Glass    try:
1798729d582SSimon Glass        # We need to use our own device tree file. Remember to restore it
1808729d582SSimon Glass        # afterwards.
1818729d582SSimon Glass        old_dtb = cons.config.dtb
1828729d582SSimon Glass        cons.config.dtb = dtb
1838729d582SSimon Glass        test_with_algo('sha1')
1848729d582SSimon Glass        test_with_algo('sha256')
1858729d582SSimon Glass    finally:
1868729d582SSimon Glass        cons.config.dtb = old_dtb
187