Openembedded Core Discussions
 help / color / mirror / Atom feed
From: Jamin Lin <jamin_lin@aspeedtech.com>
To: <openembedded-core@lists.openembedded.org>
Cc: <troy_lee@aspeedtech.com>, <jamin_lin@aspeedtech.com>
Subject: [PATCH v4 3/3] oe-selftest: fitimage: add testcases to test ATF and TEE
Date: Mon, 18 Nov 2024 14:32:33 +0800	[thread overview]
Message-ID: <20241118063233.698679-4-jamin_lin@aspeedtech.com> (raw)
In-Reply-To: <20241118063233.698679-1-jamin_lin@aspeedtech.com>

Add "test_uboot_atf_tee_fit_image" test caste to check u-boot FIT image and
Image Tree Source(ITS) are built and the ITS has the correct fields.

Add "test_sign_standalone_uboot_atf_tee_fit_image" test case to check if u-boot
FIT image and Image Tree Source (ITS) are created and signed correctly for the
scenario where only the u-boot proper fitImage is being created and signed.

Currently, ATF and TEE(optee-os) recipes are placed in meta-arm layer.
OpenEmbedded-Core is a basic and core meta layer. To avoid OpenEmbedded-core
depends meta-arm, both test cases are used dummy images for testing.

Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 meta/lib/oeqa/selftest/cases/fitimage.py | 288 +++++++++++++++++++++++
 1 file changed, 288 insertions(+)

diff --git a/meta/lib/oeqa/selftest/cases/fitimage.py b/meta/lib/oeqa/selftest/cases/fitimage.py
index 0b5f4602fb..fc9d224f50 100644
--- a/meta/lib/oeqa/selftest/cases/fitimage.py
+++ b/meta/lib/oeqa/selftest/cases/fitimage.py
@@ -852,3 +852,291 @@ FIT_HASH_ALG = "sha256"
         # Verify the signature
         uboot_tools_sysroot_native = self._setup_uboot_tools_native()
         self._verify_fit_image_signature(uboot_tools_sysroot_native, fitimage_path, os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], 'am335x-bone.dtb'))
