First, let's be clear about this: if you're looking for the trustworthy target info (hash, length, etc.) for a target whose name you know, TUF has that clearly solved for you: the algorithms are in the specification (item 4.5 here) and the reference implementation provides Updater.get_one_valid_target_info() implementing them. This works fine with or without using delegations.
However, an important part of many update systems is finding out what is available in the first place. There are reasonable arguments for using TUF to find target listings:
Updater.get_one_valid_target_info()). You can lose cycles looking for them, but that's about it.)If you do not use delegations, the listing of targets on the repository is easy to obtain and verify.
The same protection provided for an individual target is extended for the listing of targets itself, with all of TUF's guarantees. This is because the list exists in one location, the top-level Targets role, and can always be verified using the information in the Root metadata. Just refreshing top-level metadata automatically gets you a verified index of targets, secured by the Targets role via Root.
If you do use delegations, getting a listing of available targets on the repository is more involved and has more complex security implications.
If you _don't_ already know what role lists the targets you might be interested in, you would have to walk the graph from Targets to obtain and verify all delegated roles to fill your list. (We can and should provide that in a function, to replace the deprecated Updater.all_targets(), and the algorithm should be added to the specification IMO so that no implementer produces something like the current insecure all_targets(). Note also that this is not very efficient.) The security of such an all-targets query is not the same as the no-delegations security provided above, where the list is secured by Targets via Root. Instead, using delegations, there's a generally-weaker Snapshot role guarantee that you are not unknowingly missing role files or updates to role files, and a guarantee from each delegated role file itself that it has not added or excluded targets.
If you _do_ already know what delegated role lists the targets you're interested in, then you can jump to that role and that role is essentially providing you a listing service. That service then has the following ill-defined security:
(If this is not clear, please ask and I'll elaborate with an example.)
Please provide an example. I understand the rest and think the snapshot role is fine for protection in most scenarios.
@trishankatdatadog
I'm finishing up rewriting all_targets and targets_of_role now (no longer deprecated 馃帀). targets_of_role isn't really interesting, and I'm content with the way I've rewritten it (docstring here).
There are two ways I could go about all_targets, though.
In both models, there will be two steps:
The two options pertain to step one, and the security guarantees provided for inclusion of target names. I can take two approaches:
OR
Since step 2 will protect you from attackers' adding targets, the distinction is in what credentials are required for an attacker to de-list things. For 1A, a mirror without keys can de-list targets by providing junk metadata, without detection. For 1B, missing roles are noticed, so nobody can be quietly deprived of their ability to list targets.
I'm going the 1B direction. That results in this docstring for all_targets. LMK if you actually find 1A more appealing .
"""
<Purpose>
Obtain every verified target info listed by the repository.
This method does that in two stages:
1. Walk the targets delegation graph, beginning at the top-level
Targets role, harvesting all target names listed by each targets
role it traverses.
2. Then -- after the full traversal yields a list of target names --
call get_one_valid_targetinfo on each target name to get the
verified target info for that target, walking the delegation graph
as necessary. This is done rather than reproducing the security
functionality of get_one_valid_targetinfo during step 1 along the
way.
This is not efficient, but neither is it catastrophically inefficient,
and it avoids dangerous code reproduction of core TUF code from
get_one_valid_targetinfo. (A more efficient single-traversal procedure
involves a good bit of overhead tracking all delegation properties from
delegations traversed to reach each node -- so that it can make decisions
about every target it sees -- and it would be easy for a maintainer to
allow its behavior to deviate from get_one_valid_targetinfo.)
This method does not update top-level metadata (Root, Timestamp,
Snapshot, Targets). It WILL, however, if necessary, update delegated
targets metadata in the process of walking the delegation graph, if and
only if (1) a needed delegated targets metadata has not previously been
obtained or (2) the currently-trusted version of Snapshot indicates that
that delegated targets role is out of date (has a lower version number
than Snapshot expects).
<Arguments>
None.
<Exceptions>
tuf.exceptions.RepositoryError:
If the metadata for the 'targets' role is missing from
the 'snapshot' metadata.
tuf.exceptions.UnknownRoleError:
If one of the top-level roles could not be found in the role database.
<Side Effects>
The metadata for target roles is updated and stored.
<Returns>
A list of targets, conformant to
'tuf.formats.LABELED_FILEINFOS_SCHEMA'.
"""
@awwad Great stuff, and I'm on board with you about 1B. I think it should work, but I haven't thought about the algorithm yet, should be feasible
Just upgraded to 0.12.2, the all_targets method is still there but deprecated.
I'm not using delegations so is it okay to carry on using it?
You should be safe if you use no targets role delegations, but be careful to keep it that way. :)
Most helpful comment
@trishankatdatadog
I'm finishing up rewriting
all_targetsandtargets_of_rolenow (no longer deprecated 馃帀).targets_of_roleisn't really interesting, and I'm content with the way I've rewritten it (docstring here).There are two ways I could go about
all_targets, though.In both models, there will be two steps:
The two options pertain to step one, and the security guarantees provided for inclusion of target names. I can take two approaches:
OR
Since step 2 will protect you from attackers' adding targets, the distinction is in what credentials are required for an attacker to de-list things. For 1A, a mirror without keys can de-list targets by providing junk metadata, without detection. For 1B, missing roles are noticed, so nobody can be quietly deprived of their ability to list targets.
I'm going the 1B direction. That results in this docstring for
all_targets. LMK if you actually find 1A more appealing .