Beispiel #1
0
def process_chain_of_trust(host: str, image: Image, req_delegations: list):
    """
    Processes the whole chain of trust, provided by the notary server (`host`)
    for any given `image`. The 'root', 'snapshot', 'timestamp', 'targets' and
    potentially 'targets/releases' are requested in this order and afterwards
    validated, also according to the `policy_rule`.

    Returns the the signed image targets, which contain the digests.

    Raises `NotFoundExceptions` should no required delegetions be present in
    the trust data, or no image targets be found.
    """
    tuf_roles = ["root", "snapshot", "timestamp", "targets"]
    trust_data = {}
    key_store = KeyStore()

    # get all trust data and collect keys (from root and targets), as well as
    # hashes (from snapshot and timestamp)
    for role in tuf_roles:
        trust_data[role] = get_trust_data(host, image, TUFRole(role))
        key_store.update(trust_data[role])

    # if the 'targets.json' has delegation roles defined, get their trust data
    # as well
    if trust_data["targets"].has_delegations():
        for delegation in trust_data["targets"].get_delegations():
            trust_data[delegation] = get_trust_data(host, image,
                                                    TUFRole(delegation))

    # validate all trust data's signatures, expiry dates and hashes
    for role in trust_data:
        trust_data[role].validate(key_store)

    # validate needed delegations
    if req_delegations:
        if trust_data["targets"].has_delegations():
            delegations = trust_data["targets"].get_delegations()

            req_delegations_set = set(req_delegations)
            delegations_set = set(delegations)

            delegations_set.discard("targets/releases")

            # make an intersection between required delegations and actually
            # present ones
            if not req_delegations_set.issubset(delegations_set):
                missing = list(req_delegations_set - delegations_set)
                raise NotFoundException(
                    "could not find delegation roles {} in trust data.".format(
                        str(missing)))
        else:
            raise NotFoundException(
                "could not find any delegations in trust data.")

    # get a list from all `targets` fields from `targets.json` + delegation roles or
    # just the delegation roles, should there be required delegation according to the
    # policy
    if req_delegations:
        image_targets = [
            trust_data[target_role].signed.get("targets", {})
            for target_role in req_delegations
        ]
    else:
        image_targets = [
            trust_data[target_role].signed.get("targets", {})
            for target_role in trust_data
            if re.match("targets(/[^/\\s]+)?", target_role)
        ]

    if not any(image_targets):
        raise NotFoundException(
            "could not find any image digests in trust data.")

    return image_targets
Beispiel #2
0
def process_chain_of_trust(
    host: str, image: Image, req_delegations: list
):  # pylint: disable=too-many-branches
    """
    Processes the whole chain of trust, provided by the notary server (`host`)
    for any given `image`. The 'root', 'snapshot', 'timestamp', 'targets' and
    potentially 'targets/releases' are requested in this order and afterwards
    validated, also according to the `policy_rule`.

    Returns the signed image targets, which contain the digests.

    Raises `NotFoundExceptions` should no required delegetions be present in
    the trust data, or no image targets be found.
    """
    tuf_roles = ["root", "snapshot", "timestamp", "targets"]
    trust_data = {}
    key_store = KeyStore()

    # get all trust data and collect keys (from root and targets), as well as
    # hashes (from snapshot and timestamp)
    for role in tuf_roles:
        trust_data[role] = get_trust_data(host, image, TUFRole(role))
        key_store.update(trust_data[role])

    # if the 'targets.json' has delegation roles defined, get their trust data
    # as well
    if trust_data["targets"].has_delegations():
        for delegation in trust_data["targets"].get_delegations():
            trust_data[delegation] = get_delegation_trust_data(
                host, image, TUFRole(delegation)
            )

    # validate all trust data's signatures, expiry dates and hashes.
    # when delegations are added to the repository, but weren't yet used for signing, the
    # delegation files don't exist yet and are `None`. in this case they can't be
    # validated and must be skipped
    for role in trust_data:
        if trust_data[role] is not None:
            trust_data[role].validate(key_store)

    # validate needed delegations
    if req_delegations:
        if trust_data["targets"].has_delegations():
            delegations = trust_data["targets"].get_delegations()

            req_delegations_set = set(req_delegations)
            delegations_set = set(delegations)

            delegations_set.discard("targets/releases")

            # make an intersection between required delegations and actually
            # present ones
            if not req_delegations_set.issubset(delegations_set):
                missing = list(req_delegations_set - delegations_set)
                raise NotFoundException(
                    "could not find delegation roles {} in trust data.".format(
                        str(missing)
                    )
                )
        else:
            raise NotFoundException("could not find any delegations in trust data.")

    # if certain delegations are required, then only take the targets fields of the
    # required delegation JSON's. otherwise take the targets field of the targets JSON, as
    # long as no delegations are defined in the targets JSON. should there be delegations
    # defined in the targets JSON the targets field of the releases JSON will be used.
    # unfortunately there is a case, where delegations could have been added to a
    # repository, but no signatures were created using the delegations. in this special
    # case, the releases JSON doesn't exist yet and the targets JSON must be used instead
    if req_delegations:
        if not all(trust_data[target_role] for target_role in req_delegations):
            tuf_roles = [
                target_role
                for target_role in req_delegations
                if not trust_data[target_role]
            ]
            msg = f"no trust data for delegation roles {tuf_roles} for image {image}"
            raise NotFoundException(msg, {"tuf_roles": tuf_roles})

        image_targets = [
            trust_data[target_role].signed.get("targets", {})
            for target_role in req_delegations
        ]
    else:
        targets_key = (
            "targets/releases"
            if trust_data["targets"].has_delegations()
            and trust_data["targets/releases"]
            else "targets"
        )
        image_targets = [trust_data[targets_key].signed.get("targets", {})]

    if not any(image_targets):
        raise NotFoundException("could not find any image digests in trust data.")

    return image_targets