Skip to content

Commit

Permalink
feat: #528 Add-Key to a role (#535)
Browse files Browse the repository at this point in the history
* 528 Add-Key to a role

Introduces the add-key command

Signed-off-by: Edward Brough <edward.brough@gmail.com>

* Make sure error message ends with a newline

Signed-off-by: Fredrik Skogman <kommendorkapten@github.com>

---------

Signed-off-by: Edward Brough <edward.brough@gmail.com>
Signed-off-by: Fredrik Skogman <kommendorkapten@github.com>
Co-authored-by: Fredrik Skogman <kommendorkapten@github.com>
  • Loading branch information
ChevronTango and kommendorkapten authored Sep 16, 2023
1 parent 14ed751 commit 70d3a54
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 4 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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=<scheme>] [--expires=<days>] [--public-key=<path>] <role>`

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=<days>] <role>`

Prompts the user for an encryption passphrase (unless the
Expand Down
77 changes: 77 additions & 0 deletions cmd/tuf/add_key.go
Original file line number Diff line number Diff line change
@@ -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=<scheme>] [--expires=<days>] [--public-key=<path>] <role>
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=<path> The Path to the file containing value of the public key. If absent, will be read from stdin.
--expires=<days> Set the metadata file to expire <days> days from now.
--scheme=<scheme> Set the key scheme to use [default: ed25519].
`)
}

func cmdAddKey(args *docopt.Args, repo *tuf.Repo) error {
role := args.String["<role>"]
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
}
1 change: 1 addition & 0 deletions cmd/tuf/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions pkg/keys/rsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/keys/rsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand All @@ -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)
}
43 changes: 43 additions & 0 deletions repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down

0 comments on commit 70d3a54

Please sign in to comment.