Skip to content

Commit

Permalink
Merge pull request #1191 from lukpueh/adopt-sslib-interface-changes
Browse files Browse the repository at this point in the history
Adopt sslib keygen interface encryption changes
  • Loading branch information
lukpueh authored Nov 11, 2020
2 parents 201e07d + dc20fdb commit 11e2f4c
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 93 deletions.
79 changes: 34 additions & 45 deletions docs/TUTORIAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,15 @@ text without prepended symbols is the output of a command.
# following function creates an RSA key pair, where the private key is saved to
# "root_key" and the public key to "root_key.pub" (both saved to the current
# working directory).
>>> generate_and_write_rsa_keypair("root_key", bits=2048, password="password")
>>> generate_and_write_rsa_keypair(password="password", filepath="root_key", bits=2048)

# If the key length is unspecified, it defaults to 3072 bits. A length of less
# than 2048 bits raises an exception. A password may be supplied as an
# argument, otherwise a user prompt is presented. If an empty password
# is entered, the private key is saved unencrypted.
>>> generate_and_write_rsa_keypair("root_key2")
Enter a password for the RSA key (/path/to/root_key2):
# than 2048 bits raises an exception. A similar function is available to supply
# a password on the prompt. If an empty password is entered, the private key
# is saved unencrypted.
>>> generate_and_write_rsa_keypair_with_prompt(filepath="root_key2")
enter password to encrypt private key file '/path/to/root_key2'
(leave empty if key should not be encrypted):
Confirm:
```
The following four key files should now exist:
Expand All @@ -117,8 +118,9 @@ If a filepath is not given, the KEYID of the generated key is used as the
filename. The key files are written to the current working directory.
```python
# Continuing from the previous section . . .
>>> generate_and_write_rsa_keypair()
Enter a password for the encrypted RSA key (/path/to/b5b8de8aeda674bce948fbe82cab07e309d6775fc0ec299199d16746dc2bd54c):
>>> generate_and_write_rsa_keypair_with_prompt()
enter password to encrypt private key file '/path/to/KEYID'
(leave empty if key should not be encrypted):
Confirm:
```

Expand All @@ -132,36 +134,27 @@ Confirm:
# Import an existing private key. Importing a private key requires a password,
# whereas importing a public key does not.
>>> private_root_key = import_rsa_privatekey_from_file("root_key")
Enter a password for the encrypted RSA key (/path/to/root_key):
```

`import_rsa_privatekey_from_file()` raises a
`securesystemslib.exceptions.CryptoError` exception if the key / password is
invalid:

```
securesystemslib.exceptions.CryptoError: RSA (public, private) tuple cannot be
generated from the encrypted PEM string: Bad decrypt. Incorrect password?
enter password to decrypt private key file '/path/to/root_key'
(leave empty if key not encrypted):
```

### Create and Import Ed25519 Keys ###
```Python
# Continuing from the previous section . . .

# Generate and write an Ed25519 key pair. A 'password' argument may be
# supplied, otherwise a prompt is presented. The private key is saved
# encrypted if a non-empty password is given, and unencrypted if the password
# is empty.
>>> generate_and_write_ed25519_keypair('ed25519_key')
Enter a password for the Ed25519 key (/path/to/ed25519_key):
# The same generation and import functions as for rsa keys exist for ed25519
>>> generate_and_write_ed25519_keypair_with_prompt(filepath='ed25519_key')
enter password to encrypt private key file '/path/to/ed25519_key'
(leave empty if key should not be encrypted):
Confirm:

# Import the ed25519 public key just created . . .
>>> public_ed25519_key = import_ed25519_publickey_from_file('ed25519_key.pub')

# and its corresponding private key.
>>> private_ed25519_key = import_ed25519_privatekey_from_file('ed25519_key')
Enter a password for the encrypted Ed25519 key (/path/to/ed25519_key):
enter password to decrypt private key file '/path/to/ed25519_key'
(leave empty if key should not be encrypted):
```

Note: Methods are also available to generate and write keys from memory.
Expand Down Expand Up @@ -259,26 +252,20 @@ secure manner.
>>> import datetime

