From 70d3a5483ff549b074d82df69c1dddccdfd30456 Mon Sep 17 00:00:00 2001 From: ChevronTango Date: Sat, 16 Sep 2023 17:06:43 +0100 Subject: [PATCH 1/2] feat: #528 Add-Key to a role (#535) * 528 Add-Key to a role Introduces the add-key command Signed-off-by: Edward Brough * Make sure error message ends with a newline Signed-off-by: Fredrik Skogman --------- Signed-off-by: Edward Brough Signed-off-by: Fredrik Skogman Co-authored-by: Fredrik Skogman --- README.md | 9 ++++++ cmd/tuf/add_key.go | 77 ++++++++++++++++++++++++++++++++++++++++++++ cmd/tuf/main.go | 1 + pkg/keys/rsa.go | 4 +-- pkg/keys/rsa_test.go | 4 +-- repo.go | 43 +++++++++++++++++++++++++ 6 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 cmd/tuf/add_key.go diff --git a/README.md b/README.md index fe283674..ce4f6363 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,15 @@ snapshots (i.e. by passing `--consistent-snapshot=false`). If consistent snapshots should be generated, the repository will be implicitly initialized to do so when generating keys. +#### `tuf add-key [--scheme=] [--expires=] [--public-key=] ` + +Adds a new signing key for the given role. + +The root metadata file will be staged +with the addition of the key's ID to the role's list of key IDs. + +The public value can be specified as a path or passed in via stdin. + #### `tuf gen-key [--expires=] ` Prompts the user for an encryption passphrase (unless the diff --git a/cmd/tuf/add_key.go b/cmd/tuf/add_key.go new file mode 100644 index 00000000..e88e25d8 --- /dev/null +++ b/cmd/tuf/add_key.go @@ -0,0 +1,77 @@ +package main + +import ( + "fmt" + "os" + "time" + + "github.com/flynn/go-docopt" + "github.com/theupdateframework/go-tuf" + "github.com/theupdateframework/go-tuf/data" +) + +func init() { + register("add-key", cmdAddKey, ` +usage: tuf add-key [--scheme=] [--expires=] [--public-key=] + +Adds a new signing key for the given role. + +The root metadata file will be staged +with the addition of the key's ID to the role's list of key IDs. + +Options: + --public-key= The Path to the file containing value of the public key. If absent, will be read from stdin. + --expires= Set the metadata file to expire days from now. + --scheme= Set the key scheme to use [default: ed25519]. +`) +} + +func cmdAddKey(args *docopt.Args, repo *tuf.Repo) error { + role := args.String[""] + var keyids []string + + var keyScheme data.KeyScheme + switch t := args.String["--scheme"]; t { + case string(data.KeySchemeEd25519), + string(data.KeySchemeECDSA_SHA2_P256), + string(data.KeySchemeRSASSA_PSS_SHA256): + keyScheme = data.KeyScheme(t) + default: + fmt.Fprintf(os.Stderr, "tuf: key schema %s not recognised\n", t) + return nil + } + f := args.String["--public-key"] + var publicValue string + if f != "" { + bytes, err := os.ReadFile(f) + if err != nil { + return err + } + publicValue = string(bytes) + } else { + var input string + _, err := fmt.Scan(&input) + if err != nil { + return err + } + publicValue = input + } + var err error + var expires time.Time + if arg := args.String["--expires"]; arg != "" { + expires, err = parseExpires(arg) + if err != nil { + return err + } + } else { + expires = data.DefaultExpires(role) + } + keyids, err = repo.AddKeyWithSchemeAndExpires(role, expires, keyScheme, publicValue) + if err != nil { + return err + } + for _, id := range keyids { + fmt.Fprintf(os.Stdout, "Add key with ID %s\n", id) + } + return nil +} diff --git a/cmd/tuf/main.go b/cmd/tuf/main.go index dc6a256c..1c9439ea 100644 --- a/cmd/tuf/main.go +++ b/cmd/tuf/main.go @@ -30,6 +30,7 @@ Options: Commands: help Show usage for a specific command init Initialize a new repository + add-key Adds a new signing key for a specific role gen-key Generate a new signing key for a specific metadata file revoke-key Revoke a signing key add Add target file(s) diff --git a/pkg/keys/rsa.go b/pkg/keys/rsa.go index 618f104e..07a4cd6b 100644 --- a/pkg/keys/rsa.go +++ b/pkg/keys/rsa.go @@ -17,11 +17,11 @@ import ( ) func init() { - VerifierMap.Store(data.KeyTypeRSASSA_PSS_SHA256, newRsaVerifier) + VerifierMap.Store(data.KeyTypeRSASSA_PSS_SHA256, NewRsaVerifier) SignerMap.Store(data.KeyTypeRSASSA_PSS_SHA256, newRsaSigner) } -func newRsaVerifier() Verifier { +func NewRsaVerifier() Verifier { return &rsaVerifier{} } diff --git a/pkg/keys/rsa_test.go b/pkg/keys/rsa_test.go index 73520003..e5406c1a 100644 --- a/pkg/keys/rsa_test.go +++ b/pkg/keys/rsa_test.go @@ -97,7 +97,7 @@ func (ECDSASuite) TestUnmarshalRSAPublicKey(c *C) { signer := &rsaSigner{priv.PrivateKey} goodKey := signer.PublicData() - verifier := newRsaVerifier() + verifier := NewRsaVerifier() c.Assert(verifier.UnmarshalPublicKey(goodKey), IsNil) } @@ -119,7 +119,7 @@ func (ECDSASuite) TestUnmarshalRSA_TooLongContent(c *C) { Algorithms: data.HashAlgorithms, Value: tooLongPayload, } - verifier := newRsaVerifier() + verifier := NewRsaVerifier() err = verifier.UnmarshalPublicKey(badKey) c.Assert(errors.Is(err, io.ErrUnexpectedEOF), Equals, true) } diff --git a/repo.go b/repo.go index db2ac663..e9382ddb 100644 --- a/repo.go +++ b/repo.go @@ -379,6 +379,49 @@ func (r *Repo) GenKeyWithSchemeAndExpires(role string, expires time.Time, keySch return signer.PublicData().IDs(), nil } +func (r *Repo) AddKeyWithSchemeAndExpires(role string, expires time.Time, keyScheme data.KeyScheme, publicValue string) ([]string, error) { + var verifier keys.Verifier + var keyType data.KeyType + switch keyScheme { + case data.KeySchemeEd25519: + verifier = keys.NewEd25519Verifier() + keyType = data.KeyTypeEd25519 + case data.KeySchemeECDSA_SHA2_P256: + verifier = keys.NewEcdsaVerifier() + keyType = data.KeyTypeECDSA_SHA2_P256 + case data.KeySchemeRSASSA_PSS_SHA256: + verifier = keys.NewRsaVerifier() + keyType = data.KeyTypeRSASSA_PSS_SHA256 + default: + return nil, errors.New("unknown key type") + } + + publicValueData, err := json.Marshal(map[string]string{ + "public": publicValue, + }) + if err != nil { + return nil, err + } + + if err := verifier.UnmarshalPublicKey(&data.PublicKey{ + Type: keyType, + Scheme: keyScheme, + Algorithms: data.HashAlgorithms, + Value: publicValueData, + }); err != nil { + return nil, err + } + + publicKey := verifier.MarshalPublicKey() + + // Not compatible with delegated targets roles, since delegated targets keys + // are associated with a delegation (edge), not a role (node). + if err := r.AddVerificationKeyWithExpiration(role, publicKey, expires); err != nil { + return nil, err + } + return publicKey.IDs(), nil +} + func (r *Repo) AddPrivateKey(role string, signer keys.Signer) error { // Not compatible with delegated targets roles, since delegated targets keys // are associated with a delegation (edge), not a role (node). From 35c71e42cd12aeac00b6e323f7748f2daac90c59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 16:26:11 -0400 Subject: [PATCH 2/2] chore(deps): bump goreleaser/goreleaser-action from 4.6.0 to 5.0.0 (#554) Bumps [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) from 4.6.0 to 5.0.0. - [Release notes](https://github.com/goreleaser/goreleaser-action/releases) - [Commits](https://github.com/goreleaser/goreleaser-action/compare/5fdedb94abba051217030cc86d4523cf3f02243d...7ec5c2b0c6cdda6e8bbb49444bc797dd33d74dd8) --- updated-dependencies: - dependency-name: goreleaser/goreleaser-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9a9d2132..c0925a22 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: with: go-version: ${{ steps.go-version.outputs.minimal }} - name: Run GoReleaser - uses: goreleaser/goreleaser-action@5fdedb94abba051217030cc86d4523cf3f02243d + uses: goreleaser/goreleaser-action@7ec5c2b0c6cdda6e8bbb49444bc797dd33d74dd8 with: distribution: goreleaser version: "v1.7.0"