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

Need a high level interface for creating and changing TUF metadata #232

Open
erickt opened this issue Nov 21, 2019 · 2 comments
Open

Need a high level interface for creating and changing TUF metadata #232

erickt opened this issue Nov 21, 2019 · 2 comments

Comments

@erickt
Copy link
Collaborator

erickt commented Nov 21, 2019

We need to do a lot of manual work to creating TUF metadata, and generating new versions if we rotate keys or add/remove targets. In comparison, go-tuf has a repo library that has a bunch of simple helper functions. For example, see this script and this test.

@cavokz
Copy link
Contributor

cavokz commented Nov 26, 2019

Questions:

  1. should this be a library+tests?
  2. should it also take care of creating keys, if needed (ie using sequoia)?

I see this possible repository creation flow:

  1. create TUF repository:
    • root key is existing or new (to be created contextually)
    • at start, all the roles are using the same root key. Maximum simplicity, minimum security.
  2. add delegation
    • one delegating key (eg root) needs to be accessible for signing the delegation (eg timestamp)
    • delegation specific parameters (eg target base path, if creating a target delegation) need to be provided
  3. sign existing delegation
    • add a signature to an existing delegation so that delegations requiring multiple signatures can reach the required validity quorum
  4. publish

Key rotation would happen in this way:

  1. new delegation is added
  2. signatures are accumulated until validity quorum is reached
  3. signatures are progressively removed from the delegation to be revoked, removal of the last signature removes also the delegation

Need to double check the TUF spec, I don't remember what specifies about rotation. Surely it's not healthy to revoke a delegation without reaching the same validity quorum that qualified it.

@erickt
Copy link
Collaborator Author

erickt commented Nov 27, 2019

Hello @cavokz! I'd appreciate any help. I've started sketching out some ideas, but haven't gotten too far yet. Here's roughly the API I think we could use:

let staging = FileSystemRepository::new("...");
let committed = FileSystemRepository::new("...");

let private_keys = load_keys(...);

let config = Config::default();

// I'd love to call this Repository, but we are using that term already. Maybe we should rename it
// to `Transport` or `Store`?
//
// Anyway, this `Creator` holds all the private keys. It might internally use `Client` to download
// the metadata, and we will use the `local` store as the location for the committed metadata, and
// `staging` as the in progress metadata.
let mut creator = Creator::new(staging, committed);

// Or, if we want to pretty print metadata. The creator needs to know this because the timestamp
// role tracks the snapshot role's file hash, so before we can create a new timestamp we need to
// make sure it captures the pretty version of the snapshot metadata.
let mut creator = Creator::builder()
    .pretty()
    .build();

// These add the keys for verifying signatures, but doesn't change metadata.
creator.load_private_keys(Role::Root, &private_keys["root"]);
creator.load_private_keys(Role::Snapshot, &private_keys["snapshot"]);
creator.load_private_keys(Role::Targets, &private_keys["targets"]);
creator.load_private_keys(Role::Timestamp, &private_keys["timestamp"]);

// Add a trusted public signing key. Anytime we manipulate metadata, first check if the metadata is
// in the staging repo. If not, copy it from the committed repo while stripping off the signatures
// and incrementing the version number.
{
    let root = creator.root();

    // Rotate a key.
    let key = root.add_key(Role::Root, PublicKey(...));
    // save key...
    
    root.remove_key(Role::Root, PublicKey(...));

    // Write the file back to the `staging` repo.
    root.finish();
}

// Adding targets. Note that this targets builder should remember the setting of consistent
// snapshot from the `staging` or `committed` root metadata, since that changes how target files
// are written to the repository.
{
    let targets = creator.targets();

    // shortcut for adding a simple target.
    targets.add_target_from_reader("foo/bar", b"123").finish();

    // more complex builder that adds custom target metadata, and explicitly sets the target
    // version and expiry.
    targets.add_target_from_reader("bar", b"123")
        .custom(json!{
            "foo": "bar",
        })
        .version(targets.version() + 5)
        .expires(Utc.ymd(2020, 1, 1).and_hms(0, 0, 0))
        .finish();

    // We might not have actual targets to upload, instead just work with target descriptions.
    let target_description: TargetDescription = ...;
    targets.add_target_description("baz", &target_description)
        .finish();

    // Removes a target, without updating the version number since it changed in the last call.
    targets.remove_target("baz");

    targets.finish();
}

// Take a snapshot.
creator.snapshot()
    .finish();

// Take a timestamp.
creator.timestamp()
    .finish();

// Copy the `staging` metadata to the `committed` repo, clearing out the staging metadata.
// This should fail if we don't have enough signatures for a valid quorum.
creator.commit();

I'm not sure yet how we should handle things like delegation though.

As to your questions:

should this be a library+tests?

Yes definitely. We're trying to hold ourselves to the standard that all new code should have tests.

should it also take care of creating keys, if needed (ie using sequoia)?

PrivateKey::new already has some facilities for creating keys, so we could use that in the basic case. That said, we ultimately should play nicely with someone being able to sign metadata with keys stored in an HSM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants