|
@@ -6,6 +6,7 @@ from oeqa.selftest.case import OESelftestTestCase
|
|
|
from oeqa.utils.commands import runCmd, bitbake, get_bb_var, runqemu
|
|
|
import os
|
|
|
import json
|
|
|
+import re
|
|
|
|
|
|
class FitImageTests(OESelftestTestCase):
|
|
|
|
|
@@ -85,3 +86,148 @@ FIT_DESC = "A model description"
|
|
|
self.assertTrue(field_index == len(its_field_check),
|
|
|
"Fields in Image Tree Source File %s did not match, error in finding %s"
|
|
|
% (fitimage_its_path, its_field_check[field_index]))
|
|
|
+
|
|
|
+
|
|
|
+ def test_sign_fit_image(self):
|
|
|
+ """
|
|
|
+ Summary: Check if FIT image and Image Tree Source (its) are created
|
|
|
+ and signed correctly.
|
|
|
+ Expected: 1) its and FIT image are built successfully
|
|
|
+ 2) Scanning the its file indicates signing is enabled
|
|
|
+ as requested by UBOOT_SIGN_ENABLE (using keys generated
|
|
|
+ via FIT_GENERATE_KEYS)
|
|
|
+ 3) Dumping the FIT image indicates signature values
|
|
|
+ are present (including for images as enabled via
|
|
|
+ FIT_SIGN_INDIVIDUAL)
|
|
|
+ 4) Examination of the do_assemble_fitimage runfile/logfile
|
|
|
+ indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN and
|
|
|
+ UBOOT_MKIMAGE_SIGN_ARGS are working as expected.
|
|
|
+ Product: oe-core
|
|
|
+ Author: Paul Eggleton <paul.eggleton@microsoft.com> based upon
|
|
|
+ work by Usama Arif <usama.arif@arm.com>
|
|
|
+ """
|
|
|
+ config = """
|
|
|
+# Enable creation of fitImage
|
|
|
+MACHINE = "beaglebone-yocto"
|
|
|
+KERNEL_IMAGETYPES += " fitImage "
|
|
|
+KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper "
|
|
|
+UBOOT_SIGN_ENABLE = "1"
|
|
|
+FIT_GENERATE_KEYS = "1"
|
|
|
+UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
|
|
|
+UBOOT_SIGN_KEYNAME = "oe-selftest"
|
|
|
+FIT_SIGN_INDIVIDUAL = "1"
|
|
|
+UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'"
|
|
|
+"""
|
|
|
+ self.write_config(config)
|
|
|
+
|
|
|
+ # fitImage is created as part of linux recipe
|
|
|
+ bitbake("virtual/kernel")
|
|
|
+
|
|
|
+ image_type = "core-image-minimal"
|
|
|
+ deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
|
|
|
+ machine = get_bb_var('MACHINE')
|
|
|
+ fitimage_its_path = os.path.join(deploy_dir_image,
|
|
|
+ "fitImage-its-%s" % (machine,))
|
|
|
+ fitimage_path = os.path.join(deploy_dir_image,
|
|
|
+ "fitImage-%s.bin" % (machine,))
|
|
|
+
|
|
|
+ self.assertTrue(os.path.exists(fitimage_its_path),
|
|
|
+ "%s image tree source doesn't exist" % (fitimage_its_path))
|
|
|
+ self.assertTrue(os.path.exists(fitimage_path),
|
|
|
+ "%s FIT image doesn't exist" % (fitimage_path))
|
|
|
+
|
|
|
+ req_itspaths = [
|
|
|
+ ['/', 'images', 'kernel@1'],
|
|
|
+ ['/', 'images', 'kernel@1', 'signature@1'],
|
|
|
+ ['/', 'images', 'fdt@am335x-boneblack.dtb'],
|
|
|
+ ['/', 'images', 'fdt@am335x-boneblack.dtb', 'signature@1'],
|
|
|
+ ['/', 'configurations', 'conf@am335x-boneblack.dtb'],
|
|
|
+ ['/', 'configurations', 'conf@am335x-boneblack.dtb', 'signature@1'],
|
|
|
+ ]
|
|
|
+
|
|
|
+ itspath = []
|
|
|
+ itspaths = []
|
|
|
+ linect = 0
|
|
|
+ sigs = {}
|
|
|
+ with open(fitimage_its_path) as its_file:
|
|
|
+ linect += 1
|
|
|
+ for line in its_file:
|
|
|
+ line = line.strip()
|
|
|
+ if line.endswith('};'):
|
|
|
+ itspath.pop()
|
|
|
+ elif line.endswith('{'):
|
|
|
+ itspath.append(line[:-1].strip())
|
|
|
+ itspaths.append(itspath[:])
|
|
|
+ elif itspath and itspath[-1] == 'signature@1':
|
|
|
+ itsdotpath = '.'.join(itspath)
|
|
|
+ if not itsdotpath in sigs:
|
|
|
+ sigs[itsdotpath] = {}
|
|
|
+ if not '=' in line or not line.endswith(';'):
|
|
|
+ self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line))
|
|
|
+ key, value = line.split('=', 1)
|
|
|
+ sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';')
|
|
|
+
|
|
|
+ for reqpath in req_itspaths:
|
|
|
+ if not reqpath in itspaths:
|
|
|
+ self.fail('Missing section in its file: %s' % reqpath)
|
|
|
+
|
|
|
+ reqsigvalues_image = {
|
|
|
+ 'algo': '"sha256,rsa2048"',
|
|
|
+ 'key-name-hint': '"oe-selftest"',
|
|
|
+ }
|
|
|
+ reqsigvalues_config = {
|
|
|
+ 'algo': '"sha256,rsa2048"',
|
|
|
+ 'key-name-hint': '"oe-selftest"',
|
|
|
+ 'sign-images': '"kernel", "fdt"',
|
|
|
+ }
|
|
|
+
|
|
|
+ for itspath, values in sigs.items():
|
|
|
+ if 'conf@' in itspath:
|
|
|
+ reqsigvalues = reqsigvalues_config
|
|
|
+ else:
|
|
|
+ reqsigvalues = reqsigvalues_image
|
|
|
+ for reqkey, reqvalue in reqsigvalues.items():
|
|
|
+ value = values.get(reqkey, None)
|
|
|
+ if value is None:
|
|
|
+ self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath))
|
|
|
+ self.assertEqual(value, reqvalue)
|
|
|
+
|
|
|
+ # Dump the image to see if it really got signed
|
|
|
+ bitbake("u-boot-tools-native -c addto_recipe_sysroot")
|
|
|
+ result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=')
|
|
|
+ recipe_sysroot_native = result.output.split('=')[1].strip('"')
|
|
|
+ dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage')
|
|
|
+ result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path))
|
|
|
+ in_signed = None
|
|
|
+ signed_sections = {}
|
|
|
+ for line in result.output.splitlines():
|
|
|
+ if line.startswith((' Configuration', ' Image')):
|
|
|
+ in_signed = re.search('\((.*)\)', line).groups()[0]
|
|
|
+ elif re.match('^ *', line) in (' ', ''):
|
|
|
+ in_signed = None
|
|
|
+ elif in_signed:
|
|
|
+ if not in_signed in signed_sections:
|
|
|
+ signed_sections[in_signed] = {}
|
|
|
+ key, value = line.split(':', 1)
|
|
|
+ signed_sections[in_signed][key.strip()] = value.strip()
|
|
|
+ self.assertIn('kernel@1', signed_sections)
|
|
|
+ self.assertIn('fdt@am335x-boneblack.dtb', signed_sections)
|
|
|
+ self.assertIn('conf@am335x-boneblack.dtb', signed_sections)
|
|
|
+ for signed_section, values in signed_sections.items():
|
|
|
+ value = values.get('Sign algo', None)
|
|
|
+ self.assertEqual(value, 'sha256,rsa2048:oe-selftest', 'Signature algorithm for %s not expected value' % signed_section)
|
|
|
+ value = values.get('Sign value', None)
|
|
|
+ self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section)
|
|
|
+
|
|
|
+ # Check for UBOOT_MKIMAGE_SIGN_ARGS
|
|
|
+ result = runCmd('bitbake -e virtual/kernel | grep ^T=')
|
|
|
+ tempdir = result.output.split('=', 1)[1].strip().strip('')
|
|
|
+ result = runCmd('grep "a smart comment" %s/run.do_assemble_fitimage' % tempdir, ignore_status=True)
|
|
|
+ self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN_ARGS value did not get used')
|
|
|
+
|
|
|
+ # Check for evidence of test-mkimage-wrapper class
|
|
|
+ result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True)
|
|
|
+ self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work')
|
|
|
+ result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True)
|
|
|
+ self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work')
|
|
|
+
|