# Generate keys for the remaining top-level roles. The root keys have been set above.
# The password argument may be omitted if a password prompt is needed.
>>> generate_and_write_rsa_keypair('targets_key', password='password')
>>> generate_and_write_rsa_keypair('snapshot_key', password='password')
>>> generate_and_write_rsa_keypair('timestamp_key', password='password')
>>> generate_and_write_rsa_keypair(password='password', filepath='targets_key')
>>> generate_and_write_rsa_keypair(password='password', filepath='snapshot_key')
>>> generate_and_write_rsa_keypair(password='password', filepath='timestamp_key')

# Add the verification keys of the remaining top-level roles.

>>> repository.targets.add_verification_key(import_rsa_publickey_from_file('targets_key.pub'))
>>> repository.snapshot.add_verification_key(import_rsa_publickey_from_file('snapshot_key.pub'))
>>> repository.timestamp.add_verification_key(import_rsa_publickey_from_file('timestamp_key.pub'))

# Import the signing keys of the remaining top-level roles. Prompt for passwords.
>>> private_targets_key = import_rsa_privatekey_from_file('targets_key')
Enter a password for the encrypted RSA key (/path/to/targets_key):

>>> private_snapshot_key = import_rsa_privatekey_from_file('snapshot_key')
Enter a password for the encrypted RSA key (/path/to/snapshot_key):

>>> private_timestamp_key = import_rsa_privatekey_from_file('timestamp_key')
Enter a password for the encrypted RSA key (/path/to/timestamp_key):
# Import the signing keys of the remaining top-level roles.
>>> private_targets_key = import_rsa_privatekey_from_file('targets_key', password='password')
>>> private_snapshot_key = import_rsa_privatekey_from_file('snapshot_key', password='password')
>>> private_timestamp_key = import_rsa_privatekey_from_file('timestamp_key', password='password')

# Load the signing keys of the remaining roles so that valid signatures are
# generated when repository.writeall() is called.
Expand Down Expand Up @@ -390,18 +377,21 @@ metadata. `snapshot.json` keys must be loaded and its metadata signed because
# The private key of the updated targets metadata must be re-loaded before it
# can be signed and written (Note the load_repository() call above).
>>> private_targets_key = import_rsa_privatekey_from_file('targets_key')
Enter a password for the encrypted RSA key (/path/to/targets_key):
enter password to decrypt private key file '/path/to/targets_key'
(leave empty if key not encrypted):

>>> repository.targets.load_signing_key(private_targets_key)

# Due to the load_repository() and new versions of metadata, we must also load
# the private keys of Snapshot and Timestamp to generate a valid set of metadata.
>>> private_snapshot_key = import_rsa_privatekey_from_file('snapshot_key')
Enter a password for the encrypted RSA key (/path/to/snapshot_key):
enter password to decrypt private key file '/path/to/snapshot_key'
(leave empty if key not encrypted):
>>> repository.snapshot.load_signing_key(private_snapshot_key)

>>> private_timestamp_key = import_rsa_privatekey_from_file('timestamp_key')
Enter a password for the encrypted RSA key (/path/to/timestamp_key):
enter password to decrypt private key file '/path/to/timestamp_key'
(leave empty if key not encrypted):
>>> repository.timestamp.load_signing_key(private_timestamp_key)

