From 8a8fff303a9b0a594e104b48a5335e1c73cb33dc Mon Sep 17 00:00:00 2001 From: Kairo de Araujo Date: Tue, 21 Dec 2021 09:13:02 +0100 Subject: [PATCH 1/2] test snapshot fast-forward attack recovery This test simulates the snapshot fast-forward attack recovery. It simulates that the snapshot keys were compromised, the attacker generated a new high version of the snapshot. The repository generates new keys for snapshot and timestamp and rollbacks the snapshot version to the initial version. Signed-off-by: Kairo de Araujo --- tests/test_updater_top_level_update.py | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/test_updater_top_level_update.py b/tests/test_updater_top_level_update.py index 3f46266a70..bde9c11cc0 100644 --- a/tests/test_updater_top_level_update.py +++ b/tests/test_updater_top_level_update.py @@ -424,6 +424,47 @@ def test_new_snapshot_version_rollback(self) -> None: self._assert_version_equals(Snapshot.type, 2) + def test_new_snapshot_fast_foward_recovery(self) -> None: + """Test snapshot fast-forward recovery using key rotation. + + The snapshot recovery requires the snapshot and timestamp key rotation. + It is made by the following steps: + - Remove the snapshot and timestamp keys + - Create and add a new key for snapshot and timestamp + - Rollback snapshot version + - Bump and publish root + - Bump the timestamp + """ + + # attacker updates to a higher version (bumping timestamp is required) + self.sim.snapshot.version = 99999 + self.sim.update_timestamp() + + # client refreshes the metadata and see the new snapshot version + self._run_refresh() + self._assert_version_equals(Snapshot.type, 99999) + + # repo add new snapshot and timestamp keys and recovers snapshot version + self.sim.root.roles["snapshot"].keyids.clear() + self.sim.signers["snapshot"].clear() + self.sim.root.roles["timestamp"].keyids.clear() + self.sim.signers["timestamp"].clear() + snapshot_key, snapshot_signer = self.sim.create_key() + self.sim.root.add_key("snapshot", snapshot_key) + self.sim.add_signer("snapshot", snapshot_signer) + timestamp_key, timestamp_signer = self.sim.create_key() + self.sim.root.add_key("timestamp", timestamp_key) + self.sim.add_signer("timestamp", timestamp_signer) + self.sim.snapshot.version = 1 + self.sim.root.version += 1 + self.sim.publish_root() + + self.sim.update_timestamp() + + # client refresh the metadata and see the initial snapshot version + self._run_refresh() + self._assert_version_equals(Snapshot.type, 1) + def test_new_snapshot_expired(self) -> None: # Check for a freeze attack self.sim.snapshot.expires = self.past_datetime From ac7a804525f41db3c1f1872f27d57ee9986ba0ee Mon Sep 17 00:00:00 2001 From: Kairo de Araujo Date: Tue, 21 Dec 2021 14:35:33 +0100 Subject: [PATCH 2/2] remove roles names as str, snapshot order This commit removes the role names as strings. Also do a slight change for clarity. Signed-off-by: Kairo de Araujo --- tests/test_updater_top_level_update.py | 34 +++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/test_updater_top_level_update.py b/tests/test_updater_top_level_update.py index bde9c11cc0..ed5a96d5ec 100644 --- a/tests/test_updater_top_level_update.py +++ b/tests/test_updater_top_level_update.py @@ -357,11 +357,11 @@ def test_new_timestamp_fast_foward_recovery(self) -> None: self._assert_version_equals(Timestamp.type, 99999) # repo add new timestamp keys and recovers the timestamp version - self.sim.root.roles["timestamp"].keyids.clear() - self.sim.signers["timestamp"].clear() + self.sim.root.roles[Timestamp.type].keyids.clear() + self.sim.signers[Timestamp.type].clear() key, signer = self.sim.create_key() - self.sim.root.add_key("timestamp", key) - self.sim.add_signer("timestamp", signer) + self.sim.root.add_key(Timestamp.type, key) + self.sim.add_signer(Timestamp.type, signer) self.sim.root.version += 1 self.sim.publish_root() self.sim.timestamp.version = 1 @@ -445,20 +445,20 @@ def test_new_snapshot_fast_foward_recovery(self) -> None: self._assert_version_equals(Snapshot.type, 99999) # repo add new snapshot and timestamp keys and recovers snapshot version - self.sim.root.roles["snapshot"].keyids.clear() - self.sim.signers["snapshot"].clear() - self.sim.root.roles["timestamp"].keyids.clear() - self.sim.signers["timestamp"].clear() + self.sim.root.roles[Snapshot.type].keyids.clear() + self.sim.signers[Snapshot.type].clear() + self.sim.root.roles[Timestamp.type].keyids.clear() + self.sim.signers[Timestamp.type].clear() snapshot_key, snapshot_signer = self.sim.create_key() - self.sim.root.add_key("snapshot", snapshot_key) - self.sim.add_signer("snapshot", snapshot_signer) + self.sim.root.add_key(Snapshot.type, snapshot_key) + self.sim.add_signer(Snapshot.type, snapshot_signer) timestamp_key, timestamp_signer = self.sim.create_key() - self.sim.root.add_key("timestamp", timestamp_key) - self.sim.add_signer("timestamp", timestamp_signer) - self.sim.snapshot.version = 1 + self.sim.root.add_key(Timestamp.type, timestamp_key) + self.sim.add_signer(Timestamp.type, timestamp_signer) self.sim.root.version += 1 self.sim.publish_root() + self.sim.snapshot.version = 1 self.sim.update_timestamp() # client refresh the metadata and see the initial snapshot version @@ -530,15 +530,15 @@ def test_compute_metafile_hashes_length(self) -> None: self.sim.compute_metafile_hashes_length = True self.sim.update_snapshot() self._run_refresh() - self._assert_version_equals("timestamp", 2) - self._assert_version_equals("snapshot", 2) + self._assert_version_equals(Timestamp.type, 2) + self._assert_version_equals(Snapshot.type, 2) self.sim.compute_metafile_hashes_length = False self.sim.update_snapshot() self._run_refresh() - self._assert_version_equals("timestamp", 3) - self._assert_version_equals("snapshot", 3) + self._assert_version_equals(Timestamp.type, 3) + self._assert_version_equals(Snapshot.type, 3) if __name__ == "__main__":