mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
Merge pull request #651 from vladimir-v-diaz/develop
CLI: Implement --trust option
This commit is contained in:
commit
bacb4e3d69
2 changed files with 106 additions and 21 deletions
46
docs/CLI.md
46
docs/CLI.md
|
|
@ -1,4 +1,4 @@
|
|||
# CLI examples #
|
||||
# CLI #
|
||||
|
||||
Note: This is a work in progress and subject to change.
|
||||
|
||||
|
|
@ -45,6 +45,7 @@ $ repo.py --init --consistent_snapshot
|
|||
|
||||
|
||||
|
||||
|
||||
## Add a target file ##
|
||||
|
||||
Copy a target file to the repo and add it to the Targets metadata (or the
|
||||
|
|
@ -81,7 +82,7 @@ Remove all target files, that match `foo*.tgz,` from the Targets metadata.
|
|||
$ repo.py --remove "foo*.tgz"
|
||||
```
|
||||
|
||||
Remove all target files from the `my_role` Targets metadata.
|
||||
Remove all target files from the `my_role` metadata.
|
||||
```Bash
|
||||
$ repo.py --remove "*" --role my_role --sign tufkeystore/my_role_key
|
||||
```
|
||||
|
|
@ -94,24 +95,46 @@ specific metadata with `--sign`. The supported key types are: `ecdsa`,
|
|||
```Bash
|
||||
$ repo.py --key
|
||||
$ repo.py --key <keytype>
|
||||
$ repo.py --key <keytype> --path </path/to/repo_dir> --pw [my_password], --filename <key_filename>
|
||||
$ repo.py --key <keytype> [--path </path/to/repo_dir> --pw [my_password], --filename <key_filename>]
|
||||
```
|
||||
|
||||
Instead of using some default password, the user can enter one on the command
|
||||
line or be prompted for it via password masking.
|
||||
```Bash
|
||||
$ repo.py --key ... --pw my_password
|
||||
$ repo.py --key ed25519 --pw my_password
|
||||
```
|
||||
|
||||
```Bash
|
||||
$ repo.py --key ... --pw
|
||||
$ repo.py --key rsa --pw
|
||||
Enter a password for the top-level role keys:
|
||||
Confirm:
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Trust keys ##
|
||||
|
||||
The Root role specifies the trusted keys of the top-level roles, including
|
||||
itself. The --trust command-line option, in conjunction with --pubkeys and
|
||||
--role, can be used to indicate the trusted keys of a role.
|
||||
|
||||
```Bash
|
||||
$ repo.py --trust --pubkeys --role
|
||||
```
|
||||
|
||||
For example:
|
||||
```Bash
|
||||
$ repo.py --init --bare
|
||||
$ repo.py --trust --pubkeys keystore/my_key.pub keystore/my_key_too.pub --role root
|
||||
```
|
||||
|
||||
Note: This action replaces any previously trusted keys that might have been
|
||||
specified for --role.
|
||||
|
||||
|
||||
|
||||
## Sign metadata ##
|
||||
Sign, using the specified key, the metadata of the role indicated by --role
|
||||
Sign, using the specified key, the metadata of the role indicated in --role
|
||||
(must be Targets or a delegated role). If no key argument or --role is given,
|
||||
the Targets role or its key is used. The Snapshot and Timestamp role are also
|
||||
automatically signed, if possible.
|
||||
|
|
@ -120,7 +143,7 @@ $ repo.py --sign
|
|||
$ repo.py --sign </path/to/key> [--role <rolename>, --path </path/to/repo>]
|
||||
```
|
||||
|
||||
For example, to sign new Timestamp metadata:
|
||||
For example, to sign the delegated `foo` metadata:
|
||||
```Bash
|
||||
$ repo.py --sign /path/to/foo_key --role foo
|
||||
```
|
||||
|
|
@ -130,14 +153,15 @@ signing of Snapshot and Timestamp metadata.
|
|||
|
||||
|
||||
|
||||
## Delegate trust ##
|
||||
## Delegation ##
|
||||
|
||||
Delegate trust of target files from the targets role (or the one specified
|
||||
Delegate trust of target files from the Targets role (or the one specified
|
||||
in --role) to some other role (--delegatee). --delegatee is trusted to
|
||||
sign for target files that match the delegated glob patterns.
|
||||
|
||||
```Bash
|
||||
$ repo.py --delegate <glob pattern> ... --delegatee <rolename> --pubkeys
|
||||
</path/to/pubkey.pub>... [--role <rolename> --terminating --threshold <X>
|
||||
</path/to/pubkey.pub> ... [--role <rolename> --terminating --threshold <X>
|
||||
--sign </path/to/role_privkey>]
|
||||
```
|
||||
|
||||
|
|
@ -149,7 +173,7 @@ $ repo.py --delegate "/foo*.tgz" --delegatee foo --pubkeys ./keystore/foo.pub
|
|||
|
||||
|
||||
|
||||
## Revoke trust ##
|
||||
## Revocation ##
|
||||
|
||||
Revoke trust of target files from a delegated role (--delegatee). The
|
||||
"targets" role performs the revocation if --role is not specified.
|
||||
|
|
|
|||
|
|
@ -25,14 +25,25 @@
|
|||
<Usage>
|
||||
Note: arguments within brackets are optional.
|
||||
|
||||
$ repo.py --init [--consistent_snapshot, --bare, --path]
|
||||
$ repo.py --init
|
||||
[--consistent_snapshot, --bare, --path, --root_pw, --targets_pw,
|
||||
--snapshot_pw, --timestamp_pw]
|
||||
$ repo.py --add <target> <dir> ... [--path, --recursive]
|
||||
$ repo.py --remove <glob pattern>
|
||||
$ repo.py --trust --pubkeys </path/to/pubkey> [--role]
|
||||
$ repo.py --sign </path/to/key> [--role <targets>]
|
||||
$ repo.py --key <keytype> [--filename <filename>
|
||||
$ repo.py --key <keytype>
|
||||
[--filename <filename>
|
||||
--path </path/to/repo>, --pw [my_password]]
|
||||
$ repo.py --delegate <glob pattern> ... --role <rolename>
|
||||
--delegatee <rolename> --terminating --threshold <X>
|
||||
--keys </path/to/pubkey> --sign </path/to/role_privkey>
|
||||
|
||||
$ repo.py --delegate <glob pattern> --delegatee <rolename>
|
||||
--pubkeys </path/to/pubkey>
|
||||
[role <rolename> --terminating --threshold <X>
|
||||
--sign </path/to/role_privkey>]
|
||||
|
||||
$ repo.py --revoke --delegatee <rolename>
|
||||
[--role <rolename> --sign </path/to/role_privkey>]
|
||||
|
||||
$ repo.py --verbose
|
||||
$ repo.py --clean [--path]
|
||||
"""
|
||||
|
|
@ -128,6 +139,9 @@ def process_arguments(parsed_arguments):
|
|||
if parsed_arguments.remove:
|
||||
remove_targets(parsed_arguments)
|
||||
|
||||
if parsed_arguments.trust:
|
||||
add_verification_key(parsed_arguments)
|
||||
|
||||
if parsed_arguments.sign:
|
||||
sign_role(parsed_arguments)
|
||||
|
||||
|
|
@ -158,7 +172,6 @@ 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 = import_publickey_from_file(
|
||||
public_key)
|
||||
public_keys.append(imported_pubkey)
|
||||
|
|
@ -320,12 +333,22 @@ def import_privatekey_from_file(keypath, password=None):
|
|||
# the derived encryption key from 'password'. Raise
|
||||
# 'securesystemslib.exceptions.CryptoError' if the decryption fails.
|
||||
try:
|
||||
|
||||
key_object = securesystemslib.keys.decrypt_key(encrypted_key.decode('utf-8'),
|
||||
password)
|
||||
|
||||
except securesystemslib.exceptions.CryptoError:
|
||||
key_object = securesystemslib.keys.import_rsakey_from_private_pem(
|
||||
encrypted_key, 'rsassa-pss-sha256', password)
|
||||
try:
|
||||
logger.debug(
|
||||
'Decryption failsed. Attempting to import a private PEM instead.')
|
||||
key_object = securesystemslib.keys.import_rsakey_from_private_pem(
|
||||
encrypted_key, 'rsassa-pss-sha256', password)
|
||||
|
||||
except securesystemslib.exceptions.CryptoError as e:
|
||||
raise tuf.exceptions.Error(repr(keypath) + ' cannot be imported, possibly'
|
||||
' because the decryption password is incorrect. Encryption'
|
||||
' passwords can be specified via the --root_pw, --targets_pw,'
|
||||
' --snapshot_pw, and --timestamp_pw command-line options.')
|
||||
|
||||
if key_object['keytype'] not in SUPPORTED_KEY_TYPES:
|
||||
raise tuf.exceptions.Error('Trying to import an unsupported key'
|
||||
|
|
@ -356,6 +379,40 @@ def import_publickey_from_file(keypath):
|
|||
|
||||
|
||||
|
||||
def add_verification_key(parsed_arguments):
|
||||
if not parsed_arguments.pubkeys:
|
||||
raise tuf.exception.Error('--pubkeys must be given with --trust.')
|
||||
|
||||
repository = repo_tool.load_repository(
|
||||
os.path.join(parsed_arguments.path, REPO_DIR))
|
||||
|
||||
for keypath in parsed_arguments.pubkeys:
|
||||
imported_pubkey = import_publickey_from_file(keypath)
|
||||
|
||||
if parsed_arguments.role == 'root':
|
||||
repository.root.add_verification_key(imported_pubkey)
|
||||
|
||||
elif parsed_arguments.role == 'targets':
|
||||
repository.targets.add_verification_key(imported_pubkey)
|
||||
|
||||
elif parsed_arguments.role == 'snapshot':
|
||||
repository.snapshot.add_verification_key(imported_pubkey)
|
||||
|
||||
elif parsed_arguments.role == 'timestamp':
|
||||
repository.timestamp.add_verification_key(imported_pubkey)
|
||||
|
||||
else:
|
||||
raise tuf.exception.Error('The given --role is not a top-level role.')
|
||||
|
||||
repository.write('root', increment_version_number=False)
|
||||
|
||||
# Move staged metadata directory to "live" metadata directory.
|
||||
write_to_live_repo()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def sign_role(parsed_arguments):
|
||||
|
||||
repository = repo_tool.load_repository(
|
||||
|
|
@ -378,7 +435,7 @@ def sign_role(parsed_arguments):
|
|||
pass
|
||||
|
||||
else:
|
||||
# TODO: The repository tool will be refactored to clean up the following
|
||||
# TODO: repository_tool.py 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):
|
||||
|
||||
|
|
@ -476,7 +533,7 @@ def add_target_to_repo(target_path, repo_targets_path, repository, custom=None):
|
|||
|
||||
else:
|
||||
logger.debug('Replacing target: ' + repr(target_path))
|
||||
roleinfo['paths'].update({relative_path: custom})
|
||||
roleinfo['paths'].update({target_path: custom})
|
||||
|
||||
tuf.roledb.update_roleinfo(parsed_arguments.role, roleinfo,
|
||||
mark_role_as_dirty=True, repository_name=repository._repository_name)
|
||||
|
|
@ -796,6 +853,10 @@ def parse_arguments():
|
|||
metavar='<filename>', help='Specify a filename. This option can'
|
||||
' be used to name a generated key file.')
|
||||
|
||||
parser.add_argument('--trust', action='store_true',
|
||||
help='Indicate the trusted key(s) (via --pubkeys) for the role in --role.'
|
||||
' This action modifies Root metadata with the trusted key(s).')
|
||||
|
||||
parser.add_argument('--sign', nargs='?', type=str, const='.',
|
||||
default=None, metavar='</path/to/privkey>', help='Sign the "targets"'
|
||||
' metadata (or the one for --role) with the specified key.')
|
||||
|
|
|
|||
Loading…
Reference in a new issue