+
+
+    def test_uboot_atf_tee_fit_image(self):
+        """
+        Summary:     Check if U-boot FIT image and Image Tree Source
+                     (its) are built and the Image Tree Source has the
+                     correct fields.
+        Expected:    1. Create atf and tee dummy images
+                     2. Both u-boot-fitImage and u-boot-its can be built
+                     3. The os, load address, entrypoint address and
+                        default values of U-boot, ATF and TEE images are
+                        correct in the Image Tree Source. Not all the
+                        fields are tested, only the key fields that wont
+                        vary between different architectures.
+                Product:     oe-core
+                Author:      Jamin Lin <jamin_lin@aspeedtech.com>
+        """
+        config = """
+# We need at least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set
+MACHINE = "qemuarm"
+UBOOT_MACHINE = "am57xx_evm_defconfig"
+SPL_BINARY = "MLO"
+
+# Enable creation of the U-Boot fitImage
+UBOOT_FITIMAGE_ENABLE = "1"
+
+# (U-boot) fitImage properties
+UBOOT_LOADADDRESS = "0x80080000"
+UBOOT_ENTRYPOINT = "0x80080000"
+UBOOT_FIT_DESC = "A model description"
+
+# Enable creation of the TEE fitImage
+UBOOT_FIT_TEE = "1"
+
+# TEE fitImage properties
+UBOOT_FIT_TEE_IMAGE = "${TOPDIR}/tee-dummy.bin"
+UBOOT_FIT_TEE_LOADADDRESS = "0x80180000"
+UBOOT_FIT_TEE_ENTRYPOINT = "0x80180000"
+
+# Enable creation of the ATF fitImage
+UBOOT_FIT_ARM_TRUSTED_FIRMWARE = "1"
+
+# ATF fitImage properties
+UBOOT_FIT_ARM_TRUSTED_FIRMWARE_IMAGE = "${TOPDIR}/atf-dummy.bin"
+UBOOT_FIT_ARM_TRUSTED_FIRMWARE_LOADADDRESS = "0x80280000"
+UBOOT_FIT_ARM_TRUSTED_FIRMWARE_ENTRYPOINT = "0x80280000"
+"""
+        self.write_config(config)
+
+        # Create an ATF dummy image
+        atf_dummy_image = os.path.join(self.builddir, "atf-dummy.bin")
+        cmd = 'dd if=/dev/random of=%s bs=1k count=64' % (atf_dummy_image)
+        result = runCmd(cmd)
+        self.logger.debug("%s\nreturned: %s\n%s", cmd, str(result.status), result.output)
+
+        # Create a TEE dummy image
+        tee_dummy_image = os.path.join(self.builddir, "tee-dummy.bin")
+        cmd = 'dd if=/dev/random of=%s bs=1k count=64' % (tee_dummy_image)
+        result = runCmd(cmd)
+        self.logger.debug("%s\nreturned: %s\n%s", cmd, str(result.status), result.output)
+
+        # The U-Boot fitImage is created as part of the U-Boot recipe
+        bitbake("virtual/bootloader")
+
+        deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+        machine = get_bb_var('MACHINE')
+        fitimage_its_path = os.path.join(deploy_dir_image,
+            "u-boot-its-%s" % (machine,))
+        fitimage_path = os.path.join(deploy_dir_image,
+            "u-boot-fitImage-%s" % (machine,))
+
+        self.assertExists(fitimage_its_path, "%s image tree source doesn't exist" % (fitimage_its_path))
+        self.assertExists(fitimage_path, "%s FIT image doesn't exist" % (fitimage_path))
+
+        # Check that the os, load address, entrypoint address and default
+        # values for u-boot, ATF and TEE in Image Tree Source are as expected.
+        # The order of fields in the below array is important. Not all the
+        # fields are tested, only the key fields that wont vary between
+        # different architectures.
+        its_field_check = [
+            'description = "A model description";',
+            'os = "u-boot";',
+            'load = <0x80080000>;',
+            'entry = <0x80080000>;',
+            'description = "Trusted Execution Environment";',
+            'os = "tee";',
+            'load = <0x80180000>;',
+            'entry = <0x80180000>;',
+            'description = "ARM Trusted Firmware";',
+            'os = "arm-trusted-firmware";',
+            'load = <0x80280000>;',
+            'entry = <0x80280000>;',
+            'default = "conf";',
+            'loadables = "atf", "tee", "uboot";',
+            'fdt = "fdt";'
+        ]
+
+        with open(fitimage_its_path) as its_file:
+            field_index = 0
+            for line in its_file:
+                if field_index == len(its_field_check):
+                    break
+                if its_field_check[field_index] in line:
+                    field_index +=1
+
+        if field_index != len(its_field_check): # if its equal, the test passed
+            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_standalone_uboot_atf_tee_fit_image(self):
+        """
+        Summary:     Check if U-Boot FIT image and Image Tree Source (its) are
+                     created and signed correctly for the scenario where only
+                     the U-Boot proper fitImage is being created and signed.
+        Expected:    1. Create atf and tee dummy images
+                     2. U-Boot its and FIT image are built successfully
+                     3. Scanning the its file indicates signing is enabled
+                        as requested by SPL_SIGN_ENABLE (using keys generated
+                        via UBOOT_FIT_GENERATE_KEYS)
+                     4. Dumping the FIT image indicates signature values
+                        are present
+                     5. Examination of the do_uboot_assemble_fitimage
+                     runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN
+                     and SPL_MKIMAGE_SIGN_ARGS are working as expected.
+                Product:     oe-core
+                Author:      Jamin Lin <jamin_lin@aspeedtech.com>
+        """
+        a_comment = "a smart cascaded U-Boot ATF TEE comment"
+        config = """
+# There's no U-boot deconfig with CONFIG_FIT_SIGNATURE yet, so we need at
+# least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set
+MACHINE = "qemuarm"
+UBOOT_MACHINE = "am57xx_evm_defconfig"
+SPL_BINARY = "MLO"
+
+# The kernel-fitimage class is a dependency even if we're only
+# creating/signing the U-Boot fitImage
+KERNEL_CLASSES = " kernel-fitimage"
+
+# Enable creation and signing of the U-Boot fitImage
+UBOOT_FITIMAGE_ENABLE = "1"
+SPL_SIGN_ENABLE = "1"
+SPL_SIGN_KEYNAME = "spl-oe-selftest"
+SPL_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
+UBOOT_DTB_BINARY = "u-boot.dtb"
+UBOOT_ARCH = "arm"
+SPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000"
+SPL_MKIMAGE_SIGN_ARGS = "-c '%s'"
+UBOOT_EXTLINUX = "0"
+UBOOT_FIT_GENERATE_KEYS = "1"
+UBOOT_FIT_HASH_ALG = "sha256"
+
+# (U-boot) fitImage properties
+UBOOT_LOADADDRESS = "0x80080000"
+UBOOT_ENTRYPOINT = "0x80080000"
+UBOOT_FIT_DESC = "A model description"
+
+# Enable creation of the TEE fitImage
+UBOOT_FIT_TEE = "1"
+
+# TEE fitImage properties
+UBOOT_FIT_TEE_IMAGE = "${TOPDIR}/tee-dummy.bin"
+UBOOT_FIT_TEE_LOADADDRESS = "0x80180000"
+UBOOT_FIT_TEE_ENTRYPOINT = "0x80180000"
+
+# Enable creation of the ATF fitImage
+UBOOT_FIT_ARM_TRUSTED_FIRMWARE = "1"
+
+# ATF fitImage properties
+UBOOT_FIT_ARM_TRUSTED_FIRMWARE_IMAGE = "${TOPDIR}/atf-dummy.bin"
+UBOOT_FIT_ARM_TRUSTED_FIRMWARE_LOADADDRESS = "0x80280000"
+UBOOT_FIT_ARM_TRUSTED_FIRMWARE_ENTRYPOINT = "0x80280000"
+""" % a_comment
+
+        self.write_config(config)
+
+        # Create an ATF dummy image
+        atf_dummy_image = os.path.join(self.builddir, "atf-dummy.bin")
+        cmd = 'dd if=/dev/random of=%s bs=1k count=64' % (atf_dummy_image)
+        result = runCmd(cmd)
+        self.logger.debug("%s\nreturned: %s\n%s", cmd, str(result.status), result.output)
+
+        # Create a TEE dummy image
+        tee_dummy_image = os.path.join(self.builddir, "tee-dummy.bin")
+        cmd = 'dd if=/dev/random of=%s bs=1k count=64' % (tee_dummy_image)
+        result = runCmd(cmd)
+        self.logger.debug("%s\nreturned: %s\n%s", cmd, str(result.status), result.output)
+
+        # The U-Boot fitImage is created as part of the U-Boot recipe
+        bitbake("virtual/bootloader")
+
+        deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+        machine = get_bb_var('MACHINE')
+        fitimage_its_path = os.path.join(deploy_dir_image,
+            "u-boot-its-%s" % (machine,))
+        fitimage_path = os.path.join(deploy_dir_image,
+            "u-boot-fitImage-%s" % (machine,))
+
+        self.assertExists(fitimage_its_path, "%s image tree source doesn't exist" % (fitimage_its_path))
+        self.assertExists(fitimage_path, "%s FIT image doesn't exist" % (fitimage_path))
+
+        req_itspaths = [
+            ['/', 'images', 'uboot'],
+            ['/', 'images', 'uboot', 'signature'],
+            ['/', 'images', 'fdt'],
+            ['/', 'images', 'fdt', 'signature'],
+            ['/', 'images', 'tee'],
+            ['/', 'images', 'tee', 'signature'],
+            ['/', 'images', 'atf'],
+            ['/', 'images', 'atf', 'signature'],
+        ]
+
+        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':
+                    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': '"spl-oe-selftest"',
+        }
+
+        for itspath, values in sigs.items():
+            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
+        uboot_tools_sysroot_native = self._setup_uboot_tools_native()
+        dumpimage_path = os.path.join(uboot_tools_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((' Image')):
+                in_signed = re.search(r'\((.*)\)', line).groups()[0]
+            elif re.match(' \w', line):
+                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('uboot', signed_sections)
+        self.assertIn('fdt', signed_sections)
+        self.assertIn('tee', signed_sections)
+        self.assertIn('atf', signed_sections)
+        for signed_section, values in signed_sections.items():
+            value = values.get('Sign algo', None)
+            self.assertEqual(value, 'sha256,rsa2048:spl-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 SPL_MKIMAGE_SIGN_ARGS
+        # Looks like mkimage supports to add a comment but does not support to read it back.
+        found_comments = FitImageTests._find_string_in_bin_file(fitimage_path, a_comment)
+        self.assertEqual(found_comments, 4, "Expected 4 signed and commented section in the fitImage.")
+
+        # Verify the signature
+        self._verify_fit_image_signature(uboot_tools_sysroot_native, fitimage_path,
+                                         os.path.join(deploy_dir_image, 'u-boot-spl.dtb'))
+
-- 
2.25.1



  parent reply	other threads:[~2024-11-18  6:32 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-11-18  6:32 [PATCH v4 0/3] uboot-sign: support ATF and TFE ITS generation Jamin Lin
2024-11-18  6:32 ` [PATCH v4 1/3] uboot-sign: support to create TEE and ATF image tree source Jamin Lin
2024-11-18  6:32 ` [PATCH v4 2/3] uboot-sign: support to create users specific " Jamin Lin
2024-11-18  6:32 ` Jamin Lin [this message]
2024-11-28 13:51 ` [OE-core] [PATCH v4 0/3] uboot-sign: support ATF and TFE ITS generation Ross Burton
2024-12-02  5:39   ` Jamin Lin
2024-12-02 17:36     ` Ross Burton
2024-12-05 23:51   ` Adrian Freihofer
2024-12-06  1:12     ` Jamin Lin
     [not found]     ` <180E7161025130F9.8554@lists.openembedded.org>
2024-12-10  8:07       ` Jamin Lin
2024-12-11  2:46         ` Jamin Lin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20241118063233.698679-4-jamin_lin@aspeedtech.com \
    --to=jamin_lin@aspeedtech.com \
    --cc=openembedded-core@lists.openembedded.org \
    --cc=troy_lee@aspeedtech.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox