Skip to content

Make length and hashes optional for timestamp and snapshot roles #1031

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jul 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions tests/test_arbitrary_package_attack.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def test_without_tuf(self):
client_target_path = os.path.join(self.client_directory, 'file1.txt')
self.assertFalse(os.path.exists(client_target_path))
length, hashes = securesystemslib.util.get_file_details(target_path)
fileinfo = tuf.formats.make_fileinfo(length, hashes)
fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

url_prefix = self.repository_mirrors['mirror1']['url_prefix']
url_file = os.path.join(url_prefix, 'targets', 'file1.txt')
Expand All @@ -190,20 +190,20 @@ def test_without_tuf(self):

self.assertTrue(os.path.exists(client_target_path))
length, hashes = securesystemslib.util.get_file_details(client_target_path)
download_fileinfo = tuf.formats.make_fileinfo(length, hashes)
download_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)
self.assertEqual(fileinfo, download_fileinfo)

# Test: Download a target file that has been modified by an attacker.
with open(target_path, 'wt') as file_object:
file_object.write('add malicious content.')
length, hashes = securesystemslib.util.get_file_details(target_path)
malicious_fileinfo = tuf.formats.make_fileinfo(length, hashes)
malicious_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

# On Windows, the URL portion should not contain back slashes.
six.moves.urllib.request.urlretrieve(url_file.replace('\\', '/'), client_target_path)

length, hashes = securesystemslib.util.get_file_details(client_target_path)
download_fileinfo = tuf.formats.make_fileinfo(length, hashes)
download_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

# Verify 'download_fileinfo' is unequal to the original trusted version.
self.assertNotEqual(download_fileinfo, fileinfo)
Expand Down
14 changes: 7 additions & 7 deletions tests/test_endless_data_attack.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def test_without_tuf(self):
client_target_path = os.path.join(self.client_directory, 'file1.txt')
self.assertFalse(os.path.exists(client_target_path))
length, hashes = securesystemslib.util.get_file_details(target_path)
fileinfo = tuf.formats.make_fileinfo(length, hashes)
fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

url_prefix = self.repository_mirrors['mirror1']['url_prefix']
url_file = os.path.join(url_prefix, 'targets', 'file1.txt')
Expand All @@ -194,15 +194,15 @@ def test_without_tuf(self):

self.assertTrue(os.path.exists(client_target_path))
length, hashes = securesystemslib.util.get_file_details(client_target_path)
download_fileinfo = tuf.formats.make_fileinfo(length, hashes)
download_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)
self.assertEqual(fileinfo, download_fileinfo)

# Test: Download a target file that has been modified by an attacker with
# extra data.
with open(target_path, 'a') as file_object:
file_object.write('append large amount of data' * 100000)
large_length, hashes = securesystemslib.util.get_file_details(target_path)
malicious_fileinfo = tuf.formats.make_fileinfo(large_length, hashes)
malicious_fileinfo = tuf.formats.make_targets_fileinfo(large_length, hashes)

# Is the modified file actually larger?
self.assertTrue(large_length > length)
Expand All @@ -211,7 +211,7 @@ def test_without_tuf(self):
six.moves.urllib.request.urlretrieve(url_file.replace('\\', '/'), client_target_path)

length, hashes = securesystemslib.util.get_file_details(client_target_path)
download_fileinfo = tuf.formats.make_fileinfo(length, hashes)
download_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

# Verify 'download_fileinfo' is unequal to the original trusted version.
self.assertNotEqual(download_fileinfo, fileinfo)
Expand All @@ -235,10 +235,10 @@ def test_with_tuf(self):
# Verify the client's downloaded file matches the repository's.
target_path = os.path.join(self.repository_directory, 'targets', 'file1.txt')
length, hashes = securesystemslib.util.get_file_details(client_target_path)
fileinfo = tuf.formats.make_fileinfo(length, hashes)
fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

length, hashes = securesystemslib.util.get_file_details(client_target_path)
download_fileinfo = tuf.formats.make_fileinfo(length, hashes)
download_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)
self.assertEqual(fileinfo, download_fileinfo)

# Modify 'file1.txt' and confirm that the TUF client only downloads up to
Expand All @@ -257,7 +257,7 @@ def test_with_tuf(self):
# extra data appended should be discarded by the client, so the downloaded
# file size and hash should not have changed.
length, hashes = securesystemslib.util.get_file_details(client_target_path)
download_fileinfo = tuf.formats.make_fileinfo(length, hashes)
download_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)
self.assertEqual(fileinfo, download_fileinfo)

# Test that the TUF client does not download large metadata files, as well.
Expand Down
72 changes: 55 additions & 17 deletions tests/test_formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,15 @@ def test_schemas(self):
'keyval': {'public': 'pubkey',
'private': 'privkey'}}),

