def process_cfm()

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