示例#1
0
    def check_pcrs(self, agentAttestState, tpm_policy, pcrs, data, virtual,
                   ima_measurement_list, allowlist, ima_keyrings,
                   mb_measurement_list, mb_refstate_str, hash_alg) -> Failure:
        failure = Failure(Component.PCR_VALIDATION)
        if isinstance(tpm_policy, str):
            tpm_policy = json.loads(tpm_policy)

        pcr_allowlist = tpm_policy.copy()

        if 'mask' in pcr_allowlist:
            del pcr_allowlist['mask']
        # convert all pcr num keys to integers
        pcr_allowlist = {int(k): v for k, v in list(pcr_allowlist.items())}

        mb_policy, mb_policy_name, mb_refstate_data = measured_boot.get_policy(
            mb_refstate_str)
        mb_pcrs_hashes, boot_aggregates, mb_measurement_data, mb_failure = self.parse_mb_bootlog(
            mb_measurement_list, hash_alg)
        failure.merge(mb_failure)

        pcrs_in_quote = set(
        )  # PCRs in quote that were already used for some kind of validation

        pcrs = AbstractTPM.__parse_pcrs(pcrs, virtual)
        pcr_nums = set(pcrs.keys())

        # Validate data PCR
        if config.TPM_DATA_PCR in pcr_nums and data is not None:
            expectedval = self.sim_extend(data, hash_alg=hash_alg)
            if expectedval != pcrs[config.TPM_DATA_PCR]:
                logger.error(
                    "%sPCR #%s: invalid bind data %s from quote does not match expected value %s",
                    ("", "v")[virtual], config.TPM_DATA_PCR,
                    pcrs[config.TPM_DATA_PCR], expectedval)
                failure.add_event(f"invalid_pcr_{config.TPM_DATA_PCR}", {
                    "got": pcrs[config.TPM_DATA_PCR],
                    "expected": expectedval
                }, True)
            pcrs_in_quote.add(config.TPM_DATA_PCR)
        else:
            logger.error(
                "Binding %sPCR #%s was not included in the quote, but is required",
                ("", "v")[virtual], config.TPM_DATA_PCR)
            failure.add_event(
                f"missing_pcr_{config.TPM_DATA_PCR}",
                f"Data PCR {config.TPM_DATA_PCR} is missing in quote, but is required",
                True)
        # Check for ima PCR
        if config.IMA_PCR in pcr_nums:
            if ima_measurement_list is None:
                logger.error(
                    "IMA PCR in policy, but no measurement list provided")
                failure.add_event(
                    f"unused_pcr_{config.IMA_PCR}",
                    "IMA PCR in policy, but no measurement list provided",
                    True)
            else:
                ima_failure = AbstractTPM.__check_ima(agentAttestState,
                                                      pcrs[config.IMA_PCR],
                                                      ima_measurement_list,
                                                      allowlist, ima_keyrings,
                                                      boot_aggregates,
                                                      hash_alg)
                failure.merge(ima_failure)

            pcrs_in_quote.add(config.IMA_PCR)

        # Collect mismatched measured boot PCRs as measured_boot failures
        mb_pcr_failure = Failure(Component.MEASURED_BOOT)
        # Handle measured boot PCRs only if the parsing worked
        if not mb_failure:
            for pcr_num in set(config.MEASUREDBOOT_PCRS) & pcr_nums:
                if mb_refstate_data:
                    if not mb_measurement_list:
                        logger.error(
                            "Measured Boot PCR %d in policy, but no measurement list provided",
                            pcr_num)
                        failure.add_event(
                            f"unused_pcr_{pcr_num}",
                            f"Measured Boot PCR {pcr_num} in policy, but no measurement list provided",
                            True)
                        continue

                    val_from_log_int = mb_pcrs_hashes.get(str(pcr_num), 0)
                    val_from_log_hex = hex(val_from_log_int)[2:]
                    val_from_log_hex_stripped = val_from_log_hex.lstrip('0')
                    pcrval_stripped = pcrs[pcr_num].lstrip('0')
                    if val_from_log_hex_stripped != pcrval_stripped:
                        logger.error(
                            "For PCR %d and hash %s the boot event log has value %r but the agent returned %r",
                            str(hash_alg), pcr_num, val_from_log_hex,
                            pcrs[pcr_num])
                        mb_pcr_failure.add_event(
                            f"invalid_pcr_{pcr_num}", {
                                "context":
                                "SHA256 boot event log PCR value does not match",
                                "got": pcrs[pcr_num],
                                "expected": val_from_log_hex
                            }, True)

                    if pcr_num in pcr_allowlist and pcrs[
                            pcr_num] not in pcr_allowlist[pcr_num]:
                        logger.error(
                            "%sPCR #%s: %s from quote does not match expected value %s",
                            ("", "v")[virtual], pcr_num, pcrs[pcr_num],
                            pcr_allowlist[pcr_num])
                        failure.add_event(
                            f"invalid_pcr_{pcr_num}", {
                                "context": "PCR value is not in allowlist",
                                "got": pcrs[pcr_num],
                                "expected": pcr_allowlist[pcr_num]
                            }, True)
                    pcrs_in_quote.add(pcr_num)
        failure.merge(mb_pcr_failure)

        # Check the remaining non validated PCRs
        for pcr_num in pcr_nums - pcrs_in_quote:
            if pcr_num not in list(pcr_allowlist.keys()):
                logger.warning(
                    "%sPCR #%s in quote not found in %stpm_policy, skipping.",
                    ("", "v")[virtual], pcr_num, ("", "v")[virtual])
                continue
            if pcrs[pcr_num] not in pcr_allowlist[pcr_num]:
                logger.error(
                    "%sPCR #%s: %s from quote does not match expected value %s",
                    ("", "v")[virtual], pcr_num, pcrs[pcr_num],
                    pcr_allowlist[pcr_num])
                failure.add_event(
                    f"invalid_pcr_{pcr_num}", {
                        "context": "PCR value is not in allowlist",
                        "got": pcrs[pcr_num],
                        "expected": pcr_allowlist[pcr_num]
                    }, True)

            pcrs_in_quote.add(pcr_num)

        missing = set(pcr_allowlist.keys()) - pcrs_in_quote
        if len(missing) > 0:
            logger.error("%sPCRs specified in policy not in quote: %s",
                         ("", "v")[virtual], missing)
            failure.add_event("missing_pcrs", {
                "context": "PCRs are missing in quote",
                "data": list(missing)
            }, True)

        if not mb_failure and mb_refstate_data:
            mb_policy_failure = measured_boot.evaluate_policy(
                mb_policy, mb_policy_name, mb_refstate_data,
                mb_measurement_data, pcrs_in_quote, ("", "v")[virtual],
                agentAttestState.get_agent_id())
            failure.merge(mb_policy_failure)

        return failure
    def check_pcrs(self, agentAttestState, tpm_policy, pcrs, data, virtual,
                   ima_measurement_list, allowlist, ima_keyring,
                   mb_measurement_list, mb_refstate_str):

        if isinstance(tpm_policy, str):
            tpm_policy = json.loads(tpm_policy)

        pcr_allowlist = tpm_policy.copy()

        if 'mask' in pcr_allowlist:
            del pcr_allowlist['mask']
        # convert all pcr num keys to integers
        pcr_allowlist = {int(k): v for k, v in list(pcr_allowlist.items())}

        mb_policy, mb_refstate_data = measured_boot.get_policy(mb_refstate_str)
        mb_pcrs_sha256, boot_aggregates, mb_measurement_data, success = self.parse_mb_bootlog(
            mb_measurement_list)
        if not success:
            return False

        pcrs_in_quote = set(
        )  # PCRs in quote that were already used for some kind of validation

        pcrs = self.__parse_pcrs(pcrs, virtual)
        pcr_nums = set(pcrs.keys())

        # Skip validation if TPM is stubbed.
        if config.STUB_TPM:
            return True

        # Validate data PCR
        if config.TPM_DATA_PCR in pcr_nums and data is not None:
            expectedval = self.sim_extend(data)
            if expectedval != pcrs[config.TPM_DATA_PCR]:
                logger.error(
                    "%sPCR #%s: invalid bind data %s from quote does not match expected value %s",
                    ("", "v")[virtual], config.TPM_DATA_PCR,
                    pcrs[config.TPM_DATA_PCR], expectedval)
                return False
            pcrs_in_quote.add(config.TPM_DATA_PCR)
        else:
            logger.error(
                "Binding %sPCR #%s was not included in the quote, but is required",
                ("", "v")[virtual], config.TPM_DATA_PCR)
            return False

        # Check for ima PCR
        if config.IMA_PCR in pcr_nums:
            if ima_measurement_list is None:
                logger.error(
                    "IMA PCR in policy, but no measurement list provided")
                return False

            if not self.__check_ima(agentAttestState, pcrs[config.IMA_PCR],
                                    ima_measurement_list, allowlist,
                                    ima_keyring, boot_aggregates):
                return False

            pcrs_in_quote.add(config.IMA_PCR)

        # Handle measured boot PCRs
        for pcr_num in set(config.MEASUREDBOOT_PCRS) & pcr_nums:
            if mb_refstate_data:
                if not mb_measurement_list:
                    logger.error(
                        "Measured Boot PCR %d in policy, but no measurement list provided",
                        pcr_num)
                    return False

                val_from_log_int = mb_pcrs_sha256.get(str(pcr_num), 0)
                val_from_log_hex = hex(val_from_log_int)[2:]
                val_from_log_hex_stripped = val_from_log_hex.lstrip('0')
                pcrval_stripped = pcrs[pcr_num].lstrip('0')
                if val_from_log_hex_stripped != pcrval_stripped:
                    logger.error(
                        "For PCR %d and hash SHA256 the boot event log has value %r but the agent returned %r",
                        pcr_num, val_from_log_hex, pcrs[pcr_num])
                    return False
                if pcr_num in pcr_allowlist and pcrs[
                        pcr_num] not in pcr_allowlist[pcr_num]:
                    logger.error(
                        "%sPCR #%s: %s from quote does not match expected value %s",
                        ("", "v")[virtual], pcr_num, pcrs[pcr_num],
                        pcr_allowlist[pcr_num])
                    return False
                pcrs_in_quote.add(pcr_num)

        # Check the remaining non validated PCRs
        for pcr_num in pcr_nums - pcrs_in_quote:
            if pcr_num not in list(pcr_allowlist.keys()):
                logger.warning(
                    "%sPCR #%s in quote not found in %stpm_policy, skipping.",
                    ("", "v")[virtual], pcr_num, ("", "v")[virtual])
                continue
            if pcrs[pcr_num] not in pcr_allowlist[pcr_num]:
                logger.error(
                    "%sPCR #%s: %s from quote does not match expected value %s",
                    ("", "v")[virtual], pcr_num, pcrs[pcr_num],
                    pcr_allowlist[pcr_num])
                return False

            pcrs_in_quote.add(pcr_num)

        missing = set(pcr_allowlist.keys()) - pcrs_in_quote
        if len(missing) > 0:
            logger.error("%sPCRs specified in policy not in quote: %s",
                         ("", "v")[virtual], missing)
            return False

        if mb_refstate_data:
            success = measured_boot.evaluate_policy(
                mb_policy, mb_refstate_data, mb_measurement_data,
                pcrs_in_quote, ("", "v")[virtual],
                agentAttestState.get_agent_id())
            if not success:
                return False

        return True