From 1d46c936244435d170c3d625dfd1de6d77677871 Mon Sep 17 00:00:00 2001 From: Vladimir Diaz Date: Mon, 5 Mar 2018 16:39:44 -0500 Subject: [PATCH 1/5] Allow 2+ role to delegate to the same role Signed-off-by: Vladimir Diaz --- tuf/repository_tool.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tuf/repository_tool.py b/tuf/repository_tool.py index 673941f3..abeaa1e9 100755 --- a/tuf/repository_tool.py +++ b/tuf/repository_tool.py @@ -2233,11 +2233,6 @@ def delegate(self, rolename, public_keys, paths, threshold=1, if path_hash_prefixes is not None: securesystemslib.formats.PATH_HASH_PREFIXES_SCHEMA.check_match(path_hash_prefixes) - # Check if 'rolename' is not already a delegation. - if tuf.roledb.role_exists(rolename, self._repository_name): - raise securesystemslib.exceptions.Error(repr(rolename) + ' already' - ' delegated.') - # Keep track of the valid keyids (added to the new Targets object) and # their keydicts (added to this Targets delegations). keyids = [] From 2d3a4193647877715d87decb5ba09467bdf5d7e4 Mon Sep 17 00:00:00 2001 From: Vladimir Diaz Date: Mon, 5 Mar 2018 16:41:02 -0500 Subject: [PATCH 2/5] Revise CLI.md Signed-off-by: Vladimir Diaz --- docs/CLI.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index c34b891f..3df06d9f 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -86,14 +86,12 @@ the Targets role or its key is used. The Snapshot and Timestamp role are also automatically signed, if possible. ```Bash $ repo.py --sign -$ repo.py --sign -$ repo.py --sign [--role ] $ repo.py --sign [--role , --path ] ``` For example, to sign new Timestamp metadata: ```Bash -$ repo.py --sign /path/to/timestamp_key --role timestamp +$ repo.py --sign /path/to/foo_key --role foo ``` Note: In the future, the user might have the option of disabling automatic @@ -112,7 +110,8 @@ $ repo.py --delegate ... --delegatee --pubkeys --sign ] ``` -Example: +For example, to delegate trust of `/foo*.gz` packages to the `foo` role: + ``` $ repo.py --delegate "/foo*.tgz" --delegatee foo --pubkeys ./keystore/foo.pub ``` From c269d4784a0a4548deed6b55179c4a15f5b0ac04 Mon Sep 17 00:00:00 2001 From: Vladimir Diaz Date: Mon, 5 Mar 2018 16:47:55 -0500 Subject: [PATCH 3/5] Support import of any key type, and sign fresh metadata Signed-off-by: Vladimir Diaz --- tuf/scripts/repo.py | 55 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/tuf/scripts/repo.py b/tuf/scripts/repo.py index 236d0b5d..d7eab06d 100755 --- a/tuf/scripts/repo.py +++ b/tuf/scripts/repo.py @@ -52,6 +52,7 @@ import shutil import errno import getpass +import time import tuf import tuf.log @@ -147,7 +148,7 @@ def delegate(parsed_arguments): public_keys = [] for public_key in parsed_arguments.pubkeys: # In the future, any type of key can be imported... - imported_pubkey = repo_tool.import_ecdsa_publickey_from_file( + imported_pubkey = import_publickey_from_file( public_key) public_keys.append(imported_pubkey) @@ -329,6 +330,21 @@ def import_privatekey_from_file(keypath, password=None): +def import_publickey_from_file(keypath): + + key_metadata = securesystemslib.util.load_json_file(keypath) + key_object, junk = securesystemslib.keys.format_metadata_to_key(key_metadata) + + if key_object['keytype'] not in SUPPORTED_KEY_TYPES: + raise tuf.exceptions.Error('Trying to import an unsupported key' + ' type: ' + repr(key_object['keytype'] + '.' + ' Supported key types: ' + repr(SUPPORTED_KEY_TYPES))) + + else: + return key_object + + + def sign_role(parsed_arguments): repository = repo_tool.load_repository( @@ -351,7 +367,34 @@ def sign_role(parsed_arguments): pass else: - repository.targets(parsed_arguments.role).load_signing_key(role_privatekey) + # TODO: The repository tool will be refactored to clean up the following + # approach, which adds and signs for a non-existent role. + if not tuf.roledb.role_exists(parsed_arguments.role): + + # Load the private key keydb and set the roleinfo in roledb so that + # metadata can be written with repository.write(). + try: + tuf.keydb.add_key( + role_privatekey, repository_name = repository._repository_name) + + except securesystemslib.exceptions.KeyAlreadyExistsError: + pass + + expiration = tuf.formats.unix_timestamp_to_datetime( + int(time.time() + 7889230)) + expiration = expiration.isoformat() + 'Z' + + roleinfo = {'name': parsed_arguments.role, 'keyids': [], + 'signing_keyids': [role_privatekey['keyid']], 'partial_loaded': False, 'paths': {}, + 'signatures': [], 'version': 1, 'expires': expiration, + 'delegations': {'keys': {}, 'roles': []}} + + tuf.roledb.add_role(parsed_arguments.role, roleinfo, + repository_name=repository._repository_name) + repository.write(parsed_arguments.role, increment_version_number=False) + + else: + repository.targets(parsed_arguments.role).load_signing_key(role_privatekey) # Update the required top-level roles, Snapshot and Timestamp, to make a new # release. @@ -523,16 +566,16 @@ def set_top_level_keys(repository): # Import the public keys. They are needed so that metadata roles are # assigned verification keys, which clients need in order to verify the # signatures created by the corresponding private keys. - root_public = repo_tool.import_ecdsa_publickey_from_file( + root_public = import_publickey_from_file( os.path.join(parsed_arguments.path, KEYSTORE_DIR, ROOT_KEY_NAME) + '.pub') - targets_public = repo_tool.import_ecdsa_publickey_from_file( + targets_public = import_publickey_from_file( os.path.join(parsed_arguments.path, KEYSTORE_DIR, TARGETS_KEY_NAME) + '.pub') - snapshot_public = repo_tool.import_ecdsa_publickey_from_file( + snapshot_public = import_publickey_from_file( os.path.join(parsed_arguments.path, KEYSTORE_DIR, SNAPSHOT_KEY_NAME) + '.pub') - timestamp_public = repo_tool.import_ecdsa_publickey_from_file( + timestamp_public = import_publickey_from_file( os.path.join(parsed_arguments.path, KEYSTORE_DIR, TIMESTAMP_KEY_NAME) + '.pub') From b68ad48cb14f0afd590cb4090051eea076aef789 Mon Sep 17 00:00:00 2001 From: Vladimir Diaz Date: Mon, 5 Mar 2018 17:24:27 -0500 Subject: [PATCH 4/5] Make sure private key is loaded with --sign Signed-off-by: Vladimir Diaz --- tuf/scripts/repo.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tuf/scripts/repo.py b/tuf/scripts/repo.py index d7eab06d..a5facafd 100755 --- a/tuf/scripts/repo.py +++ b/tuf/scripts/repo.py @@ -373,18 +373,16 @@ def sign_role(parsed_arguments): # Load the private key keydb and set the roleinfo in roledb so that # metadata can be written with repository.write(). - try: - tuf.keydb.add_key( - role_privatekey, repository_name = repository._repository_name) - - except securesystemslib.exceptions.KeyAlreadyExistsError: - pass + tuf.keydb.remove_key(role_privatekey['keyid'], + repository_name = repository._repository_name) + tuf.keydb.add_key( + role_privatekey, repository_name = repository._repository_name) expiration = tuf.formats.unix_timestamp_to_datetime( int(time.time() + 7889230)) expiration = expiration.isoformat() + 'Z' - roleinfo = {'name': parsed_arguments.role, 'keyids': [], + roleinfo = {'name': parsed_arguments.role, 'keyids': [role_privatekey['keyid']], 'signing_keyids': [role_privatekey['keyid']], 'partial_loaded': False, 'paths': {}, 'signatures': [], 'version': 1, 'expires': expiration, 'delegations': {'keys': {}, 'roles': []}} From b7cb025eae6f86ee8ee4537bbc04e7d3da39441a Mon Sep 17 00:00:00 2001 From: Vladimir Diaz Date: Tue, 6 Mar 2018 10:15:22 -0500 Subject: [PATCH 5/5] Remove test condition for delegation to 2+ roles Signed-off-by: Vladimir Diaz --- tests/test_repository_tool.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/test_repository_tool.py b/tests/test_repository_tool.py index 0bf8b318..7d2e6e6c 100755 --- a/tests/test_repository_tool.py +++ b/tests/test_repository_tool.py @@ -1189,12 +1189,6 @@ def test_delegate(self): self.assertEqual(self.targets_object.get_delegated_rolenames(), ['tuf']) - # Try to delegate to a role that has already been delegated. - self.assertRaises(securesystemslib.exceptions.Error, - self.targets_object.delegate, rolename, public_keys, paths, threshold, - terminating=False, list_of_targets=list_of_targets, - path_hash_prefixes=path_hash_prefixes) - # Test for targets that do not exist under the targets directory. self.targets_object.revoke(rolename) self.assertRaises(securesystemslib.exceptions.Error,