[PATCH v2 4/6] binman: capsule: Use dumped capsule header contents for verification

Sughosh Ganu sughosh.ganu at linaro.org
Tue Oct 10 11:10:57 CEST 2023


The various fields of a generated capsule are currently verified
through hard-coded offsets. Use the dump-capsule feature for dumping
the capsule header contents and use those for capsule verification.

Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org>
---
Changes since V1:
* Move the get_binman_test_guid() function outside the
  Entry_efi_capsule class so that it can be called from outside the
  module.
* Use lowercase characters in the GUID values
* Add comments for the _GetCapsuleHeaders() function.
* Use a simple dict in _GetCapsuleHeaders() for storing the capsule
  header values dumped by the mkeficapsule tool.

 tools/binman/etype/efi_capsule.py |  24 +++++--
 tools/binman/ftest.py             | 105 ++++++++++++++++++------------
 2 files changed, 82 insertions(+), 47 deletions(-)

diff --git a/tools/binman/etype/efi_capsule.py b/tools/binman/etype/efi_capsule.py
index 006eb630ad..e320371782 100644
--- a/tools/binman/etype/efi_capsule.py
+++ b/tools/binman/etype/efi_capsule.py
@@ -11,6 +11,24 @@ from binman.etype.section import Entry_section
 from dtoc import fdt_util
 from u_boot_pylib import tools
 
+def get_binman_test_guid(type_str):
+    """Get the test image GUID for binman
+
+    Based on the string passed to the function, return
+    the corresponding GUID.
+
+    Args:
+        type_str: Key value of the type of GUID to look for
+
+    Returns:
+        The actual GUID value (str)
+    """
+    TYPE_TO_GUID = {
+        'binman-test' : '09d7cf52-0720-4710-91d1-08469b7fe9c8'
+    }
+
+    return TYPE_TO_GUID[type_str]
+
 class Entry_efi_capsule(Entry_section):
     """Generate EFI capsules
 
@@ -104,12 +122,6 @@ class Entry_efi_capsule(Entry_section):
             self.auth = 1
 
     def BuildSectionData(self, required):
-        def get_binman_test_guid(type_str):
-            TYPE_TO_GUID = {
-                'binman-test' : '09d7cf52-0720-4710-91d1-08469b7fe9c8'
-            }
-            return TYPE_TO_GUID[type_str]
-
         private_key = ''
         public_key_cert = ''
         if self.auth:
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 8e419645a6..2ea18d2d08 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -121,9 +121,11 @@ COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
 TEE_ADDR = 0x5678
 
 # Firmware Management Protocol(FMP) GUID
-FW_MGMT_GUID = 'edd5cb6d2de8444cbda17194199ad92a'
+FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
 # Image GUID specified in the DTS
-CAPSULE_IMAGE_GUID = '52cfd7092007104791d108469b7fe9c8'
+CAPSULE_IMAGE_GUID = '09d7cf52-0720-4710-91d1-08469b7fe9c8'
+# Windows cert GUID
+WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
 
 class TestFunctional(unittest.TestCase):
     """Functional tests for binman
@@ -7223,52 +7225,73 @@ fdt         fdtmap                Extract the devicetree blob from the fdtmap
         self.assertRegex(err,
                          "Image 'image'.*missing bintools.*: bootgen")
 
+    def _GetCapsuleHeaders(self, data):
+        """Get the capsule header contents
+
+        Args:
+            data: Capsule file contents
+
+        Returns:
+            Dict:
+                key: Capsule Header name (str)
+                value: Header field value (str)
+        """
+        capsule_file = os.path.join(self._indir, 'test.capsule')
+        tools.write_file(capsule_file, data)
+
+        out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
+        lines = out.splitlines()
+
+        re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
+        vals = {}
+        for line in lines:
+            mat = re_line.match(line)
+            if mat:
+                vals[mat.group(1)] = mat.group(2)
+
+        return vals
+
     def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
                       capoemflags=False):
-        fmp_signature = "4d535331" # 'M', 'S', 'S', '1'
-        fmp_size = "10"
-        fmp_fw_version = "02"
-        oemflag = "0080"
+        fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
+        fmp_size = "00000010"
+        fmp_fw_version = "00000002"
+        capsule_image_index = "00000001"
+        oemflag = "00018000"
+        auth_hdr_revision = "00000200"
+        auth_hdr_cert_type = "00000EF1"
+
+        payload_data_len = len(EFI_CAPSULE_DATA)
 
-        payload_data = EFI_CAPSULE_DATA
+        hdr = self._GetCapsuleHeaders(data)
 
-        # TODO - Currently, these offsets for capsule fields are hardcoded.
-        # There are plans to add support to the mkeficapsule tool to dump
-        # the capsule contents which can then be used for capsule
-        # verification.
+        self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
 
-        # Firmware Management Protocol(FMP) GUID - offset(0 - 32)
-        self.assertEqual(FW_MGMT_GUID, data.hex()[:32])
-        # Image GUID - offset(96 - 128)
-        self.assertEqual(CAPSULE_IMAGE_GUID, data.hex()[96:128])
+        self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
+                         hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
+        self.assertEqual(capsule_image_index,
+                         hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
 
         if capoemflags:
-            # OEM Flags - offset(40 - 44)
-            self.assertEqual(oemflag, data.hex()[40:44])
-        if signed_capsule and version_check:
-            # FMP header signature - offset(4770 - 4778)
-            self.assertEqual(fmp_signature, data.hex()[4770:4778])
-            # FMP header size - offset(4778 - 4780)
-            self.assertEqual(fmp_size, data.hex()[4778:4780])
-            # firmware version - offset(4786 - 4788)
-            self.assertEqual(fmp_fw_version, data.hex()[4786:4788])
-            # payload offset signed capsule(4802 - 4808)
-            self.assertEqual(payload_data.hex(), data.hex()[4802:4808])
-        elif signed_capsule:
-            # payload offset signed capsule(4770 - 4776)
-            self.assertEqual(payload_data.hex(), data.hex()[4770:4776])
-        elif version_check:
-            # FMP header signature - offset(184 - 192)
-            self.assertEqual(fmp_signature, data.hex()[184:192])
-            # FMP header size - offset(192 - 194)
-            self.assertEqual(fmp_size, data.hex()[192:194])
-            # firmware version - offset(200 - 202)
-            self.assertEqual(fmp_fw_version, data.hex()[200:202])
-            # payload offset for non-signed capsule with version header(216 - 222)
-            self.assertEqual(payload_data.hex(), data.hex()[216:222])
-        else:
-            # payload offset for non-signed capsule with no version header(184 - 190)
-            self.assertEqual(payload_data.hex(), data.hex()[184:190])
+            self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
+
+        if signed_capsule:
+            self.assertEqual(auth_hdr_revision,
+                             hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
+            self.assertEqual(auth_hdr_cert_type,
+                             hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
+            self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
+                             hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
+
+        if version_check:
+            self.assertEqual(fmp_signature,
+                             hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
+            self.assertEqual(fmp_size,
+                             hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
+            self.assertEqual(fmp_fw_version,
+                             hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
+
+        self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
 
     def testCapsuleGen(self):
         """Test generation of EFI capsule"""
-- 
2.34.1



More information about the U-Boot mailing list