# Mark roles for metadata update (see #964, #958)
Expand Down Expand Up @@ -451,7 +441,7 @@ threshold, it needs to be added to `root.json`, e.g. via
>>> from securesystemslib.formats import encode_canonical
>>> from securesystemslib.keys import create_signature
>>> private_ed25519_key = import_ed25519_privatekey_from_file('ed25519_key')
Enter a password for the encrypted Ed25519 key (/path/to/ed25519_key):
enter password to decrypt private key file '/path/to/ed25519_key'
>>> signature = create_signature(
... private_ed25519_key, encode_canonical(signable_content).encode())
```
Expand Down Expand Up @@ -489,7 +479,7 @@ targets and generate signed metadata.
# Continuing from the previous section . . .

# Generate a key for a new delegated role named "unclaimed".
>>> generate_and_write_rsa_keypair('unclaimed_key', bits=2048, password='password')
>>> generate_and_write_rsa_keypair(password='password', filepath='unclaimed_key', bits=2048)
>>> public_unclaimed_key = import_rsa_publickey_from_file('unclaimed_key.pub')

# Make a delegation (delegate trust of 'myproject/*.txt' files) from "targets"
Expand All @@ -502,8 +492,7 @@ targets and generate signed metadata.

# Load the private key of "unclaimed" so that unclaimed's metadata can be
# signed, and valid metadata created.
>>> private_unclaimed_key = import_rsa_privatekey_from_file('unclaimed_key')
Enter a password for the encrypted RSA key (/path/to/unclaimed_key):
>>> private_unclaimed_key = import_rsa_privatekey_from_file('unclaimed_key', password='password')

>>> repository.targets("unclaimed").load_signing_key(private_unclaimed_key)

Expand Down
2 changes: 1 addition & 1 deletion requirements-pinned.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ ipaddress==1.0.23 ; python_version < '3' # via cryptography
pycparser==2.20 # via cffi
pynacl==1.4.0 # via securesystemslib
requests==2.24.0
securesystemslib[crypto,pynacl]==0.17.0
securesystemslib[crypto,pynacl]==0.18.0
six==1.15.0
subprocess32==3.5.4 ; python_version < '3' # via securesystemslib
urllib3==1.25.11 # via requests
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
install_requires = [
'requests>=2.19.1',
'six>=1.11.0',
'securesystemslib>=0.16.0'
'securesystemslib>=0.18.0'
],
tests_require = [
'mock; python_version < "3.3"'
Expand Down
10 changes: 5 additions & 5 deletions tests/repository_data/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@
# Generate public and private key files for the top-level roles, and two
# delegated roles (these number of keys should be sufficient for most of the
# unit tests). Unit tests may generate additional keys, if needed.
generate_and_write_rsa_keypair(root_key_file, password='password')
generate_and_write_ed25519_keypair(targets_key_file, password='password')
generate_and_write_ed25519_keypair(snapshot_key_file, password='password')
generate_and_write_ed25519_keypair(timestamp_key_file, password='password')
generate_and_write_ed25519_keypair(delegation_key_file, password='password')
generate_and_write_rsa_keypair(password='password', filepath=root_key_file)
generate_and_write_ed25519_keypair(password='password', filepath=targets_key_file)
generate_and_write_ed25519_keypair(password='password', filepath=snapshot_key_file)
generate_and_write_ed25519_keypair(password='password', filepath=timestamp_key_file)
generate_and_write_ed25519_keypair(password='password', filepath=delegation_key_file)

# Import the public keys. These keys are needed so that metadata roles are
# assigned verification keys, which clients use to verify the signatures created
Expand Down
2 changes: 1 addition & 1 deletion tests/test_repository_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def test_import_ed25519_privatekey_from_file(self):
temporary_directory = tempfile.mkdtemp(dir=self.temporary_directory)
ed25519_keypath = os.path.join(temporary_directory, 'ed25519_key')
securesystemslib.interface.generate_and_write_ed25519_keypair(
ed25519_keypath, password='pw')
password='pw', filepath=ed25519_keypath)

imported_ed25519_key = \
repo_lib.import_ed25519_privatekey_from_file(ed25519_keypath, 'pw')
Expand Down
18 changes: 9 additions & 9 deletions tests/test_tutorial.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ def test_tutorial(self):

# ----- Tutorial Section: Keys

generate_and_write_rsa_keypair('root_key', bits=2048, password='password')
generate_and_write_rsa_keypair(password='password', filepath='root_key', bits=2048)

# Skipping user entry of password
## generate_and_write_rsa_keypair('root_key2')
generate_and_write_rsa_keypair('root_key2', password='password')
## generate_and_write_rsa_keypair_with_prompt('root_key2')
generate_and_write_rsa_keypair(password='password', filepath='root_key2')

# Tutorial tells users to expect these files to exist:
# ['root_key', 'root_key.pub', 'root_key2', 'root_key2.pub']
Expand Down Expand Up @@ -109,8 +109,8 @@ def test_tutorial(self):
# ----- Tutorial Section: Create and Import Ed25519 Keys

# Skipping user entry of password
## generate_and_write_ed25519_keypair('ed25519_key')
generate_and_write_ed25519_keypair('ed25519_key', password='password')
## generate_and_write_ed25519_keypair_with_prompt('ed25519_key')
generate_and_write_ed25519_keypair(password='password', filepath='ed25519_key')

public_ed25519_key = import_ed25519_publickey_from_file('ed25519_key.pub')

Expand Down Expand Up @@ -157,9 +157,9 @@ def test_tutorial(self):
repr('targets') + " role contains 0 / 1 signatures."
], [args[0] for args, _ in mock_logger.info.call_args_list])

generate_and_write_rsa_keypair('targets_key', password='password')
generate_and_write_rsa_keypair('snapshot_key', password='password')
generate_and_write_rsa_keypair('timestamp_key', password='password')
generate_and_write_rsa_keypair(password='password', filepath='targets_key')
generate_and_write_rsa_keypair(password='password', filepath='snapshot_key')
generate_and_write_rsa_keypair(password='password', filepath='timestamp_key')

repository.targets.add_verification_key(import_rsa_publickey_from_file(
'targets_key.pub'))
Expand Down Expand Up @@ -309,7 +309,7 @@ def test_tutorial(self):

# ----- Tutorial Section: Delegations
generate_and_write_rsa_keypair(
'unclaimed_key', bits=2048, password='password')
password='password', filepath='unclaimed_key', bits=2048)
public_unclaimed_key = import_rsa_publickey_from_file('unclaimed_key.pub')
repository.targets.delegate(
'unclaimed', [public_unclaimed_key], ['myproject/*.txt'])
Expand Down
11 changes: 6 additions & 5 deletions tuf/README-developer-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,16 @@ is the private key.

```
>>> from tuf.developer_tool import *
>>> generate_and_write_rsa_keypair("path/to/key")
Enter a password for the RSA key:
>>> generate_and_write_rsa_keypair_with_prompt(filepath="path/to/key")
enter password to encrypt private key file 'path/to/key'
(leave empty if key should not be encrypted):
Confirm:
>>>
```

We can also use the bits parameter to set a different key length (the default
is 3072). We can also provide the password parameter in order to suppress the
password prompt.
is 3072). We can also `generate_and_write_rsa_keypair` with a `password`
parameter if a prompt is not desired.

In this example we will be using rsa keys, but ed25519 keys are also supported.

Expand Down Expand Up @@ -257,7 +258,7 @@ When generating keys, it is possible to specify the length of the key in bits
and its password as parameters:

```
>>> generate_and_write_rsa_keypair("path/to/key", bits=2048, password="pw")
>>> generate_and_write_rsa_keypair(password="pw", filepath="path/to/key", bits=2048)
```
The bits parameter defaults to 3072, and values below 2048 will raise an error.
The password parameter is only intended to be used in scripts.
Expand Down
7 changes: 7 additions & 0 deletions tuf/developer_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,14 @@

from securesystemslib.interface import (
generate_and_write_rsa_keypair,
generate_and_write_rsa_keypair_with_prompt,
generate_and_write_unencrypted_rsa_keypair,
generate_and_write_ecdsa_keypair,
generate_and_write_ecdsa_keypair_with_prompt,
generate_and_write_unencrypted_ecdsa_keypair,
generate_and_write_ed25519_keypair,
generate_and_write_ed25519_keypair_with_prompt,
generate_and_write_unencrypted_ed25519_keypair,
import_rsa_publickey_from_file,
import_ed25519_publickey_from_file,
import_ed25519_privatekey_from_file)
Expand Down
6 changes: 6 additions & 0 deletions tuf/repository_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,14 @@

from securesystemslib.interface import (
generate_and_write_rsa_keypair,
generate_and_write_rsa_keypair_with_prompt,
generate_and_write_unencrypted_rsa_keypair,
generate_and_write_ecdsa_keypair,
generate_and_write_ecdsa_keypair_with_prompt,
generate_and_write_unencrypted_ecdsa_keypair,
generate_and_write_ed25519_keypair,
generate_and_write_ed25519_keypair_with_prompt,
generate_and_write_unencrypted_ed25519_keypair,
import_rsa_publickey_from_file,
import_ecdsa_publickey_from_file,
import_ed25519_publickey_from_file,
Expand Down
Loading

0 comments on commit 11e2f4c

Please sign in to comment.