in tools/manifest_tools/manifest_parser.py [0:0]
def process_cfm (root, xml_file, selection_list):
"""
Process CFM XML and generate list of element and attribute values.
:param root: XML to utilize
:param xml_file: Filename of XML
:param selection_list: List of component types to include
:return List of CFM values, manifest version, boolean for whether manifest is for an empty CFM
"""
xml = {}
component_type = xml_extract_attrib (root, XML_TYPE_ATTRIB, True, xml_file)
component_type = component_type.strip ('\"')
if component_type not in selection_list:
return None, manifest_types.VERSION_2, False
xml[component_type] = {}
component = xml[component_type]
component["unique"] = -1
for element in root:
if element.tag == "Measurement":
component["unique"] = 0
break
if element.tag == "MeasurementData":
component["unique"] = 1
break
result = xml_extract_attrib (root, XML_ATTESTATION_PROTOCOL_ATTRIB, True, xml_file)
if result.lower () == "cerberus":
component["attestation_protocol"] = 0
elif result.lower () == "spdm":
component["attestation_protocol"] = 1
else:
raise ValueError ("Component {0} has unknown attestation protocol '{1}' in {2}".format (
component_type, result, xml_file))
component["slot_num"] = int (xml_extract_attrib (root, XML_SLOT_NUM_ATTRIB, False, xml_file))
result = xml_extract_attrib (root, XML_TRANSCRIPT_HASH_TYPE_ATTRIB, True, xml_file)
if result == "SHA256":
component["transcript_hash_type"] = 0
elif result == "SHA384":
component["transcript_hash_type"] = 1
elif result == "SHA512":
component["transcript_hash_type"] = 2
else:
raise ValueError ("Component {0} has unknown transcript hash type '{1}' in {2}".format (
component_type, result, xml_file))
result = xml_extract_attrib (root, XML_MEASUREMENT_HASH_TYPE_ATTRIB, True, xml_file)
if result == "SHA256":
component["measurement_hash_type"] = 0
elif result == "SHA384":
component["measurement_hash_type"] = 1
elif result == "SHA512":
component["measurement_hash_type"] = 2
else:
raise ValueError ("Component {0} has unknown measurement hash type '{1}' in {2}".format (
component_type, result, xml_file))
for root_ca_digests in root.findall (XML_ROOT_CA_DIGEST_TAG):
if "root_ca_digests" in component:
raise ValueError ("Component {0} has multiple root CA digest entries in {1}".format (
component_type, xml_file))
component["root_ca_digests"] = {}
component["root_ca_digests"]["allowable_digests"] = []
for allowable_digest in root_ca_digests.findall (XML_DIGEST_TAG):
component["root_ca_digests"]["allowable_digests"].append (
binascii.a2b_hex (re.sub ("\s", "", allowable_digest.text.strip ())))
for pmr in root.findall (XML_PMR_TAG):
if "pmr" not in component:
component["pmr"] = {}
pmr_id = int (xml_extract_attrib (pmr, XML_PMR_ID_ATTRIB, False, xml_file))
if pmr_id in component["pmr"]:
raise ValueError (
"Too many PMR elements for PMR ID {0} for component {1} in manifest {2}".format (
pmr_id, component_type, xml_file))
component["pmr"][pmr_id] = xml_extract_single_value (pmr,
{"initial_value": XML_INITIAL_VALUE_TAG}, xml_file)
component["pmr"][pmr_id]["initial_value"] = binascii.a2b_hex (
re.sub ("\s", "", component["pmr"][pmr_id]["initial_value"]))
for pmr_digest in root.findall (XML_PMR_DIGEST_TAG):
if "pmr_digests" not in component:
component["pmr_digests"] = {}
pmr_id = int (xml_extract_attrib (pmr_digest, XML_PMR_ID_ATTRIB, False, xml_file))
if pmr_id in component["pmr_digests"]:
raise ValueError (
"Too many rules for PMR ID {0} digests for component {1} in manifest {2}".format (
pmr_id, component_type, xml_file))
component["pmr_digests"][pmr_id] = {}
component["pmr_digests"][pmr_id]["allowable_digests"] = []
for allowable_digest in pmr_digest.findall (XML_DIGEST_TAG):
component["pmr_digests"][pmr_id]["allowable_digests"].append (
binascii.a2b_hex (re.sub ("\s", "", allowable_digest.text.strip ())))
for measurement in root.findall (XML_MEASUREMENT_TAG):
if "measurements" not in component:
component["measurements"] = {}
pmr_id = int (xml_extract_attrib (measurement, XML_PMR_ID_ATTRIB, False, xml_file))
measurement_id = int (xml_extract_attrib (measurement, XML_MEASUREMENT_ID_ATTRIB, False,
xml_file))
if pmr_id in component["measurements"]:
if measurement_id in component["measurements"][pmr_id]:
raise ValueError (
"Too many rules for PMR ID {0} measurement ID {1} for component {2} in manifest {3}".format (
pmr_id, measurement_id, component_type, xml_file))
else:
component["measurements"][pmr_id] = {}
component["measurements"][pmr_id][measurement_id] = {}
component["measurements"][pmr_id][measurement_id]["allowable_digests"] = []
for allowable_digest in measurement.findall (XML_DIGEST_TAG):
component["measurements"][pmr_id][measurement_id]["allowable_digests"].append (
binascii.a2b_hex (re.sub ("\s", "", allowable_digest.text.strip ())))
for measurement_data in root.findall (XML_MEASUREMENT_DATA_TAG):
if "measurement_data" not in component:
component["measurement_data"] = {}
pmr_id = int (xml_extract_attrib (measurement_data, XML_PMR_ID_ATTRIB, False, xml_file))
measurement_id = int (xml_extract_attrib (measurement_data, XML_MEASUREMENT_ID_ATTRIB,
False, xml_file))
if pmr_id in component["measurement_data"]:
if measurement_id in component["measurement_data"][pmr_id]:
raise ValueError (
"Too many rules for PMR ID {0} measurement data ID {1} for component {2} in manifest {3}".format (
pmr_id, measurement_id, component_type, xml_file))
else:
component["measurement_data"][pmr_id] = {}
component["measurement_data"][pmr_id][measurement_id] = {}
component["measurement_data"][pmr_id][measurement_id]["allowable_data"] = []
for allowable_data in measurement_data.findall (XML_ALLOWABLE_DATA_TAG):
data_dict = {}
data_dict["data"] = []
bitmask_tag = xml_find_single_tag (allowable_data, XML_BITMASK_TAG, xml_file, False)
if bitmask_tag is not None:
bitmask_text = binascii.a2b_hex (re.sub ("\s", "", bitmask_tag.text.strip ()))
data_dict["bitmask"] = bitmask_text
data_dict["bitmask_length"] = len (bitmask_text)
check = process_cfm_check (allowable_data, "data", component_type, xml_file)
data_dict["check"] = check
endianness_tag = xml_extract_single_value (allowable_data,
{"endianness": XML_ENDIANNESS_TAG}, xml_file)
if endianness_tag["endianness"] == CFM_ENDIANNESS_LITTLE_ENDIAN:
data_dict["endianness"] = 0
elif endianness_tag["endianness"] == CFM_ENDIANNESS_BIG_ENDIAN:
data_dict["endianness"] = 1
else:
raise ValueError (
"Unknown endianness '{0}' in allowable data for component {1} in manifest {2}".format (
endianness_tag["endianness"], component_type, xml_file))
for data in allowable_data.findall (XML_DATA_TAG):
data_text = data.text.strip ()
if data_text[0] == '"' and data_text[-1] == '"':
data_text = binascii.hexlify (data_text.strip ('\"').encode ())
else:
data_text = re.sub ("\s", "", data_text)
data_text = binascii.a2b_hex (data_text)
if "data_len" in component["measurement_data"][pmr_id][measurement_id]:
data_len = component["measurement_data"][pmr_id][measurement_id]["data_len"]
if len (data_text) != data_len:
raise ValueError (
"Data {0} has different length than other data for component {1} in manifest {2}: {3} vs {4}".format (
data_text, component_type, xml_file, len (data_text), data_len))
else:
component["measurement_data"][pmr_id][measurement_id]["data_len"] = \
len (data_text)
if "bitmask" in data_dict and len (data_text) > len (data_dict["bitmask"]):
raise ValueError (
"Data {0} length should be no greater than bitmask {1} for component {2} in manifest {3}".format (
data_text, data_dict["bitmask"], component_type, xml_file))
data_dict["data"].append (data_text)
component["measurement_data"][pmr_id][measurement_id]["allowable_data"].append (
data_dict)
for allowable_pfm in root.findall (XML_ALLOWABLE_PFM_TAG):
if "allowable_pfm" not in component:
component["allowable_pfm"] = {}
port_id = int (xml_extract_attrib (allowable_pfm, XML_PORT_ATTRIB, False, xml_file))
platform = xml_extract_attrib (allowable_pfm, XML_PLATFORM_ATTRIB, True, xml_file)
if port_id in component["allowable_pfm"]:
raise ValueError ("Too many rules for port {0} PFMs for component {1} in manifest {2}".format (
port_id, component_type, xml_file))
component["allowable_pfm"][port_id] = process_cfm_allowable_manifest (allowable_pfm,
"PFM", component_type, xml_file)
component["allowable_pfm"][port_id]["platform"] = platform
for allowable_cfm in root.findall (XML_ALLOWABLE_CFM_TAG):
if "allowable_cfm" not in component:
component["allowable_cfm"] = {}
index = int (xml_extract_attrib (allowable_cfm, XML_INDEX_ATTRIB, False, xml_file))
platform = xml_extract_attrib (allowable_cfm, XML_PLATFORM_ATTRIB, True, xml_file)
if index in component["allowable_cfm"]:
raise ValueError ("Too many rules for index {0} CFMs for component {1} in manifest {2}".format (
index, component_type, xml_file))
component["allowable_cfm"][index] = process_cfm_allowable_manifest (allowable_cfm,
"CFM", component_type, xml_file)
component["allowable_cfm"][index]["platform"] = platform
allowable_pcd = xml_find_single_tag (root, XML_ALLOWABLE_PCD_TAG, xml_file, False)
if allowable_pcd is not None:
platform = xml_extract_attrib (allowable_pcd, XML_PLATFORM_ATTRIB, True, xml_file)
component["allowable_pcd"] = process_cfm_allowable_manifest (allowable_pcd, "PCD",
component_type, xml_file)
component["allowable_pcd"]["platform"] = platform
return xml, manifest_types.VERSION_2, False