Skip to content

Commit

Permalink
Add payload and add-signature commands.
Browse files Browse the repository at this point in the history
Fixes #205.
  • Loading branch information
znewman01 committed Feb 1, 2022
1 parent 87caa18 commit 6e19e18
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 0 deletions.
37 changes: 37 additions & 0 deletions cmd/tuf/add_signature.go
@@ -0,0 +1,37 @@
package main

import (
"os"

"github.com/flynn/go-docopt"
"github.com/theupdateframework/go-tuf"
"github.com/theupdateframework/go-tuf/data"
)

func init() {
register("add-signature", cmdAddSignature, `
usage: tuf add-signature <role> --key-id <key_id> --signature <sig_file>
Adds a signature (as hex-encoded bytes) generated by an offline tool to the given role.
If the signature does not verify, it will not be added.
`)
}

func cmdAddSignature(args *docopt.Args, repo *tuf.Repo) error {
role := args.String["<role>"]
keyID := args.String["<key_id>"]

f := args.String["<sig_file>"]
sigBytes, err := os.ReadFile(f)
if err != nil {
return err
}
sigData := data.HexBytes(sigBytes)

sig := data.Signature{
KeyID: keyID,
Signature: sigData,
}
return repo.AddOrUpdateSignature(role, sig)
}
2 changes: 2 additions & 0 deletions cmd/tuf/main.go
Expand Up @@ -36,6 +36,8 @@ Commands:
remove Remove a target file
snapshot Update the snapshot metadata file
timestamp Update the timestamp metadata file
payload Output a role's metadata file for signing
add-signature Adds a signature generated offline
sign Sign a role's metadata file
commit Commit staged files to the repository
regenerate Recreate the targets metadata file [Not supported yet]
Expand Down
27 changes: 27 additions & 0 deletions cmd/tuf/payload.go
@@ -0,0 +1,27 @@
package main

import (
"fmt"

"github.com/flynn/go-docopt"
"github.com/theupdateframework/go-tuf"
)

func init() {
register("payload", cmdPayload, `
usage: tuf payload <role>
Output a role's metadata in a ready-to-sign format.
The output is canonicalized.
`)
}

func cmdPayload(args *docopt.Args, repo *tuf.Repo) error {
p, err := repo.Payload(args.String["<role>"])
if err != nil {
return err
}
fmt.Print(string(p))
return nil
}
16 changes: 16 additions & 0 deletions repo.go
Expand Up @@ -1092,3 +1092,19 @@ func (r *Repo) timestampFileMeta(roleFilename string) (data.TimestampFileMeta, e
}
return util.GenerateTimestampFileMeta(bytes.NewReader(b), r.hashAlgorithms...)
}

func (r *Repo) Payload(roleFilename string) ([]byte, error) {
// TODO: if you pass "root" instead of "root.json" you get a cryptic error message
// this is probably true for "sign" as well
role := strings.TrimSuffix(roleFilename, ".json")
if !roles.IsTopLevelRole(role) {
return nil, ErrInvalidRole{role}
}

s, err := r.SignedMeta(roleFilename)
if err != nil {
return nil, err
}

return s.Signed, nil
}
29 changes: 29 additions & 0 deletions repo_test.go
Expand Up @@ -1830,3 +1830,32 @@ func (rs *RepoSuite) TestSignDigest(c *C) {
c.Assert(targets.Targets["sha256:bc11b176a293bb341a0f2d0d226f52e7fcebd186a7c4dfca5fc64f305f06b94c"].FileMeta.Hashes["sha256"], DeepEquals, hex_digest_bytes)

}

func (rs *RepoSuite) TestPayload(c *C) {
signer, err := keys.GenerateEd25519Key()
c.Assert(err, IsNil)

// meta := map[string]json.RawMessage{"root.json": []byte(`{"signed":{},"signatures":[]}`)}
meta := make(map[string]json.RawMessage)
local := MemoryStore(meta, nil)
r, err := NewRepo(local)
c.Assert(err, IsNil)
c.Assert(r.Init(false), IsNil)

err = r.AddVerificationKey("root", signer.PublicData())
c.Assert(err, IsNil)

payload, err := r.Payload("root.json")
c.Assert(err, IsNil)
rawSig, err := signer.SignMessage(payload)
keyID := signer.PublicData().IDs()[0]
sig := data.Signature{
KeyID: keyID,
Signature: rawSig,
}
c.Assert(err, IsNil)

// This method checks that the signature verifies!
err = r.AddOrUpdateSignature("root.json", sig)
c.Assert(err, IsNil)
}

0 comments on commit 6e19e18

Please sign in to comment.