python-tuf icon indicating copy to clipboard operation
python-tuf copied to clipboard

Must signed.version be incremented every time a role is re-signed?

Open dennisvang opened this issue 3 years ago • 21 comments

Description of issue or feature request:

After reading the TUF specification and studying the basic_repo.py example, one thing remains unclear to me:

When exactly do we need to increment signed.version?

It is clear that we need to increment the signed.version after e.g. adding a new target, as detailed in the basic_repo.py example.

However, what if we only modify signed.expires, after a role has expired, without changing anything else? Do we also need to increment signed.version in that case? That would imply e.g. the version of timestamp is incremented every time it is re-signed.

In general, do we need to increment a role's signed.version every time we re-sign that role, without exception?

Current behavior:

It is not explicitly clear from the documentation when signed.version needs to be incremented.

Expected behavior:

It would be very helpful if the documentation/specification could clarify this point explicitly.

Perhaps the basic_repo.py example could also show a snippet where an expired timestamp is re-signed (without any changes to the root, targets, or snapshot metadata).

dennisvang avatar Jun 08 '22 13:06 dennisvang

Good point, stuff like this would make the docs much better. I believe any change to published signed metadata should lead to version bump: otherwise clients can't know when they need to download new metadata (in the case that they already have the previous version downloaded).

The only modification to metadata that doesn't need this that I could imagine is adding signatures... but even that seems safe only before the metadata is made public to clients (otherwise some clients could have fewer signatures and then signing keys might get changed and who knows how that would end).

jku avatar Jun 08 '22 14:06 jku

Good question!

The spec has recently been updated to be a bit more specific about how the client should deal with new metadata that has the same version as the trusted one (see theupdateframework/specification#209).

In case they [versions] are equal, discard the new timestamp metadata and abort the update cycle. This is normal and it shouldn't raise any error. The reason for aborting the update process is that there shouldn't be any changes in the content of this, or any other metadata files too, considering it has the same version as the already trusted one.

Parts of this are still being discussed in theupdateframework/specification#114

lukpueh avatar Jun 08 '22 14:06 lukpueh

... I believe any change to published signed metadata should lead to version bump: ...

@jku Yes, that certainly makes sense. Thanks for clarifying! :-)

dennisvang avatar Jun 08 '22 14:06 dennisvang

... I believe any change to published signed metadata should lead to version bump: ...

@jku Yes, that certainly makes sense. Thanks for clarifying! :-)

In the case of targets and snapshot metadata it also makes sense to bump if only the signatures are changed, because their file hashes could be listed in other metadata (snapshot can list targets metadata file hashes, and timestamp can list snapshot metadata file hashes).

lukpueh avatar Jun 08 '22 14:06 lukpueh

In the case of targets and snapshot metadata it also makes sense to bump if only the signatures are changed, because their file hashes could be listed in other metadata (snapshot can list targets metadata file hashes, and timestamp can list snapshot metadata file hashes).

@lukpueh Thanks for pointing that out.

So, would it be correct to say that the safest rule-of-thumb is to always bump the version whenever someone signs a role?

dennisvang avatar Jun 08 '22 14:06 dennisvang

bump the version whenever someone signs a role

... and publishes it for someone to consume.

I would say.

lukpueh avatar Jun 08 '22 14:06 lukpueh

bump the version whenever someone signs a role

... and publishes it for someone to consume.

where the consumer would be either a tuf client or another key-owner?

(sorry for going on about this)

dennisvang avatar Jun 08 '22 15:06 dennisvang

Ha, excellent follow-up question. I was only thinking of a client.

For threshold signing we actually must not bump the version on each signature. Otherwise we'd sign different content each time and would never reach the desired threshold.

lukpueh avatar Jun 08 '22 15:06 lukpueh

In the case of targets and snapshot metadata it also makes sense to bump if only the signatures are changed, because their file hashes could be listed in other metadata (snapshot can list targets metadata file hashes, and timestamp can list snapshot metadata file hashes).

Still trying to figure this out...

Suppose timestamp lists the hash for the snapshot file, and only the signatures for snapshot are changed (for some reason). This means the snapshot "signed" portion does not change, but the snapshot file hash does change. Thus, the "signed" portion for timestamp changes. Then wouldn't it make sense to bump the signed.version for timestamp only, and leave the signed.version for snapshot untouched?

dennisvang avatar Jun 09 '22 14:06 dennisvang

Do you release the file when you don't have a threshold of signatures? I mean, is it considered valid when it isn't fully signed? I would think it should not be and should not be released / trusted by clients.

On Wed, Jun 8, 2022 at 11:22 PM Lukas Pühringer @.***> wrote:

Ha, excellent follow-up question. I was only thinking of a client.

For threshold signing we actually must not bump the version on each signature. Otherwise we'd sign different content each time and would never reach the desired threshold.

— Reply to this email directly, view it on GitHub https://github.com/theupdateframework/python-tuf/issues/2020#issuecomment-1150063233, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAGROD5IVCLF4SB6K3KDC2TVOC3EPANCNFSM5YGP6DJA . You are receiving this because you are subscribed to this thread.Message ID: @.***>

JustinCappos avatar Jun 09 '22 18:06 JustinCappos

