4444from __future__ import division
4545from __future__ import unicode_literals
4646
47+ import datetime
4748import os
4849import time
4950import tempfile
5354import unittest
5455import sys
5556
57+ if sys .version_info >= (3 , 3 ):
58+ import unittest .mock as mock
59+ else :
60+ import mock
61+
5662import tuf .formats
5763import tuf .log
5864import tuf .client .updater as updater
@@ -265,8 +271,7 @@ def test_with_tuf(self):
265271 # Load the repository
266272 repository = repo_tool .load_repository (self .repository_directory )
267273
268- # Load the timestamp and snapshot keys, since we will be signing a new
269- # timestamp and a new snapshot file.
274+ # Load the snapshot and timestamp keys
270275 key_file = os .path .join (self .keystore_directory , 'timestamp_key' )
271276 timestamp_private = repo_tool .import_ed25519_privatekey_from_file (key_file ,
272277 'password' )
@@ -276,17 +281,11 @@ def test_with_tuf(self):
276281 'password' )
277282 repository .snapshot .load_signing_key (snapshot_private )
278283
279- # Expire snapshot in 10s. This should be far enough into the future that we
280- # haven't reached it before the first refresh validates timestamp expiry.
281- # We want a successful refresh before expiry, then a second refresh after
282- # expiry (which we then expect to raise an exception due to expired
283- # metadata).
284- expiry_time = time .time () + 10
285- datetime_object = tuf .formats .unix_timestamp_to_datetime (int (expiry_time ))
286-
287- repository .snapshot .expiration = datetime_object
288-
289- # Now write to the repository.
284+ # sign snapshot with expiry in near future (earlier than e.g. timestamp)
285+ expiry = int (time .time () + 60 * 60 )
286+ repository .snapshot .expiration = tuf .formats .unix_timestamp_to_datetime (
287+ expiry )
288+ repository .mark_dirty (['snapshot' , 'timestamp' ])
290289 repository .writeall ()
291290
292291 # And move the staged metadata to the "live" metadata.
@@ -297,30 +296,24 @@ def test_with_tuf(self):
297296 # Refresh metadata on the client. For this refresh, all data is not expired.
298297 logger .info ('Test: Refreshing #1 - Initial metadata refresh occurring.' )
299298 self .repository_updater .refresh ()
300- logger .info ('Test: Refreshed #1 - Initial metadata refresh completed '
301- 'successfully. Now sleeping until snapshot metadata expires.' )
302-
303- # Sleep until expiry_time ('repository.snapshot.expiration')
304- time .sleep (max (0 , expiry_time - time .time () + 1 ))
305-
306- logger .info ('Test: Refreshing #2 - Now trying to refresh again after local'
307- ' snapshot expiry.' )
308299
309- try :
310- self .repository_updater .refresh () # We expect this to fail!
300+ logger .info ('Test: Refreshing #2 - refresh after local snapshot expiry.' )
311301
312- except tuf .exceptions .ExpiredMetadataError :
313- logger .info ('Test: Refresh #2 - failed as expected. Expired local'
314- ' snapshot case generated a tuf.exceptions.ExpiredMetadataError'
315- ' exception as expected. Test pass.' )
302+ # mock current time to one second after snapshot expiry
303+ mock_time = mock .Mock ()
304+ mock_time .return_value = expiry + 1
305+ with mock .patch ('time.time' , mock_time ):
306+ try :
307+ self .repository_updater .refresh () # We expect this to fail!
316308
317- # I think that I only expect tuf.ExpiredMetadata error here. A
318- # NoWorkingMirrorError indicates something else in this case - unavailable
319- # repo, for example.
320- else :
309+ except tuf .exceptions . ExpiredMetadataError :
310+ logger . info ( 'Test: Refresh #2 - failed as expected. Expired local'
311+ ' snapshot case generated a tuf.exceptions.ExpiredMetadataError'
312+ ' exception as expected. Test pass.' )
321313
322- self .fail ('TUF failed to detect expired stale snapshot metadata. Freeze'
323- ' attack successful.' )
314+ else :
315+ self .fail ('TUF failed to detect expired stale snapshot metadata. Freeze'
316+ ' attack successful.' )
324317
325318
326319
@@ -355,7 +348,7 @@ def test_with_tuf(self):
355348 # We cannot set the timestamp expiration with
356349 # 'repository.timestamp.expiration = ...' with already-expired timestamp
357350 # metadata because of consistency checks that occur during that assignment.
358- expiry_time = time .time () + 1
351+ expiry_time = time .time () + 60 * 60
359352 datetime_object = tuf .formats .unix_timestamp_to_datetime (int (expiry_time ))
360353 repository .timestamp .expiration = datetime_object
361354 repository .writeall ()
@@ -365,29 +358,21 @@ def test_with_tuf(self):
365358 shutil .copytree (os .path .join (self .repository_directory , 'metadata.staged' ),
366359 os .path .join (self .repository_directory , 'metadata' ))
367360
368- # Wait just long enough for the timestamp metadata (which is now both on
369- # the repository and on the client) to expire.
370- time .sleep (max (0 , expiry_time - time .time () + 1 ))
361+ # mock current time to one second after timestamp expiry
362+ mock_time = mock .Mock ()
363+ mock_time .return_value = expiry_time + 1
364+ with mock .patch ('time.time' , mock_time ):
365+ try :
366+ self .repository_updater .refresh () # We expect NoWorkingMirrorError.
371367
372- # Try to refresh top-level metadata on the client. Since we're already past
373- # 'repository.timestamp.expiration', the TUF client is expected to detect
374- # that timestamp metadata is outdated and refuse to continue the update
375- # process.
376- try :
377- self .repository_updater .refresh () # We expect NoWorkingMirrorError.
368+ except tuf .exceptions .NoWorkingMirrorError as e :
369+ # Make sure the contained error is ExpiredMetadataError
370+ for mirror_url , mirror_error in six .iteritems (e .mirror_errors ):
371+ self .assertTrue (isinstance (mirror_error , tuf .exceptions .ExpiredMetadataError ))
378372
379- except tuf .exceptions .NoWorkingMirrorError as e :
380- # NoWorkingMirrorError indicates that we did not find valid, unexpired
381- # metadata at any mirror. That exception class preserves the errors from
382- # each mirror. We now assert that for each mirror, the particular error
383- # detected was that metadata was expired (the timestamp we manually
384- # expired).
385- for mirror_url , mirror_error in six .iteritems (e .mirror_errors ):
386- self .assertTrue (isinstance (mirror_error , tuf .exceptions .ExpiredMetadataError ))
387-
388- else :
389- self .fail ('TUF failed to detect expired, stale timestamp metadata.'
390- ' Freeze attack successful.' )
373+ else :
374+ self .fail ('TUF failed to detect expired, stale timestamp metadata.'
375+ ' Freeze attack successful.' )
391376
392377
393378
@@ -416,8 +401,8 @@ def test_with_tuf(self):
416401 # Set ts to expire in 1 month.
417402 ts_expiry_time = time .time () + 2630000
418403
419- # Set snapshot to expire in 1 second .
420- snapshot_expiry_time = time .time () + 1
404+ # Set snapshot to expire in 1 hour .
405+ snapshot_expiry_time = time .time () + 60 * 60
421406
422407 ts_datetime_object = tuf .formats .unix_timestamp_to_datetime (
423408 int (ts_expiry_time ))
@@ -432,28 +417,23 @@ def test_with_tuf(self):
432417 shutil .copytree (os .path .join (self .repository_directory , 'metadata.staged' ),
433418 os .path .join (self .repository_directory , 'metadata' ))
434419
435- # Wait just long enough for the Snapshot metadata (which is now on the
436- # repository) to expire.
437- time .sleep (max (0 , snapshot_expiry_time - time .time () + 1 ))
438-
439-
440- try :
441- # We expect the following refresh() to raise a NoWorkingMirrorError.
442- self .repository_updater .refresh ()
443-
444- except tuf .exceptions .NoWorkingMirrorError as e :
445- # NoWorkingMirrorError indicates that we did not find valid, unexpired
446- # metadata at any mirror. That exception class preserves the errors from
447- # each mirror. We now assert that for each mirror, the particular error
448- # detected was that metadata was expired (the Snapshot we manually
449- # expired).
450- for mirror_url , mirror_error in six .iteritems (e .mirror_errors ):
451- self .assertTrue (isinstance (mirror_error , tuf .exceptions .ExpiredMetadataError ))
452- self .assertTrue (mirror_url .endswith ('snapshot.json' ))
453-
454- else :
455- self .fail ('TUF failed to detect expired, stale Snapshot metadata.'
456- ' Freeze attack successful.' )
420+ # mock current time to one second after snapshot expiry
421+ mock_time = mock .Mock ()
422+ mock_time .return_value = snapshot_expiry_time + 1
423+ with mock .patch ('time.time' , mock_time ):
424+ try :
425+ # We expect the following refresh() to raise a NoWorkingMirrorError.
426+ self .repository_updater .refresh ()
427+
428+ except tuf .exceptions .NoWorkingMirrorError as e :
429+ # Make sure the contained error is ExpiredMetadataError
430+ for mirror_url , mirror_error in six .iteritems (e .mirror_errors ):
431+ self .assertTrue (isinstance (mirror_error , tuf .exceptions .ExpiredMetadataError ))
432+ self .assertTrue (mirror_url .endswith ('snapshot.json' ))
433+
434+ else :
435+ self .fail ('TUF failed to detect expired, stale Snapshot metadata.'
436+ ' Freeze attack successful.' )
457437
458438 # The client should have rejected the malicious Snapshot metadata, and
459439 # distrusted the local snapshot file that is no longer valid.
0 commit comments