Repository navigation
avoid trying to update root role every time #225
Description
Activity
Hi @nexustar, thank you for taking the time to file this issue.
Historically TUF did work this way: root metadata was listed as a
METAFILEin themetafield of the snapshot metadata and would only be fetched if snapshot indicated the root role had changed. When root had changed, the client would then restart the update process with the new root metadata.This behaviour was changed to improve TUF's compromise resilience (and, I think, simplifies implementation of the client workflow). Signing keys for the snapshot role are often kept online or used in an automated fashion. With the old TUF behaviour, if the snapshot role was compromised an attacker may choose to continue to list old versions of the root metadata in snapshot which could refer to the compromised snapshot key as being valid (at least until such time as the old root metadata expires).
Unfortunately, tracking the full history of when this change was introduced is difficult. The earliest references I could find are:
- Introduction of versioned roots in Various changes to repository writing python-tuf#379 (specifically theupdateframework/python-tuf@0e93c3a which changes the client behaviour in the Python reference implementation to build the trust chain from a known local root metadata file to the latest version published on the repository)
- Beginning to describe the new client workflow in the specification Expand on the TUF client update workflow, per popular demand. python-tuf#440
- pinned this issue
on May 12, 2022 - unpinned this issue
on Oct 26, 2022 This issue mentions avoiding unnecessary root downloads as a motivation for including the root version in the snapshot file. But there is a more important motivation: It would allow quickly detecting freeze attacks against the root metadata. I was surprised that TUF does not already do this. One of the main reasons for having the timestamp file in TUF is that freeze attacks can be detected quickly, because it has a short validity period. But because the root version is not listed in either timestamp or snapshot, this protection against freeze attacks does not extend to the root metadata. The root metadata commonly has a long validity period of several months, but at the same time it is important that updates are noticed quickly.
The TUF specification acknowledges this limitation:
Note that an attacker, who controls the repository, can launch freeze attacks by withholding new root metadata. The attacker does not need to compromise root keys to do so. However, these freeze attacks are limited by the expiration time of the latest root metadata available to the client.
For example, a new root version is created with one or more root keys rotated, but keys for other roles are unchanged. An attacker who controls the repository can hide the new root version, and clients would not notice that anything is wrong until the previous root expires. If the root version was part of the snapshot, then clients could notice the problem as soon as the previous timestamp expires.
As a side note, the TUF website still describes the previous spec versions where the root version was part of the snapshot:
The snapshot.json metadata file lists version numbers of all metadata files other than timestamp.json.
Implementing root freeze protection
Here is how this could be implemented in the spec. The description of snapshot.json is updated to say that it also MUST list the version number of the root metadata. In the client update workflow, a step is inserted to report failure if the root version is not equal to the version listed in the snapshot. For backward compatibility, this check is omitted if the snapshot does not list the root version.
It is possible that the version check fails, because the repository was concurrently updated with a new root, snapshot and timestamp, just between the time where the client fetches the root, and the time where the client fetches the timestamp. This is not an entirely new problem; this situation could have caused verification failures previously if e.g. timestamp keys were rotated. This problem could be mitigated by retrying the update from the beginning if a root version mismatch is detected. But properly fixing this requires implementing the root download optimization (i.e. taking the root version from the snapshot instead of trying to download new roots until a newer one is not found), which would ensure that we get a consistent view of the repository including the root, even if it is concurrently being updated.
Implementing root download optimization
Once we have the root version in the snapshot, this could also be used to avoid downloading the root if unchanged. This is only an optimization, and for compatibility with existing TUF repos without this addition, implementations would have to retain the old update behavior as a fallback. Currently, even the snapshot and target download are not optimized, see #235.
Implementing this optimization would require first downloading the timestamp, and if needed the snapshot, and extracting the root version from the snapshot, all before verifying signatures on the timestamp or snapshot.
There is a potential problem from this optimization: In case the repository was recovered from a compromise, it is possible that the new snapshot has the same version as a previous attacker-created snapshot. If a client sees that the snapshot version is unchanged and thus skips the snapshot download (even though the snapshot on the server has changed), it would fail to notice that the root has updated. To fix this potential problem, either the snapshot or the root download optimization should only be enabled if the timestamp includes a hash of the snapshot, such that the client can be sure that the locally cached snapshot is up to date.
- Thanks for taking the time to respond here. I wanted to echo @joshua Lock ***@***.***> 's thoughts about client optimization and add a few of my own related to the security tradeoffs. In the case that the repository and the keys it stores online are compromised (which is essentially always timestamp and almost always snapshot), the attacker can lie about things like the version number of the root metadata. Note that if the repository is recovered to a good state which is visible to a user, then the user will always get the latest root role, timestamp, snapshot, etc. So let's consider the case where the attacker's ability to interfere with the repository lasts a very long time and the snapshot key / timestamp key are/were also compromised. In this case, the attacker can sign whatever snapshot they want and "freeze" the root role even if we include the version number in the snapshot. Only the timeout of the root role's metadata will eventually be detected. So as I understand what is written above, I don't think any proposed scheme can help with this situation. Okay, so this leaves another case unaddressed: What if the attacker has saved metadata from timestamp and/or snapshot and can pretend to be the repository (i.e., MITM), but hasn't compromised the actual signing keys. If the attacker hasn't compromised the timestamp key, then any freeze attack is still limited by this key's lifetime, which is quite short. If the attacker has compromised the timestamp key, but not the snapshot key, and is a persistent MITM / has a long term repository compromise, then the attacker would be able to replay old snapshot files with the old root key. In this case, I think the proposed solution would help, because a user would detect a freeze attack when the snapshot files expired. This is likely better than the root key expiry, but this time can still be rather long. One other thing to note is that if you do list the root role in the snapshot and then decide not to download it if it is not updated, this does mean that a MITM who has compromised only the snapshot key but is not a persistent MITM, can potentially stop you from getting a new root file. At first glance, this may not seem particularly likely to happen in practice, but CDNs which origin pull content upon request (as is common) would make clients vulnerable to this sort of attack, when they otherwise would not likely be for an extended period. CDNs are also pretty common amongst adopters, so are actually a case we need to worry about. Note, this isn't meant to justify that we made the right tradeoff here. We did spend some time working this out on a whiteboard and thought we were making the best choice here. There may be other things we hadn't thought of, errors in judgment / analysis, and of course reasonable minds can always differ at how to value different attack cases.…On Thu, Dec 12, 2024 at 6:12 AM Jan Schär ***@***.***> wrote: This issue mentions avoiding unnecessary root downloads as a motivation for including the root version in the snapshot file. But there is a more important motivation: It would allow quickly detecting freeze attacks against the root metadata. I was surprised that TUF does not already do this. One of the main reasons for having the timestamp file in TUF is that freeze attacks can be detected quickly, because it has a short validity period. But because the root version is not listed in either timestamp or snapshot, this protection against freeze attacks does not extend to the root metadata. The root metadata commonly has a long validity period of several months, but at the same time it is important that updates are noticed quickly. The TUF specification <https://theupdateframework.github.io/specification/v1.0.33/#key-management-and-migration> acknowledges this limitation: Note that an attacker, who controls the repository, can launch freeze attacks by withholding new root metadata. The attacker does not need to compromise root keys to do so. However, these freeze attacks are limited by the expiration time of the latest root metadata available to the client. For example, a new root version is created with one or more root keys rotated, but keys for other roles are unchanged. An attacker who controls the repository can hide the new root version, and clients would not notice that anything is wrong until the previous root expires. If the root version was part of the snapshot, then clients could notice the problem as soon as the previous timestamp expires. As a side note, the TUF website <https://theupdateframework.io/docs/metadata/#snapshot-metadata-snapshotjson> still describes the previous spec versions where the root version was part of the snapshot: The snapshot.json metadata file lists version numbers of all metadata files other than timestamp.json. Implementing root freeze protection Here is how this could be implemented in the spec. The description of snapshot.json is updated to say that it also MUST list the version number of the root metadata. In the client update workflow, a step is inserted to report failure if the root version is not equal to the version listed in the snapshot. For backward compatibility, this check is omitted if the snapshot does not list the root version. It is possible that the version check fails, because the repository was concurrently updated with a new root, snapshot and timestamp, just between the time where the client fetches the root, and the time where the client fetches the timestamp. This is not an entirely new problem; this situation could have caused verification failures previously if e.g. timestamp keys were rotated. This problem could be mitigated by retrying the update from the beginning if a root version mismatch is detected. But properly fixing this requires implementing the root download optimization (i.e. taking the root version from the snapshot instead of trying to download new roots until a newer one is not found), which would ensure that we get a consistent view of the repository including the root, even if it is concurrently being updated. Implementing root download optimization Once we have the root version in the snapshot, this could also be used to avoid downloading the root if unchanged. This is only an optimization, and for compatibility with existing TUF repos without this addition, implementations would have to retain the old update behavior as a fallback. Currently, even the snapshot and target download are not optimized, see #235 <#235>. Implementing this optimization would require first downloading the timestamp, and if needed the snapshot, and extracting the root version from the snapshot, all before verifying signatures on the timestamp or snapshot. There is a potential problem from this optimization: In case the repository was recovered from a compromise, it is possible that the new snapshot has the same version as a previous attacker-created snapshot. If a client sees that the snapshot version is unchanged and thus skips the snapshot download (even though the snapshot on the server has changed), it would fail to notice that the root has updated. To fix this potential problem, either the snapshot or the root download optimization should only be enabled if the timestamp includes a hash of the snapshot, such that the client can be sure that the locally cached snapshot is up to date. — Reply to this email directly, view it on GitHub <#225 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAGROD6LTPIQODCL7JIAUJ32FFVRPAVCNFSM6AAAAABTPRGOUSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDKMZYGU4DIOBWHE> . You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
At beginning of update, TUF client try to update root role,but most of time there is no update of root role. For a check for updates step, at lease 2 download is needed (n+1.root.json and timestamp.json if there is no update)
if record version of root role in snapshot role, we can fetch timestamp role first, and update it when timestamp role changed and snapshot say it need to update.
On security way, I think it is the same because if the attacker can return fake snapshot,he also can pretend that there is no n+1 version of root role