In the case of targets and snapshot metadata it also makes sense to bump if only the signatures are changed, because their file hashes could be listed in other metadata (snapshot can list targets metadata file hashes, and timestamp can list snapshot metadata file hashes).

Still trying to figure this out...

Suppose timestamp lists the hash for the snapshot file, and only the signatures for snapshot are changed (for some reason). This means the snapshot "signed" portion does not change, but the snapshot file hash does change. Thus, the "signed" portion for timestamp changes. Then wouldn't it make sense to bump the signed.version for timestamp only, and leave the signed.version for snapshot untouched?

Changing the signature of snapshot without changing the signed portion means that there is a change in the snapshot key used for singing. I think you will want to have a new version of snapshot in this case as you want to signal to your clients that there is a change in the keys used. This is useful in the case of snapshot key/keys compromise when you will want to rotate the keys with new ones.

MVrachev avatar Jun 09 '22 18:06 MVrachev

... as you want to signal to your clients that there is a change in the keys used. This is useful in the case of snapshot key/keys compromise when you will want to rotate the keys with new ones.

@MVrachev Doesn't the client handle this automatically, because the root role is updated at the beginning of the client workflow?

As I understand it (perhaps wrongly...), the spec suggests that the signed.version for snapshot is only read after verifying the signatures, see e.g. 5.5 steps 3 and 4. The hash for snapshot would have changed, but that would be taken care of by the updated timestamp file, which would have been downloaded first (5.4).

Side note: Not sure if it matters for the current discussion, but I'm not considering consistent snapshots in this example, so the snapshot metadata file doesn't have a version in the filename.

dennisvang avatar Jun 09 '22 18:06 dennisvang

If we consider the metadata object (basically the content of a metadata file):

{
  "signed" : ROLE,
  "signatures" : [
    { "keyid" : KEYID,
      "sig" : SIGNATURE }
      , ... ]
}

It is clear that the "signatures" element depends on the "signed" element: We sign off on the content of "signed", which includes a specific "version".

But, the other way round, shouldn't the "signed" element always remain independent of the "signatures" element (within that same metadata object)?

In other words, being a naive user, I would expect that an isolated change in the "signatures" element (for whatever reason) should never cause a change in the "signed" element (such as a version bump) of the same metadata object. On the other hand, it could (or should?) cause a version bump in the "signed" element of other, dependent, metadata objects (once it is published).

For example, an isolated change in the "signatures" element for snapshot should not cause a version bump for snapshot itself, but could lead to a version bump in timestamp, but only if timestamp contains the file hash etc. for snapshot.json.

Please correct me if I'm wrong here. :-)

dennisvang avatar Jun 10 '22 09:06 dennisvang

Your mental model seems right to me, maybe it works better with what we suggested above if we shift the causality a bit...

So I wouldn't say that a change in the independent signatures element causes a change in the signed element, but rather that only a version bump in the signed element causes the client to consider it as new metadata. Does that make sense?

lukpueh avatar Jun 10 '22 10:06 lukpueh

@MVrachev:

Changing the signature of snapshot without changing the signed portion means that there is a change in the snapshot key used for singing.

This is a likely but not the only reason for a change in signatures.

I think you will want to have a new version of snapshot in this case as you want to signal to your clients that there is a change in the keys used.

In case of a timestamp or snapshot key rotation in root metadata, we delete the trusted versions of those metadata files to allow recovery from a potential ffw attack. So in that case the version bump isn't actually required. :)

lukpueh avatar Jun 10 '22 11:06 lukpueh

@lukpueh Yes, thanks, I think that makes sense.

I'm still looking for a clear guideline. Something like the following, perhaps?

The "signed" version for a metadata object must be incremented if, and only if, the "signed" content has changed w.r.t. the latest published version of that metadata object.

dennisvang avatar Jun 10 '22 11:06 dennisvang

Maybe we can phrase it with regards to the user?

The "signed" version for a metadata object must be incremented if, any client downloader should consider it as new trusted metadata.

lukpueh avatar Jun 10 '22 11:06 lukpueh

The "signed" version for a metadata object must be incremented if, any client downloader should consider it as new trusted metadata.

That sounds better, and looking at this from the client workflow perspective does provide a better understanding of how the "version" is actually used. Although I do think this is a bit less explicit.

From the repository perspective, I was thinking along these lines (see if-condition):

...
# load metadata from file
snapshot = Metadata.from_file(snapshot_path)
original_snapshot_signed = copy.deepcopy(snapshot.signed)
# make some changes to the signed metadata (or maybe not, if we're only threshold signing)
...
# bump version if necessary (see tuf.api.metadata.Signed.__eq__)
version_bumped = snapshot.signed.version > original_snapshot_signed.version
if snapshot.signed != original_snapshot_signed and not version_bumped:
    snapshot.signed.version += 1
# sign and persist
...

dennisvang avatar Jun 10 '22 15:06 dennisvang

So this translates to "bump version right before sign/persist (for publication) if signed part has changed, unless the change already includes a version bump"? I think this makes sense as a rule of thumb.

lukpueh avatar Jun 13 '22 08:06 lukpueh

@lukpueh Yes, I think that translation covers it.

dennisvang avatar Jun 13 '22 08:06 dennisvang

This issue should be resolved as part of #1136 either in code or in documentation.

lukpueh avatar Jun 15 '22 08:06 lukpueh