Skip to content

Commit e8c9dd0

Browse files
committed
When updating timestamp, make sure we aren't rolling back snapshot
This implements [TUF-1.0.5 §5.2.2.2], which states: > The version number of the targets metadata file, and all > delegated targets metadata files (if any), in the trusted snapshot metadata > file, if any, MUST be less than or equal to its version number in the new > snapshot metadata file. Furthermore, any targets metadata filename that was > listed in the trusted snapshot metadata file, if any, MUST continue to be > listed in the new snapshot metadata file. If any of these conditions are > not met, discard the new snapshot metadadata file, abort the update cycle, > and report the failure. Furthermore, it adds three tests to: * make sure rollbacks are prevented * that trusted target roles cannot be removed in a normal update. * that we can remove a target role with a root roll. Fixes #294. [TUF-1.0.5 §5.2.2.2]: https://github.com/theupdateframework/specification/blob/39c80de07407bd4251ad823976dc4116a4b05043/tuf-spec.md?plain=1#L1163
1 parent 0c08b7d commit e8c9dd0

1 file changed

Lines changed: 62 additions & 1 deletion

File tree

tuf/src/database.rs

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,15 @@ impl<D: Pouf> Database<D> {
424424
// new timestamp metadata file. If not, discard the new timestamp metadadata file,
425425
// abort the update cycle, and report the failure.
426426

427-
// FIXME(#294): Implement this section.
427+
if let Some(trusted_timestamp) = &self.trusted_timestamp {
428+
if new_timestamp.snapshot().version() < trusted_timestamp.snapshot().version() {
429+
return Err(Error::AttemptedMetadataRollBack {
430+
role: MetadataPath::snapshot(),
431+
trusted_version: trusted_timestamp.snapshot().version(),
432+
new_version: new_timestamp.snapshot().version(),
433+
});
434+
}
435+
}
428436

429437
/////////////////////////////////////////
430438
// TUF-1.0.5 §5.2.3:
@@ -1370,6 +1378,59 @@ mod test {
13701378
assert!(tuf.update_timestamp(&now, &raw_timestamp).is_err())
13711379
}
13721380

1381+
#[test]
1382+
fn bad_timestamp_update_rollback_snapshot() {
1383+
let now = Utc::now();
1384+
1385+
let raw_root = RootMetadataBuilder::new()
1386+
.root_key(KEYS[0].public().clone())
1387+
.snapshot_key(KEYS[1].public().clone())
1388+
.targets_key(KEYS[1].public().clone())
1389+
.timestamp_key(KEYS[1].public().clone())
1390+
.signed::<Pouf1>(&KEYS[0])
1391+
.unwrap()
1392+
.to_raw()
1393+
.unwrap();
1394+
1395+
let mut tuf = Database::from_trusted_root(&raw_root).unwrap();
1396+
1397+
let snapshot_v2 = SnapshotMetadataBuilder::new()
1398+
.version(2)
1399+
.signed::<Pouf1>(&KEYS[1])
1400+
.unwrap();
1401+
1402+
let raw_timestamp_v1 =
1403+
TimestampMetadataBuilder::from_snapshot(&snapshot_v2, &[HashAlgorithm::Sha256])
1404+
.unwrap()
1405+
.version(1)
1406+
.signed::<Pouf1>(&KEYS[1])
1407+
.unwrap()
1408+
.to_raw()
1409+
.unwrap();
1410+
1411+
tuf.update_timestamp(&now, &raw_timestamp_v1).unwrap();
1412+
1413+
let snapshot_v1 = SnapshotMetadataBuilder::new()
1414+
.version(1)
1415+
.signed::<Pouf1>(&KEYS[1])
1416+
.unwrap();
1417+
1418+
let raw_timestamp_v2 =
1419+
TimestampMetadataBuilder::from_snapshot(&snapshot_v1, &[HashAlgorithm::Sha256])
1420+
.unwrap()
1421+
.version(2)
1422+
.signed::<Pouf1>(&KEYS[1])
1423+
.unwrap()
1424+
.to_raw()
1425+
.unwrap();
1426+
1427+
assert_matches!(
1428+
tuf.update_timestamp(&now, &raw_timestamp_v2),
1429+
Err(Error::AttemptedMetadataRollBack { role, trusted_version: 2, new_version: 1 })
1430+
if role == MetadataPath::snapshot()
1431+
);
1432+
}
1433+
13731434
#[test]
13741435
fn good_snapshot_update() {
13751436
let now = Utc::now();

0 commit comments

Comments
 (0)