Skip to content
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

Add repository initialization #1

Merged
merged 1 commit into from Dec 16, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
@@ -0,0 +1,6 @@
venv/
bin/
__pycache__/
*.egg-info/
.vscode/
testing/
9 changes: 9 additions & 0 deletions Makefile
@@ -0,0 +1,9 @@
.PHONY: bootstrap
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a more robust way of ensuring a clean virtual environment and Python3?
(And in general, what would be the best practice for ensuring the desired environment?)

bootstrap:
python3 -m venv venv && \
. ./venv/bin/activate && \
pip3 install -r requirements.txt

.PHONY: build
build:
pip3 install --editable .
37 changes: 37 additions & 0 deletions pysigny.py
@@ -0,0 +1,37 @@
import click
import pathlib

import tuf_helpers

global_options = [
click.option('--trustdir', default=tuf_helpers.default_trust_dir,
help='Directory where the trust data is persisted', show_default=True)
]


def apply_global_options(func):
for option in global_options:
func = option(func)
return func


@click.group()
def cli():
"""PySigny is a Python implementation of the CNAB Security Specification."""
pass


@apply_global_options
@click.command()
@click.argument('target')
@click.argument('name')
def sign(target, name, trustdir):
"""Initializes a new trust collection."""

click.echo('Signing file {0} and adding to repo {1} in trust dir {2}'.format(
target, name, trustdir))

tuf_helpers.init_repo(target, name, trustdir)


cli.add_command(sign)
6 changes: 6 additions & 0 deletions readme.md
@@ -0,0 +1,6 @@
### Setup

```
$ make boostrap build
$ pysigny --help
```
16 changes: 16 additions & 0 deletions setup.py
@@ -0,0 +1,16 @@
from setuptools import setup

setup(
name='pysigny',
version='0.0.1',
py_modules=['pysigny'],
install_requires=[
'Click',
'securesystemslib',
'tuf'
],
entry_points='''
[console_scripts]
pysigny=pysigny:cli
''',
)
78 changes: 78 additions & 0 deletions tuf_helpers.py
@@ -0,0 +1,78 @@

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: empty line.

import os
import pathlib
import shutil
from typing import Dict

import securesystemslib as sslib
import tuf.scripts.repo as tuf_repo
import tuf.repository_tool as repo_tool


default_trust_dir = pathlib.Path.joinpath(pathlib.Path.home(), '.pysigny')
keystore_dir = 'private'
root_key_name = 'root_key'
targets_key_name = 'targets_key'
snapshot_key_name = 'snapshot_key'
timestamp_key_name = 'timestamp_key'
metadata_staged_dir = 'metadata.staged'
metadata_dir = 'metadata'


class TUFKey:
private: None
public: None
passphrase: None


keys: Dict[str, TUFKey] = {
root_key_name: TUFKey,
targets_key_name: TUFKey,
snapshot_key_name: TUFKey,
timestamp_key_name: TUFKey
}


def init_repo(target, name, trustdir):
repo_path = pathlib.Path.joinpath(trustdir, name)
repository = repo_tool.create_new_repository(str(repo_path))
create_and_set_keys(repository, name, trustdir)
write_repo(name, trustdir)


def create_and_set_keys(repository, name, trustdir):
for k in keys:
p = os.environ.get(k.upper() + '_PASSPHRASE')
if p == None:
keys[k].passphrase = sslib.interface.get_password(
prompt='Enter password for {0}: '.format(k), confirm=True)
else:
keys[k].passphrase = p

repo_tool.generate_and_write_ecdsa_keypair(os.path.join(
trustdir, name, keystore_dir, k), password=keys[k].passphrase)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example repository tool generates the keys for all repositories in the same directory (I assume for reusing the root key?)

I am still evaluating whether to:

  • keep the convention from the TUF reference implementation
  • mimic the behaviour of Notary and offer to create a new root key per repository.

I think it is still early in this tool to take this decision, but we should have this conversation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sharing the same root key by default per repo makes sense, considering that most people are likely to have a separate repo per bundle, following the DCT model. However, we should give an option to override this.


keys[k].private = tuf_repo.import_privatekey_from_file(
os.path.join(trustdir, name, keystore_dir, k), keys[k].passphrase)

print('trying to load public key from {0}'.format(
os.path.join(trustdir, name, keystore_dir, k) + '.pub'))
keys[k].public = tuf_repo.import_publickey_from_file(
os.path.join(trustdir, name, keystore_dir, k) + '.pub')

repository.root.add_verification_key(keys[root_key_name].public)
repository.targets.add_verification_key(keys[targets_key_name].public)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@trishankatdatadog - this generates 3 warnings for the targets, snapshot, and timestamp public keys:

Adding a verification key that has already been used.

While using the same key here is not an error:

# Keys may be shared, so do not raise an exception if 'key' has already been loaded.

I am wondering though why the keys appear to be shared, since they are generated every time for now (they do share the same passphrase in all my tests so far).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pyTUF repo tool has some spurious messages like that. Will look into this.

repository.snapshot.add_verification_key(keys[snapshot_key_name].public)
repository.timestamp.add_verification_key(keys[timestamp_key_name].public)

repository.root.load_signing_key(keys[root_key_name].private)
repository.targets.load_signing_key(keys[targets_key_name].private)
repository.snapshot.load_signing_key(keys[snapshot_key_name].private)
repository.timestamp.load_signing_key(keys[timestamp_key_name].private)


def write_repo(name, trustdir):
staged_meta = os.path.join(trustdir, name, metadata_staged_dir)
meta = os.path.join(trustdir, name, metadata_dir)
shutil.rmtree(meta, ignore_errors=True)
shutil.copytree(staged_meta, meta)