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

feat: #528 Add-Key to a role #535

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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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),
ChevronTango marked this conversation as resolved.
Show resolved Hide resolved
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