From 607b97ac8d414cb57b1ca89925631d41bd7ac04c Mon Sep 17 00:00:00 2001 From: Sergio Correia Date: Fri, 8 Aug 2025 16:41:54 +0100 Subject: [PATCH 9/9] mb: support vendor_db as logged by newer shim versions - Updated example policy to properly handle different event structures for vendor_db validation: - KeySubsetMulti for EV_EFI_VARIABLE_DRIVER_CONFIG (has SignatureType field) - SignatureSetMember for EV_EFI_VARIABLE_AUTHORITY (direct signature format) - Added method to extract vendor_db from EV_EFI_VARIABLE_AUTHORITY events in reference state generation (keylime-policy create measured-boot and the legacy create_mb_refstate script) - Made vendor_db optional for backward compatibility This fixes attestation failures when vendor_db variables are present but missing from reference states or validated with incorrect test types. See: https://github.com/rhboot/shim/pull/728 Signed-off-by: Sergio Correia --- keylime/mba/elchecking/example.py | 45 +++++++++ keylime/policy/create_mb_policy.py | 30 ++++++ scripts/create_mb_refstate | 30 ++++++ test/test_create_mb_policy.py | 142 +++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+) diff --git a/keylime/mba/elchecking/example.py b/keylime/mba/elchecking/example.py index a3d918a..5a933ac 100644 --- a/keylime/mba/elchecking/example.py +++ b/keylime/mba/elchecking/example.py @@ -21,6 +21,7 @@ from . import policies, tests # kek - list of allowed KEK keys # db - list of allowed db keys # dbx - list of required dbx keys +# vendor_db - list of allowed vendor_db keys (optional, for newer shim versions) # mokdig - list of allowed digests of MoKList (PCR 14 EV_IPL) # mokxdig - list of allowed digests of MoKListX (PCR 14 EV_IPL) # kernels - list of allowed { @@ -121,6 +122,10 @@ class Example(policies.Policy): if req not in refstate: raise Exception(f"refstate lacks {req}") + # vendor_db is optional for backward compatibility + if "vendor_db" not in refstate: + refstate["vendor_db"] = [] + dispatcher = tests.Dispatcher(("PCRIndex", "EventType")) vd_driver_config = tests.VariableDispatch() vd_authority = tests.VariableDispatch() @@ -268,6 +273,34 @@ class Example(policies.Policy): "db", db_test, ) + # Support vendor_db as logged by newer shim versions + # See: https://github.com/rhboot/shim/pull/728 + if not has_secureboot and not refstate["vendor_db"]: + vendor_db_test = tests.OnceTest(tests.AcceptAll()) + else: + vendor_db_test = tests.OnceTest( + tests.Or( + tests.KeySubsetMulti( + ["a159c0a5-e494-a74a-87b5-ab155c2bf072", "2616c4c1-4c50-9240-aca9-41f936934328"], + sigs_strip0x(refstate["vendor_db"]), + ), + tests.KeySubsetMulti( + ["a5c059a1-94e4-4aa7-87b5-ab155c2bf072", "c1c41626-504c-4092-aca9-41f936934328"], + sigs_strip0x(refstate["vendor_db"]), + ), + ) + ) + + vd_driver_config.set( + "cbb219d7-3a3d-9645-a3bc-dad00e67656f", + "vendor_db", + vendor_db_test, + ) + vd_driver_config.set( + "d719b2cb-3d3a-4596-a3bc-dad00e67656f", + "vendor_db", + vendor_db_test, + ) if not has_secureboot and not refstate["dbx"]: dbx_test = tests.OnceTest(tests.AcceptAll()) @@ -295,6 +328,18 @@ class Example(policies.Policy): vd_db_test = tests.OnceTest(tests.AcceptAll()) vd_authority.set("cbb219d7-3a3d-9645-a3bc-dad00e67656f", "db", vd_db_test) vd_authority.set("d719b2cb-3d3a-4596-a3bc-dad00e67656f", "db", vd_db_test) + # Support vendor_db as logged by newer shim versions in EV_EFI_VARIABLE_AUTHORITY events + # See: https://github.com/rhboot/shim/pull/728 + # EV_EFI_VARIABLE_AUTHORITY events have different structure than EV_EFI_VARIABLE_DRIVER_CONFIG + # They contain direct signature data without SignatureType field + if not has_secureboot and not refstate["vendor_db"]: + vendor_db_authority_test = tests.OnceTest(tests.AcceptAll()) + else: + vendor_db_authority_test = tests.OnceTest( + tests.IterateTest(tests.SignatureSetMember(sigs_strip0x(refstate["vendor_db"]))) + ) + vd_authority.set("cbb219d7-3a3d-9645-a3bc-dad00e67656f", "vendor_db", vendor_db_authority_test) + vd_authority.set("d719b2cb-3d3a-4596-a3bc-dad00e67656f", "vendor_db", vendor_db_authority_test) # Accept all SbatLevels of the Shim, because we already checked the hash of the Shim itself. vd_sbat_level_test = tests.OnceTest(tests.AcceptAll()) vd_authority.set("50ab5d60-46e0-0043-abb6-3dd810dd8b23", "SbatLevel", vd_sbat_level_test) diff --git a/keylime/policy/create_mb_policy.py b/keylime/policy/create_mb_policy.py index 859e652..b2b48f7 100644 --- a/keylime/policy/create_mb_policy.py +++ b/keylime/policy/create_mb_policy.py @@ -93,6 +93,35 @@ def get_keys(events: List[Dict[str, Any]]) -> Dict[str, List[Any]]: return out +def get_vendor_db(events: List[Dict[str, Any]]) -> Dict[str, List[Any]]: + """Get vendor_db signatures from EV_EFI_VARIABLE_AUTHORITY events.""" + out: Dict[str, List[Any]] = {"vendor_db": []} + + for event in events: + if "EventType" not in event: + continue + if event["EventType"] != "EV_EFI_VARIABLE_AUTHORITY": + continue + if "Event" not in event or "UnicodeName" not in event["Event"]: + continue + + event_name = event["Event"]["UnicodeName"].lower() + if event_name == "vendor_db": + data = None + if "VariableData" in event["Event"]: + data = event["Event"]["VariableData"] + + if data is not None: + # VariableData for EV_EFI_VARIABLE_AUTHORITY is a list of signatures + for entry in data: + if "SignatureOwner" in entry and "SignatureData" in entry: + out["vendor_db"].append( + {"SignatureOwner": entry["SignatureOwner"], "SignatureData": f"0x{entry['SignatureData']}"} + ) + + return out + + def get_kernel(events: List[Dict[str, Any]], secure_boot: bool) -> Dict[str, List[Dict[str, Any]]]: """Extract digest for Shim, Grub, Linux Kernel and initrd.""" out = [] @@ -259,6 +288,7 @@ def create_mb_refstate(args: argparse.Namespace) -> Optional[Dict[str, object]]: } ], **get_keys(events), + **get_vendor_db(events), **get_mok(events), **get_kernel(events, has_secureboot), } diff --git a/scripts/create_mb_refstate b/scripts/create_mb_refstate index 23cafb9..c98e61d 100755 --- a/scripts/create_mb_refstate +++ b/scripts/create_mb_refstate @@ -78,6 +78,35 @@ def get_keys(events): return out +def get_vendor_db(events): + """Get vendor_db signatures from EV_EFI_VARIABLE_AUTHORITY events.""" + out = {"vendor_db": []} + + for event in events: + if "EventType" not in event: + continue + if event["EventType"] != "EV_EFI_VARIABLE_AUTHORITY": + continue + if "Event" not in event or "UnicodeName" not in event["Event"]: + continue + + event_name = event["Event"]["UnicodeName"].lower() + if event_name == "vendor_db": + data = None + if "VariableData" in event["Event"]: + data = event["Event"]["VariableData"] + + if data is not None: + # VariableData for EV_EFI_VARIABLE_AUTHORITY is a list of signatures + for entry in data: + if "SignatureOwner" in entry and "SignatureData" in entry: + out["vendor_db"].append( + {"SignatureOwner": entry["SignatureOwner"], "SignatureData": f"0x{entry['SignatureData']}"} + ) + + return out + + def get_kernel(events, secure_boot): """ Extract digest for Shim, Grub, Linux Kernel and initrd. @@ -197,6 +226,7 @@ def main(): } ], **get_keys(events), + **get_vendor_db(events), **get_mok(events), **get_kernel(events, has_secureboot), } diff --git a/test/test_create_mb_policy.py b/test/test_create_mb_policy.py index b00d8e7..cd32bda 100644 --- a/test/test_create_mb_policy.py +++ b/test/test_create_mb_policy.py @@ -364,6 +364,148 @@ class CreateMeasuredBootPolicy_Test(unittest.TestCase): for c in test_cases: self.assertDictEqual(create_mb_policy.get_mok(c["events"]), c["expected"]) + def test_get_vendor_db(self): + test_cases = [ + {"events": [], "expected": {"vendor_db": []}}, + # No EV_EFI_VARIABLE_AUTHORITY events. + { + "events": [ + { + "EventType": "EV_EFI_VARIABLE_DRIVER_CONFIG", + "Event": {"UnicodeName": "vendor_db", "VariableData": []}, + } + ], + "expected": {"vendor_db": []}, + }, + # Good vendor_db event with EV_EFI_VARIABLE_AUTHORITY. + { + "events": [ + { + "EventType": "EV_EFI_VARIABLE_AUTHORITY", + "Event": { + "UnicodeName": "vendor_db", + "VariableData": [ + { + "SignatureOwner": "0223eddb-9079-4388-af77-2d65b1c35d3b", + "SignatureData": "sig-data-1", + } + ], + }, + } + ], + "expected": { + "vendor_db": [ + {"SignatureOwner": "0223eddb-9079-4388-af77-2d65b1c35d3b", "SignatureData": "0xsig-data-1"} + ] + }, + }, + # Multiple vendor_db signatures. + { + "events": [ + { + "EventType": "EV_EFI_VARIABLE_AUTHORITY", + "Event": { + "UnicodeName": "vendor_db", + "VariableData": [ + { + "SignatureOwner": "0223eddb-9079-4388-af77-2d65b1c35d3b", + "SignatureData": "sig-data-1", + }, + { + "SignatureOwner": "77fa9abd-0359-4d32-bd60-28f4e78f784b", + "SignatureData": "sig-data-2", + }, + ], + }, + } + ], + "expected": { + "vendor_db": [ + {"SignatureOwner": "0223eddb-9079-4388-af77-2d65b1c35d3b", "SignatureData": "0xsig-data-1"}, + {"SignatureOwner": "77fa9abd-0359-4d32-bd60-28f4e78f784b", "SignatureData": "0xsig-data-2"}, + ] + }, + }, + # Missing EventType. + { + "events": [ + { + "Event": { + "UnicodeName": "vendor_db", + "VariableData": [ + { + "SignatureOwner": "0223eddb-9079-4388-af77-2d65b1c35d3b", + "SignatureData": "sig-data-1", + } + ], + } + } + ], + "expected": {"vendor_db": []}, + }, + # Wrong EventType. + { + "events": [ + { + "EventType": "EV_EFI_VARIABLE_DRIVER_CONFIG", + "Event": { + "UnicodeName": "vendor_db", + "VariableData": [ + { + "SignatureOwner": "0223eddb-9079-4388-af77-2d65b1c35d3b", + "SignatureData": "sig-data-1", + } + ], + }, + } + ], + "expected": {"vendor_db": []}, + }, + # Missing Event. + { + "events": [{"EventType": "EV_EFI_VARIABLE_AUTHORITY"}], + "expected": {"vendor_db": []}, + }, + # Missing UnicodeName. + { + "events": [ + { + "EventType": "EV_EFI_VARIABLE_AUTHORITY", + "Event": { + "VariableData": [ + { + "SignatureOwner": "0223eddb-9079-4388-af77-2d65b1c35d3b", + "SignatureData": "sig-data-1", + } + ] + }, + } + ], + "expected": {"vendor_db": []}, + }, + # Wrong UnicodeName. + { + "events": [ + { + "EventType": "EV_EFI_VARIABLE_AUTHORITY", + "Event": { + "UnicodeName": "db", + "VariableData": [ + { + "SignatureOwner": "0223eddb-9079-4388-af77-2d65b1c35d3b", + "SignatureData": "sig-data-1", + } + ], + }, + } + ], + "expected": {"vendor_db": []}, + }, + ] + + for c in test_cases: + self.assertDictEqual(create_mb_policy.get_vendor_db(c["events"]), c["expected"]) + def test_get_kernel(self): test_cases = [ {"events": [], "secureboot": False, "expected": {}}, -- 2.47.3