@@ -178,6 +178,10 @@ def update_root(self, data: bytes):
178178 def update_timestamp (self , data : bytes ):
179179 """Verifies and loads 'data' as new timestamp metadata.
180180
181+ Note that an expired intermediate timestamp is considered valid so it
182+ can be used for rollback checks on newer, final timestamp. Expiry is
183+ only checked for the final timestamp in update_snapshot().
184+
181185 Args:
182186 data: unverified new timestamp metadata as bytes
183187
@@ -227,15 +231,19 @@ def update_timestamp(self, data: bytes):
227231 self .timestamp .signed .meta ["snapshot.json" ].version ,
228232 )
229233
230- if new_timestamp . signed . is_expired ( self . reference_time ):
231- raise exceptions . ExpiredMetadataError ( "New timestamp is expired" )
234+ # expiry not checked to allow old timestamp to be used for rollback
235+ # protection of new timestamp: expiry is checked in update_snapshot( )
232236
233237 self ._trusted_set ["timestamp" ] = new_timestamp
234238 logger .debug ("Updated timestamp" )
235239
236240 def update_snapshot (self , data : bytes ):
237241 """Verifies and loads 'data' as new snapshot metadata.
238242
243+ Note that an expired intermediate snapshot is considered valid so it
244+ can be used for rollback checks on newer, final snapshot. Expiry is
245+ only checked for the final snapshot in update_delegated_targets().
246+
239247 Args:
240248 data: unverified new snapshot metadata as bytes
241249
@@ -250,6 +258,11 @@ def update_snapshot(self, data: bytes):
250258 raise RuntimeError ("Cannot update snapshot after targets" )
251259 logger .debug ("Updating snapshot" )
252260
261+ # Local timestamp was allowed to be expired to allow for rollback
262+ # checks on new timestamp but now timestamp must not be expired
263+ if self .timestamp .signed .is_expired (self .reference_time ):
264+ raise exceptions .ExpiredMetadataError ("timestamp.json is expired" )
265+
253266 meta = self .timestamp .signed .meta ["snapshot.json" ]
254267
255268 # Verify against the hashes in timestamp, if any
@@ -301,8 +314,8 @@ def update_snapshot(self, data: bytes):
301314 f"{ new_fileinfo .version } , got { fileinfo .version } ."
302315 )
303316
304- if new_snapshot . signed . is_expired ( self . reference_time ):
305- raise exceptions . ExpiredMetadataError ( "New snapshot is expired" )
317+ # expiry not checked to allow old snapshot to be used for rollback
318+ # protection of new snapshot: expiry is checked in update_targets( )
306319
307320 self ._trusted_set ["snapshot" ] = new_snapshot
308321 logger .debug ("Updated snapshot" )
@@ -336,6 +349,11 @@ def update_delegated_targets(
336349 if self .snapshot is None :
337350 raise RuntimeError ("Cannot load targets before snapshot" )
338351
352+ # Local snapshot was allowed to be expired to allow for rollback
353+ # checks on new snapshot but now snapshot must not be expired
354+ if self .snapshot .signed .is_expired (self .reference_time ):
355+ raise exceptions .ExpiredMetadataError ("snapshot.json is expired" )
356+
339357 delegator : Optional [Metadata ] = self .get (delegator_name )
340358 if delegator is None :
341359 raise RuntimeError ("Cannot load targets before delegator" )
0 commit comments