'FILEINFO_SCHEMA': (tuf.formats.FILEINFO_SCHEMA,
{'length': 1024,
'hashes': {'sha256': 'A4582BCF323BCEF'},
'custom': {'type': 'paintjob'}}),
'TARGETS_FILEINFO_SCHEMA': (tuf.formats.TARGETS_FILEINFO_SCHEMA,
{'length': 1024,
'hashes': {'sha256': 'A4582BCF323BCEF'},
'custom': {'type': 'paintjob'}}),

'METADATA_FILEINFO_SCHEMA': (tuf.formats.METADATA_FILEINFO_SCHEMA,
{'length': 1024,
'hashes': {'sha256': 'A4582BCF323BCEF'},
'version': 1}),

'FILEDICT_SCHEMA': (tuf.formats.FILEDICT_SCHEMA,
{'metadata/root.json': {'length': 1024,
Expand Down Expand Up @@ -241,7 +246,8 @@ def test_schemas(self):
'version': 8,
'expires': '1985-10-21T13:20:00Z',
'meta': {'metadattimestamp.json': {'length': 1024,
'hashes': {'sha256': 'AB1245'}}}}),
'hashes': {'sha256': 'AB1245'},
'version': 1}}}),

'MIRROR_SCHEMA': (tuf.formats.MIRROR_SCHEMA,
{'url_prefix': 'http://localhost:8001',
Expand Down Expand Up @@ -394,7 +400,7 @@ def test_build_dict_conforming_to_schema(self):
length = 88
hashes = {'sha256': '3c7fe3eeded4a34'}
expires = '1985-10-21T13:20:00Z'
filedict = {'snapshot.json': {'length': length, 'hashes': hashes}}
filedict = {'snapshot.json': {'length': length, 'hashes': hashes, 'version': 1}}


# Try with and without _type and spec_version, both of which are
Expand Down Expand Up @@ -797,28 +803,60 @@ def test_make_signable(self):



def test_make_fileinfo(self):
def test_make_targets_fileinfo(self):
# Test conditions for valid arguments.
length = 1024
hashes = {'sha256': 'A4582BCF323BCEF', 'sha512': 'A4582BCF323BFEF'}
version = 8
custom = {'type': 'paintjob'}

FILEINFO_SCHEMA = tuf.formats.FILEINFO_SCHEMA
make_fileinfo = tuf.formats.make_fileinfo
self.assertTrue(FILEINFO_SCHEMA.matches(make_fileinfo(length, hashes, version, custom)))
self.assertTrue(FILEINFO_SCHEMA.matches(make_fileinfo(length, hashes)))
TARGETS_FILEINFO_SCHEMA = tuf.formats.TARGETS_FILEINFO_SCHEMA
make_targets_fileinfo = tuf.formats.make_targets_fileinfo
self.assertTrue(TARGETS_FILEINFO_SCHEMA.matches(make_targets_fileinfo(length, hashes, custom)))
self.assertTrue(TARGETS_FILEINFO_SCHEMA.matches(make_targets_fileinfo(length, hashes)))

# Test conditions for invalid arguments.
bad_length = 'bad'
bad_hashes = 'bad'
bad_custom = 'bad'

self.assertRaises(securesystemslib.exceptions.FormatError, make_fileinfo, bad_length, hashes, custom)
self.assertRaises(securesystemslib.exceptions.FormatError, make_fileinfo, length, bad_hashes, custom)
self.assertRaises(securesystemslib.exceptions.FormatError, make_fileinfo, length, hashes, bad_custom)
self.assertRaises(securesystemslib.exceptions.FormatError, make_fileinfo, bad_length, hashes)
self.assertRaises(securesystemslib.exceptions.FormatError, make_fileinfo, length, bad_hashes)
self.assertRaises(securesystemslib.exceptions.FormatError, make_targets_fileinfo,
bad_length, hashes, custom)
self.assertRaises(securesystemslib.exceptions.FormatError, make_targets_fileinfo,
length, bad_hashes, custom)
self.assertRaises(securesystemslib.exceptions.FormatError, make_targets_fileinfo,
length, hashes, bad_custom)
self.assertRaises(securesystemslib.exceptions.FormatError, make_targets_fileinfo,
bad_length, hashes)
self.assertRaises(securesystemslib.exceptions.FormatError, make_targets_fileinfo,
length, bad_hashes)



def test_make_metadata_fileinfo(self):
# Test conditions for valid arguments.
length = 1024
hashes = {'sha256': 'A4582BCF323BCEF', 'sha512': 'A4582BCF323BFEF'}
version = 8

METADATA_FILEINFO_SCHEMA = tuf.formats.METADATA_FILEINFO_SCHEMA
make_metadata_fileinfo = tuf.formats.make_metadata_fileinfo
self.assertTrue(METADATA_FILEINFO_SCHEMA.matches(make_metadata_fileinfo(
version, length, hashes)))
self.assertTrue(METADATA_FILEINFO_SCHEMA.matches(make_metadata_fileinfo(version)))

# Test conditions for invalid arguments.
bad_version = 'bad'
bad_length = 'bad'
bad_hashes = 'bad'

self.assertRaises(securesystemslib.exceptions.FormatError, make_metadata_fileinfo,
bad_version, length, hashes)
self.assertRaises(securesystemslib.exceptions.FormatError, make_metadata_fileinfo,
version, bad_length, hashes)
self.assertRaises(securesystemslib.exceptions.FormatError, make_metadata_fileinfo,
version, length, bad_hashes)
self.assertRaises(securesystemslib.exceptions.FormatError, make_metadata_fileinfo,
bad_version)



Expand Down
4 changes: 2 additions & 2 deletions tests/test_indefinite_freeze_attack.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,15 +230,15 @@ def test_without_tuf(self):
shutil.copy(timestamp_path, client_timestamp_path)

length, hashes = securesystemslib.util.get_file_details(timestamp_path)
fileinfo = tuf.formats.make_fileinfo(length, hashes)
fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

url_prefix = self.repository_mirrors['mirror1']['url_prefix']
url_file = os.path.join(url_prefix, 'metadata', 'timestamp.json')

six.moves.urllib.request.urlretrieve(url_file.replace('\\', '/'), client_timestamp_path)

length, hashes = securesystemslib.util.get_file_details(client_timestamp_path)
download_fileinfo = tuf.formats.make_fileinfo(length, hashes)
download_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

# Verify 'download_fileinfo' is equal to the current local file.
self.assertEqual(download_fileinfo, fileinfo)
Expand Down
14 changes: 7 additions & 7 deletions tests/test_replay_attack.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def test_without_tuf(self):
# The fileinfo of the previous version is saved to verify that it is indeed
# accepted by the non-TUF client.
length, hashes = securesystemslib.util.get_file_details(backup_timestamp)
previous_fileinfo = tuf.formats.make_fileinfo(length, hashes)
previous_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

# Modify the timestamp file on the remote repository.
repository = repo_tool.load_repository(self.repository_directory)
Expand All @@ -227,7 +227,7 @@ def test_without_tuf(self):
# Save the fileinfo of the new version generated to verify that it is
# saved by the client.
length, hashes = securesystemslib.util.get_file_details(timestamp_path)
new_fileinfo = tuf.formats.make_fileinfo(length, hashes)
new_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

url_prefix = self.repository_mirrors['mirror1']['url_prefix']
url_file = os.path.join(url_prefix, 'metadata', 'timestamp.json')
Expand All @@ -238,7 +238,7 @@ def test_without_tuf(self):
six.moves.urllib.request.urlretrieve(url_file.replace('\\', '/'), client_timestamp_path)

length, hashes = securesystemslib.util.get_file_details(client_timestamp_path)
download_fileinfo = tuf.formats.make_fileinfo(length, hashes)
download_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

# Verify 'download_fileinfo' is equal to the new version.
self.assertEqual(download_fileinfo, new_fileinfo)
Expand All @@ -251,7 +251,7 @@ def test_without_tuf(self):
six.moves.urllib.request.urlretrieve(url_file.replace('\\', '/'), client_timestamp_path)

length, hashes = securesystemslib.util.get_file_details(client_timestamp_path)
download_fileinfo = tuf.formats.make_fileinfo(length, hashes)
download_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

# Verify 'download_fileinfo' is equal to the previous version.
self.assertEqual(download_fileinfo, previous_fileinfo)
Expand All @@ -278,7 +278,7 @@ def test_with_tuf(self):
# The fileinfo of the previous version is saved to verify that it is indeed
# accepted by the non-TUF client.
length, hashes = securesystemslib.util.get_file_details(backup_timestamp)
previous_fileinfo = tuf.formats.make_fileinfo(length, hashes)
previous_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

# Modify the timestamp file on the remote repository.
repository = repo_tool.load_repository(self.repository_directory)
Expand All @@ -300,7 +300,7 @@ def test_with_tuf(self):
# Save the fileinfo of the new version generated to verify that it is
# saved by the client.
length, hashes = securesystemslib.util.get_file_details(timestamp_path)
new_fileinfo = tuf.formats.make_fileinfo(length, hashes)
new_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

# Refresh top-level metadata, including 'timestamp.json'. Installation of
# new version of 'timestamp.json' is expected.
Expand All @@ -309,7 +309,7 @@ def test_with_tuf(self):
client_timestamp_path = os.path.join(self.client_directory,
self.repository_name, 'metadata', 'current', 'timestamp.json')
length, hashes = securesystemslib.util.get_file_details(client_timestamp_path)
download_fileinfo = tuf.formats.make_fileinfo(length, hashes)
download_fileinfo = tuf.formats.make_targets_fileinfo(length, hashes)

# Verify 'download_fileinfo' is equal to the new version.
self.assertEqual(download_fileinfo, new_fileinfo)
Expand Down
Loading