From ba22b361ae771d0939937ffb8dc5d0d32d01a462 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Mon, 30 Aug 2021 12:46:22 -0500 Subject: [PATCH 01/17] wip Signed-off-by: Asra Ali --- data/types.go | 35 ++------------- keys/ecdsa.go | 67 +++++++++++++++++++++++++++++ sign/keys.go => keys/ed25519.go | 46 +++++++++++--------- keys/keys.go | 75 +++++++++++++++++++++++++++++++++ {sign => keys}/keys_test.go | 0 repo.go | 42 ++++++++++++++++-- sign/sign.go | 24 ++--------- verify/db.go | 6 ++- verify/verifiers.go | 74 -------------------------------- verify/verify.go | 4 +- 10 files changed, 220 insertions(+), 153 deletions(-) create mode 100644 keys/ecdsa.go rename sign/keys.go => keys/ed25519.go (63%) create mode 100644 keys/keys.go rename {sign => keys}/keys_test.go (100%) diff --git a/data/types.go b/data/types.go index ff231e80..0853e7b3 100644 --- a/data/types.go +++ b/data/types.go @@ -37,10 +37,10 @@ type Signature struct { } type Key struct { - Type string `json:"keytype"` - Scheme string `json:"scheme"` - Algorithms []string `json:"keyid_hash_algorithms,omitempty"` - Value KeyValue `json:"keyval"` + Type string `json:"keytype"` + Scheme string `json:"scheme"` + Algorithms []string `json:"keyid_hash_algorithms,omitempty"` + Value json.RawMessage `json:"keyval"` ids []string idOnce sync.Once @@ -64,10 +64,6 @@ func (k *Key) ContainsID(id string) bool { return false } -type KeyValue struct { - Public HexBytes `json:"public"` -} - func DefaultExpires(role string) time.Time { var t time.Time switch role { @@ -116,29 +112,6 @@ func (r *Root) AddKey(key *Key) bool { return changed } -// UniqueKeys returns the unique keys for each associated role. -// We might have multiple key IDs that correspond to the same key. -func (r Root) UniqueKeys() map[string][]*Key { - keysByRole := make(map[string][]*Key) - for name, role := range r.Roles { - seen := make(map[string]struct{}) - keys := []*Key{} - for _, id := range role.KeyIDs { - // Double-check that there is actually a key with that ID. - if key, ok := r.Keys[id]; ok { - val := key.Value.Public.String() - if _, ok := seen[val]; ok { - continue - } - seen[val] = struct{}{} - keys = append(keys, key) - } - } - keysByRole[name] = keys - } - return keysByRole -} - type Role struct { KeyIDs []string `json:"keyids"` Threshold int `json:"threshold"` diff --git a/keys/ecdsa.go b/keys/ecdsa.go new file mode 100644 index 00000000..e8680b64 --- /dev/null +++ b/keys/ecdsa.go @@ -0,0 +1,67 @@ +package keys + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/sha256" + "encoding/asn1" + "encoding/json" + "errors" + "math/big" + + "github.com/theupdateframework/go-tuf/data" +) + +func init() { + KeyMap.Store(data.KeyTypeECDSA_SHA2_P256, NewEcdsa) +} + +func NewEcdsa() Verifier { + v := p256Verifier{} + return &v +} + +type ecdsaSignature struct { + R, S *big.Int +} + +type p256Verifier struct { + public data.HexBytes `json:"public"` +} + +func (p p256Verifier) Public() string { + return p.public.String() +} + +func (p p256Verifier) Verify(msg, sigBytes []byte) error { + x, y := elliptic.Unmarshal(elliptic.P256(), p.public) + k := &ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: x, + Y: y, + } + + var sig ecdsaSignature + if _, err := asn1.Unmarshal(sigBytes, &sig); err != nil { + return err + } + + hash := sha256.Sum256(msg) + + if !ecdsa.Verify(k, hash[:], sig.R, sig.S) { + return errors.New("verifyig ecdsa signature") + } + return nil +} + +func (p p256Verifier) ValidKey(v json.RawMessage) bool { + if err := json.Unmarshal(v, p.public); err != nil { + return false + } + x, _ := elliptic.Unmarshal(elliptic.P256(), p.public) + return x != nil +} + +func (p p256Verifier) UnmarshalKey(key data.Key) error { + return json.Unmarshal(key.Value, p.public) +} diff --git a/sign/keys.go b/keys/ed25519.go similarity index 63% rename from sign/keys.go rename to keys/ed25519.go index 5afa126e..1d706703 100644 --- a/sign/keys.go +++ b/keys/ed25519.go @@ -1,32 +1,39 @@ -package sign +package keys import ( + "crypto/ed25519" "crypto/rand" + "encoding/json" "sync" "github.com/theupdateframework/go-tuf/data" - "golang.org/x/crypto/ed25519" ) -type PrivateKey struct { - Type string `json:"keytype"` - Scheme string `json:"scheme,omitempty"` - Algorithms []string `json:"keyid_hash_algorithms,omitempty"` - Value PrivateKeyValue `json:"keyval"` +func init() { + KeyMap.Store(data.KeySchemeEd25519, NewP256) } -type PrivateKeyValue struct { - Public data.HexBytes `json:"public"` - Private data.HexBytes `json:"private"` +func NewP256() Verifier { + v := ed25519Verifier{} + return &v } -func (k *PrivateKey) PublicData() *data.Key { - return &data.Key{ - Type: k.Type, - Scheme: k.Scheme, - Algorithms: k.Algorithms, - Value: data.KeyValue{Public: k.Value.Public}, +type ed25519Verifier struct { + public ed25519.PublicKey +} + +func (e ed25519Verifier) Verify(msg, sig []byte) error { + if !ed25519.Verify(e.public, msg, sig) { + return ErrInvalid + } + return nil +} + +func (e ed25519Verifier) ValidKey(v json.RawMessage) bool { + if err := json.Unmarshal(v, e.public); err != nil { + return false } + return len(e.public) == ed25519.PublicKeySize } func (k *PrivateKey) Signer() Signer { @@ -67,7 +74,7 @@ type ed25519Signer struct { var _ Signer = &ed25519Signer{} func (s *ed25519Signer) IDs() []string { - s.idOnce.Do(func() { s.ids = s.publicData().IDs() }) + s.idOnce.Do(func() { s.ids = s.MarshalKey().IDs() }) return s.ids } @@ -80,12 +87,13 @@ func (s *ed25519Signer) ContainsID(id string) bool { return false } -func (s *ed25519Signer) publicData() *data.Key { +func (s *ed25519Signer) MarshalKey() *data.Key { + keyValBytes, _ := json.Marshal(data.KeyValue{Public: []byte(s.PrivateKey.Public().(ed25519.PublicKey))}) return &data.Key{ Type: s.keyType, Scheme: s.keyScheme, Algorithms: s.keyAlgorithms, - Value: data.KeyValue{Public: []byte(s.PrivateKey.Public().(ed25519.PublicKey))}, + Value: keyValBytes, } } diff --git a/keys/keys.go b/keys/keys.go new file mode 100644 index 00000000..ec74c44d --- /dev/null +++ b/keys/keys.go @@ -0,0 +1,75 @@ +package keys + +import ( + "crypto" + "encoding/json" + "errors" + "sync" + + "github.com/theupdateframework/go-tuf/data" +) + +// KeyMap stores mapping between key type strings and verifier constructors. +var KeyMap sync.Map + +var ( + ErrInvalid = errors.New("tuf: signature verification failed") +) + +// A Verifier verifies public key signatures. +type Verifier interface { + // UnmarshalKey takes key data to a working verifier implementation for the key type. + UnmarshalKey(key data.Key) error + + // This is the public string used as a unique identifier for the verifier instance. + Public() string + + // Verify takes a message and signature, all as byte slices, + // and determines whether the signature is valid for the given + // key and message. + Verify(msg, sig []byte) error + + // ValidKey returns true if the provided public key is valid and usable to + // verify signatures with this verifier. + ValidKey(value json.RawMessage) bool +} + +type Signer interface { + // IDs returns the TUF key ids + IDs() []string + + // ContainsID returns if the signer contains the key id + ContainsID(id string) bool + + // Type returns the TUF key type + Type() string + + // Scheme returns the TUF key scheme + Scheme() string + + // Signer is used to sign messages and provides access to the public key. + // The signer is expected to do its own hashing, so the full message will be + // provided as the message to Sign with a zero opts.HashFunc(). + crypto.Signer +} + +type PrivateKey struct { + Type string `json:"keytype"` + Scheme string `json:"scheme,omitempty"` + Algorithms []string `json:"keyid_hash_algorithms,omitempty"` + Value PrivateKeyValue `json:"keyval"` +} + +type PrivateKeyValue struct { + Public data.HexBytes `json:"public"` + Private data.HexBytes `json:"private"` +} + +func (k *PrivateKey) PublicData() *data.Key { + return &data.Key{ + Type: k.Type, + Scheme: k.Scheme, + Algorithms: k.Algorithms, + Value: data.KeyValue{Public: k.Value.Public}, + } +} diff --git a/sign/keys_test.go b/keys/keys_test.go similarity index 100% rename from sign/keys_test.go rename to keys/keys_test.go diff --git a/repo.go b/repo.go index 969097c6..552ab8b4 100644 --- a/repo.go +++ b/repo.go @@ -11,6 +11,8 @@ import ( cjson "github.com/tent/canonical-json-go" "github.com/theupdateframework/go-tuf/data" + "github.com/theupdateframework/go-tuf/keys" + tkeys "github.com/theupdateframework/go-tuf/keys" "github.com/theupdateframework/go-tuf/sign" "github.com/theupdateframework/go-tuf/util" "github.com/theupdateframework/go-tuf/verify" @@ -57,10 +59,10 @@ type LocalStore interface { Commit(bool, map[string]int, map[string]data.Hashes) error // GetSigningKeys return a list of signing keys for a role. - GetSigningKeys(string) ([]sign.Signer, error) + GetSigningKeys(string) ([]keys.Signer, error) // SavePrivateKey adds a signing key to a role. - SavePrivateKey(string, *sign.PrivateKey) error + SavePrivateKey(string, *keys.PrivateKey) error // Clean is used to remove all staged manifests. Clean() error @@ -318,7 +320,7 @@ func (r *Repo) GenKey(role string) ([]string, error) { } func (r *Repo) GenKeyWithExpires(keyRole string, expires time.Time) ([]string, error) { - key, err := sign.GenerateEd25519Key() + key, err := keys.GenerateEd25519Key() if err != nil { return []string{}, err } @@ -330,7 +332,7 @@ func (r *Repo) GenKeyWithExpires(keyRole string, expires time.Time) ([]string, e return key.PublicData().IDs(), nil } -func (r *Repo) AddPrivateKey(role string, key *sign.PrivateKey) error { +func (r *Repo) AddPrivateKey(role string, key *keys.PrivateKey) error { return r.AddPrivateKeyWithExpires(role, key, data.DefaultExpires(role)) } @@ -392,6 +394,38 @@ func validExpires(expires time.Time) bool { return expires.Sub(time.Now()) > 0 } +// UniqueKeys returns the unique keys for each associated role. +// We might have multiple key IDs that correspond to the same key. +func (r Root) UniqueKeys() map[string][]*data.Key { + keysByRole := make(map[string][]*data.Key) + for name, role := range r.Roles { + seen := make(map[string]struct{}) + keys := []*data.Key{} + for _, id := range role.KeyIDs { + // Double-check that there is actually a key with that ID. + if key, ok := r.Keys[id]; ok { + if kt, found := tkeys.KeyMap.Load(key.Type); found { + k := kt.(func() tkeys.Verifier)() + if k != nil { + key, err := k.UnmarshalKey(key) + if err != nil { + val := key.Public() + if _, ok := seen[val]; ok { + continue + } + seen[val] = struct{}{} + keys = append(keys, key) + } + + } + } + } + } + keysByRole[name] = keys + } + return keysByRole +} + func (r *Repo) RootKeys() ([]*data.Key, error) { root, err := r.root() if err != nil { diff --git a/sign/sign.go b/sign/sign.go index 1e6d4e5f..1c8410c7 100644 --- a/sign/sign.go +++ b/sign/sign.go @@ -6,28 +6,10 @@ import ( cjson "github.com/tent/canonical-json-go" "github.com/theupdateframework/go-tuf/data" + "github.com/theupdateframework/go-tuf/keys" ) -type Signer interface { - // IDs returns the TUF key ids - IDs() []string - - // ContainsID returns if the signer contains the key id - ContainsID(id string) bool - - // Type returns the TUF key type - Type() string - - // Scheme returns the TUF key scheme - Scheme() string - - // Signer is used to sign messages and provides access to the public key. - // The signer is expected to do its own hashing, so the full message will be - // provided as the message to Sign with a zero opts.HashFunc(). - crypto.Signer -} - -func Sign(s *data.Signed, k Signer) error { +func Sign(s *data.Signed, k keys.Signer) error { ids := k.IDs() signatures := make([]data.Signature, 0, len(s.Signatures)+1) for _, sig := range s.Signatures { @@ -59,7 +41,7 @@ func Sign(s *data.Signed, k Signer) error { return nil } -func Marshal(v interface{}, keys ...Signer) (*data.Signed, error) { +func Marshal(v interface{}, keys ...keys.Signer) (*data.Signed, error) { b, err := cjson.Marshal(v) if err != nil { return nil, err diff --git a/verify/db.go b/verify/db.go index 7c6e91e1..d38bb3ee 100644 --- a/verify/db.go +++ b/verify/db.go @@ -2,6 +2,7 @@ package verify import ( "github.com/theupdateframework/go-tuf/data" + "github.com/theupdateframework/go-tuf/keys" ) type Role struct { @@ -60,14 +61,15 @@ func NewDelegationsVerifier(d *data.Delegations) (DelegationsVerifier, error) { } func (db *DB) AddKey(id string, k *data.Key) error { - v, ok := Verifiers[k.Type] + vt, ok := keys.KeyMap.Load(k.Type) if !ok { return nil } + v := vt.(func() keys.Verifier)() if !k.ContainsID(id) { return ErrWrongID{} } - if !v.ValidKey(k.Value.Public) { + if !v.ValidKey(k.Value) { return ErrInvalidKey } diff --git a/verify/verifiers.go b/verify/verifiers.go index 8a80aa27..efc7e18c 100644 --- a/verify/verifiers.go +++ b/verify/verifiers.go @@ -1,75 +1 @@ package verify - -import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/sha256" - "encoding/asn1" - "math/big" - - "github.com/theupdateframework/go-tuf/data" - "golang.org/x/crypto/ed25519" -) - -// A Verifier verifies public key signatures. -type Verifier interface { - // Verify takes a key, message and signature, all as byte slices, - // and determines whether the signature is valid for the given - // key and message. - Verify(key, msg, sig []byte) error - - // ValidKey returns true if the provided public key is valid and usable to - // verify signatures with this verifier. - ValidKey([]byte) bool -} - -// Verifiers is used to map key types to Verifier instances. -var Verifiers = map[string]Verifier{ - data.KeySchemeEd25519: ed25519Verifier{}, - data.KeySchemeECDSA_SHA2_P256: p256Verifier{}, -} - -type ed25519Verifier struct{} - -func (ed25519Verifier) Verify(key, msg, sig []byte) error { - if !ed25519.Verify(key, msg, sig) { - return ErrInvalid - } - return nil -} - -func (ed25519Verifier) ValidKey(k []byte) bool { - return len(k) == ed25519.PublicKeySize -} - -type ecdsaSignature struct { - R, S *big.Int -} - -type p256Verifier struct{} - -func (p256Verifier) Verify(key, msg, sigBytes []byte) error { - x, y := elliptic.Unmarshal(elliptic.P256(), key) - k := &ecdsa.PublicKey{ - Curve: elliptic.P256(), - X: x, - Y: y, - } - - var sig ecdsaSignature - if _, err := asn1.Unmarshal(sigBytes, &sig); err != nil { - return ErrInvalid - } - - hash := sha256.Sum256(msg) - - if !ecdsa.Verify(k, hash[:], sig.R, sig.S) { - return ErrInvalid - } - return nil -} - -func (p256Verifier) ValidKey(k []byte) bool { - x, _ := elliptic.Unmarshal(elliptic.P256(), k) - return x != nil -} diff --git a/verify/verify.go b/verify/verify.go index b6d4162d..98a6c158 100644 --- a/verify/verify.go +++ b/verify/verify.go @@ -86,8 +86,8 @@ func (db *DB) VerifySignatures(s *data.Signed, role string) error { continue } - if err := Verifiers[key.Type].Verify(key.Value.Public, msg, sig.Signature); err != nil { - return err + if err := key.Verify(msg, sig.Signature); err != nil { + return ErrInvalid } // Only consider this key valid if we haven't seen any of it's From 0948d1a5e30cc343f0a29c6dd6e0f7545b8ea0f7 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Tue, 31 Aug 2021 10:07:05 -0500 Subject: [PATCH 02/17] update for testing Signed-off-by: Asra Ali --- data/types.go | 17 +++++++ keys/ecdsa.go | 29 ++++++++---- keys/ed25519.go | 113 ++++++++++++++++++++++++++++++++-------------- keys/keys.go | 40 ++++++++-------- keys/keys_test.go | 23 ++++++---- local_store.go | 57 +++++++++++++---------- repo.go | 20 +++++--- repo_test.go | 35 +++++++++++++- verify/db.go | 19 ++++---- 9 files changed, 238 insertions(+), 115 deletions(-) diff --git a/data/types.go b/data/types.go index 0853e7b3..00da1a16 100644 --- a/data/types.go +++ b/data/types.go @@ -46,6 +46,23 @@ type Key struct { idOnce sync.Once } +type PrivateKey struct { + Type string `json:"keytype"` + Scheme string `json:"scheme,omitempty"` + Algorithms []string `json:"keyid_hash_algorithms,omitempty"` + Value json.RawMessage `json:"keyval"` + Private json.RawMessage +} + +func (k *PrivateKey) PublicData() *Key { + return &Key{ + Type: k.Type, + Scheme: k.Scheme, + Algorithms: k.Algorithms, + Value: k.Value, + } +} + func (k *Key) IDs() []string { k.idOnce.Do(func() { data, _ := cjson.Marshal(k) diff --git a/keys/ecdsa.go b/keys/ecdsa.go index e8680b64..31b2ca10 100644 --- a/keys/ecdsa.go +++ b/keys/ecdsa.go @@ -16,9 +16,12 @@ func init() { KeyMap.Store(data.KeyTypeECDSA_SHA2_P256, NewEcdsa) } -func NewEcdsa() Verifier { - v := p256Verifier{} - return &v +func NewEcdsa() SignerVerifier { + sv := SignerVerifier{ + Signer: nil, + Verifier: &p256Verifier{}, + } + return sv } type ecdsaSignature struct { @@ -26,15 +29,16 @@ type ecdsaSignature struct { } type p256Verifier struct { - public data.HexBytes `json:"public"` + PublicKey data.HexBytes `json:"public"` + key *data.Key } func (p p256Verifier) Public() string { - return p.public.String() + return p.PublicKey.String() } func (p p256Verifier) Verify(msg, sigBytes []byte) error { - x, y := elliptic.Unmarshal(elliptic.P256(), p.public) + x, y := elliptic.Unmarshal(elliptic.P256(), p.PublicKey) k := &ecdsa.PublicKey{ Curve: elliptic.P256(), X: x, @@ -55,13 +59,18 @@ func (p p256Verifier) Verify(msg, sigBytes []byte) error { } func (p p256Verifier) ValidKey(v json.RawMessage) bool { - if err := json.Unmarshal(v, p.public); err != nil { + if err := json.Unmarshal(v, &p.PublicKey); err != nil { return false } - x, _ := elliptic.Unmarshal(elliptic.P256(), p.public) + x, _ := elliptic.Unmarshal(elliptic.P256(), p.PublicKey) return x != nil } -func (p p256Verifier) UnmarshalKey(key data.Key) error { - return json.Unmarshal(key.Value, p.public) +func (p p256Verifier) UnmarshalKey(key *data.Key) error { + p.key = key + return json.Unmarshal(key.Value, &p.PublicKey) +} + +func (p *p256Verifier) IDs() []string { + return p.key.IDs() } diff --git a/keys/ed25519.go b/keys/ed25519.go index 1d706703..12cc111a 100644 --- a/keys/ed25519.go +++ b/keys/ed25519.go @@ -13,54 +13,107 @@ func init() { KeyMap.Store(data.KeySchemeEd25519, NewP256) } -func NewP256() Verifier { - v := ed25519Verifier{} - return &v +func NewP256() SignerVerifier { + sv := SignerVerifier{ + Signer: &ed25519Signer{}, + Verifier: &ed25519Verifier{}, + } + return sv } type ed25519Verifier struct { - public ed25519.PublicKey + PublicKey data.HexBytes `json:"public"` + key *data.Key +} + +func (e ed25519Verifier) Public() string { + return string(e.PublicKey) } func (e ed25519Verifier) Verify(msg, sig []byte) error { - if !ed25519.Verify(e.public, msg, sig) { + if !ed25519.Verify([]byte(e.PublicKey), msg, sig) { return ErrInvalid } return nil } func (e ed25519Verifier) ValidKey(v json.RawMessage) bool { - if err := json.Unmarshal(v, e.public); err != nil { + if err := json.Unmarshal(v, &e.PublicKey); err != nil { return false } - return len(e.public) == ed25519.PublicKeySize + return len(e.PublicKey) == ed25519.PublicKeySize } -func (k *PrivateKey) Signer() Signer { - return &ed25519Signer{ - PrivateKey: ed25519.PrivateKey(k.Value.Private), - keyType: k.Type, - keyScheme: k.Scheme, - keyAlgorithms: k.Algorithms, +func (e ed25519Verifier) UnmarshalKey(key *data.Key) error { + e.key = key + return json.Unmarshal(key.Value, &e.PublicKey) +} + +func (e ed25519Verifier) IDs() []string { + return e.key.IDs() +} + +type ed25519PrivateKeyValue struct { + Public data.HexBytes `json:"public"` + Private data.HexBytes `json:"private"` +} + +func GenerateEd25519Key() (*ed25519Signer, error) { + _, private, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return nil, err } + if err != nil { + return nil, err + } + return &ed25519Signer{ + PrivateKey: ed25519.PrivateKey(data.HexBytes(private)), + keyType: data.KeyTypeEd25519, + keyScheme: data.KeySchemeEd25519, + keyAlgorithms: data.KeyAlgorithms, + }, nil } -func GenerateEd25519Key() (*PrivateKey, error) { - public, private, err := ed25519.GenerateKey(rand.Reader) +func (e ed25519Signer) MarshalPrivate() (*data.PrivateKey, error) { + valueBytes, err := json.Marshal(ed25519PrivateKeyValue{ + Public: data.HexBytes([]byte(e.PrivateKey.Public().(ed25519.PublicKey))), + Private: data.HexBytes(e.PrivateKey), + }) if err != nil { return nil, err } - return &PrivateKey{ - Type: data.KeyTypeEd25519, - Scheme: data.KeySchemeEd25519, - Algorithms: data.KeyAlgorithms, - Value: PrivateKeyValue{ - Public: data.HexBytes(public), - Private: data.HexBytes(private), - }, + return &data.PrivateKey{ + Type: e.keyType, + Scheme: e.keyScheme, + Algorithms: e.keyAlgorithms, + Value: valueBytes, }, nil } +func (e ed25519Signer) UnmarshalSigner(key *data.PrivateKey) error { + keyValue := &ed25519PrivateKeyValue{} + if err := json.Unmarshal(key.Value, keyValue); err != nil { + return err + } + e = ed25519Signer{ + PrivateKey: ed25519.PrivateKey(keyValue.Private), + keyType: key.Type, + keyScheme: key.Scheme, + keyAlgorithms: key.Algorithms, + } + return nil +} + +func (e ed25519Signer) PublicData() *data.Key { + keyValBytes, _ := json.Marshal(ed25519Verifier{PublicKey: []byte(e.PrivateKey.Public().(ed25519.PublicKey))}) + return &data.Key{ + Type: e.keyType, + Scheme: e.keyScheme, + Algorithms: e.keyAlgorithms, + Value: keyValBytes, + } +} + type ed25519Signer struct { ed25519.PrivateKey @@ -71,10 +124,10 @@ type ed25519Signer struct { idOnce sync.Once } -var _ Signer = &ed25519Signer{} +// var _ Signer = &ed25519Signer{} func (s *ed25519Signer) IDs() []string { - s.idOnce.Do(func() { s.ids = s.MarshalKey().IDs() }) + s.idOnce.Do(func() { s.ids = s.PublicData().IDs() }) return s.ids } @@ -87,16 +140,6 @@ func (s *ed25519Signer) ContainsID(id string) bool { return false } -func (s *ed25519Signer) MarshalKey() *data.Key { - keyValBytes, _ := json.Marshal(data.KeyValue{Public: []byte(s.PrivateKey.Public().(ed25519.PublicKey))}) - return &data.Key{ - Type: s.keyType, - Scheme: s.keyScheme, - Algorithms: s.keyAlgorithms, - Value: keyValBytes, - } -} - func (s *ed25519Signer) Type() string { return s.keyType } diff --git a/keys/keys.go b/keys/keys.go index ec74c44d..ad1c6757 100644 --- a/keys/keys.go +++ b/keys/keys.go @@ -12,6 +12,11 @@ import ( // KeyMap stores mapping between key type strings and verifier constructors. var KeyMap sync.Map +type SignerVerifier struct { + Signer Signer + Verifier Verifier +} + var ( ErrInvalid = errors.New("tuf: signature verification failed") ) @@ -19,11 +24,14 @@ var ( // A Verifier verifies public key signatures. type Verifier interface { // UnmarshalKey takes key data to a working verifier implementation for the key type. - UnmarshalKey(key data.Key) error + UnmarshalKey(key *data.Key) error // This is the public string used as a unique identifier for the verifier instance. Public() string + // IDs returns the TUF key ids + IDs() []string + // Verify takes a message and signature, all as byte slices, // and determines whether the signature is valid for the given // key and message. @@ -35,6 +43,15 @@ type Verifier interface { } type Signer interface { + // Marshal into a private key. + MarshalPrivate() (*data.PrivateKey, error) + + // UnmarshalKey takes private key data to a working Signer implementation for the key type. + UnmarshalSigner(key *data.PrivateKey) error + + // Returns the public data.Key from the private key + PublicData() *data.Key + // IDs returns the TUF key ids IDs() []string @@ -52,24 +69,3 @@ type Signer interface { // provided as the message to Sign with a zero opts.HashFunc(). crypto.Signer } - -type PrivateKey struct { - Type string `json:"keytype"` - Scheme string `json:"scheme,omitempty"` - Algorithms []string `json:"keyid_hash_algorithms,omitempty"` - Value PrivateKeyValue `json:"keyval"` -} - -type PrivateKeyValue struct { - Public data.HexBytes `json:"public"` - Private data.HexBytes `json:"private"` -} - -func (k *PrivateKey) PublicData() *data.Key { - return &data.Key{ - Type: k.Type, - Scheme: k.Scheme, - Algorithms: k.Algorithms, - Value: data.KeyValue{Public: k.Value.Public}, - } -} diff --git a/keys/keys_test.go b/keys/keys_test.go index aa05b69e..fe6497ea 100644 --- a/keys/keys_test.go +++ b/keys/keys_test.go @@ -1,4 +1,4 @@ -package sign +package keys import ( "testing" @@ -16,21 +16,26 @@ var _ = Suite(&KeysSuite{}) func (KeysSuite) TestSignerKeyIDs(c *C) { key, err := GenerateEd25519Key() c.Assert(err, IsNil) - signer := key.Signer() - c.Assert(key.PublicData().IDs(), DeepEquals, signer.IDs()) + c.Assert(key.PublicData().IDs(), DeepEquals, key.IDs()) // If we have a TUF-0.9 key, we won't have a scheme. key, err = GenerateEd25519Key() c.Assert(err, IsNil) - key.Scheme = "" - signer = key.Signer() - c.Assert(key.PublicData().IDs(), DeepEquals, signer.IDs()) + privKey, err := key.MarshalPrivate() + c.Assert(err, IsNil) + privKey.Scheme = "" + err = key.UnmarshalSigner(*privKey) + c.Assert(err, IsNil) + c.Assert(key.PublicData().IDs(), DeepEquals, key.IDs()) // Make sure we preserve ids if we don't have any // keyid_hash_algorithms. key, err = GenerateEd25519Key() c.Assert(err, IsNil) - key.Algorithms = []string{} - signer = key.Signer() - c.Assert(key.PublicData().IDs(), DeepEquals, signer.IDs()) + privKey, err = key.MarshalPrivate() + c.Assert(err, IsNil) + privKey.Algorithms = []string{} + err = key.UnmarshalSigner(*privKey) + c.Assert(err, IsNil) + c.Assert(key.PublicData().IDs(), DeepEquals, key.IDs()) } diff --git a/local_store.go b/local_store.go index ca2d0a0e..594e663e 100644 --- a/local_store.go +++ b/local_store.go @@ -11,10 +11,29 @@ import ( "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/encrypted" - "github.com/theupdateframework/go-tuf/sign" + "github.com/theupdateframework/go-tuf/keys" "github.com/theupdateframework/go-tuf/util" ) +func privateKeySigners(privateKeys []*data.PrivateKey) []keys.Signer { + res := make([]keys.Signer, len(privateKeys)) + for i, k := range privateKeys { + svt, ok := keys.KeyMap.Load(k.Type) + if !ok { + continue + } + sv := svt.(func() keys.SignerVerifier)() + if sv.Signer == nil { + continue + } + if err := sv.Signer.UnmarshalSigner(k); err != nil { + continue + } + res[i] = sv.Signer + } + return res +} + func MemoryStore(meta map[string]json.RawMessage, files map[string][]byte) LocalStore { if meta == nil { meta = make(map[string]json.RawMessage) @@ -23,7 +42,7 @@ func MemoryStore(meta map[string]json.RawMessage, files map[string][]byte) Local meta: meta, stagedMeta: make(map[string]json.RawMessage), files: files, - signers: make(map[string][]sign.Signer), + signers: make(map[string][]*data.PrivateKey), } } @@ -31,7 +50,7 @@ type memoryStore struct { meta map[string]json.RawMessage stagedMeta map[string]json.RawMessage files map[string][]byte - signers map[string][]sign.Signer + signers map[string][]*data.PrivateKey } func (m *memoryStore) GetMeta() (map[string]json.RawMessage, error) { @@ -82,12 +101,12 @@ func (m *memoryStore) Commit(consistentSnapshot bool, versions map[string]int, h return nil } -func (m *memoryStore) GetSigningKeys(role string) ([]sign.Signer, error) { - return m.signers[role], nil +func (m *memoryStore) GetSigningKeys(role string) ([]keys.Signer, error) { + return privateKeySigners(m.signers[role]), nil } -func (m *memoryStore) SavePrivateKey(role string, key *sign.PrivateKey) error { - m.signers[role] = append(m.signers[role], key.Signer()) +func (m *memoryStore) SavePrivateKey(role string, key *data.PrivateKey) error { + m.signers[role] = append(m.signers[role], key) return nil } @@ -104,7 +123,7 @@ func FileSystemStore(dir string, p util.PassphraseFunc) LocalStore { return &fileSystemStore{ dir: dir, passphraseFunc: p, - signers: make(map[string][]sign.Signer), + signers: make(map[string][]keys.Signer), } } @@ -113,7 +132,7 @@ type fileSystemStore struct { passphraseFunc util.PassphraseFunc // signers is a cache of persisted keys to avoid decrypting multiple times - signers map[string][]sign.Signer + signers map[string][]keys.Signer } func (f *fileSystemStore) repoDir() string { @@ -304,7 +323,7 @@ func (f *fileSystemStore) Commit(consistentSnapshot bool, versions map[string]in return f.Clean() } -func (f *fileSystemStore) GetSigningKeys(role string) ([]sign.Signer, error) { +func (f *fileSystemStore) GetSigningKeys(role string) ([]keys.Signer, error) { if keys, ok := f.signers[role]; ok { return keys, nil } @@ -315,11 +334,11 @@ func (f *fileSystemStore) GetSigningKeys(role string) ([]sign.Signer, error) { } return nil, err } - f.signers[role] = f.privateKeySigners(keys) + f.signers[role] = privateKeySigners(keys) return f.signers[role], nil } -func (f *fileSystemStore) SavePrivateKey(role string, key *sign.PrivateKey) error { +func (f *fileSystemStore) SavePrivateKey(role string, key *data.PrivateKey) error { if err := f.createDirs(); err != nil { return err } @@ -362,21 +381,13 @@ func (f *fileSystemStore) SavePrivateKey(role string, key *sign.PrivateKey) erro if err := util.AtomicallyWriteFile(f.keysPath(role), append(data, '\n'), 0600); err != nil { return err } - f.signers[role] = f.privateKeySigners(keys) + f.signers[role] = privateKeySigners(keys) return nil } -func (f *fileSystemStore) privateKeySigners(keys []*sign.PrivateKey) []sign.Signer { - res := make([]sign.Signer, len(keys)) - for i, k := range keys { - res[i] = k.Signer() - } - return res -} - // loadKeys loads keys for the given role and returns them along with the // passphrase (if read) so that callers don't need to re-read it. -func (f *fileSystemStore) loadKeys(role string) ([]*sign.PrivateKey, []byte, error) { +func (f *fileSystemStore) loadKeys(role string) ([]*data.PrivateKey, []byte, error) { file, err := os.Open(f.keysPath(role)) if err != nil { return nil, nil, err @@ -388,7 +399,7 @@ func (f *fileSystemStore) loadKeys(role string) ([]*sign.PrivateKey, []byte, err return nil, nil, err } - var keys []*sign.PrivateKey + var keys []*data.PrivateKey if !pk.Encrypted { if err := json.Unmarshal(pk.Data, &keys); err != nil { return nil, nil, err diff --git a/repo.go b/repo.go index 552ab8b4..37b9e7a0 100644 --- a/repo.go +++ b/repo.go @@ -12,7 +12,6 @@ import ( cjson "github.com/tent/canonical-json-go" "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/keys" - tkeys "github.com/theupdateframework/go-tuf/keys" "github.com/theupdateframework/go-tuf/sign" "github.com/theupdateframework/go-tuf/util" "github.com/theupdateframework/go-tuf/verify" @@ -62,7 +61,7 @@ type LocalStore interface { GetSigningKeys(string) ([]keys.Signer, error) // SavePrivateKey adds a signing key to a role. - SavePrivateKey(string, *keys.PrivateKey) error + SavePrivateKey(string, *data.PrivateKey) error // Clean is used to remove all staged manifests. Clean() error @@ -325,18 +324,23 @@ func (r *Repo) GenKeyWithExpires(keyRole string, expires time.Time) ([]string, e return []string{}, err } - if err = r.AddPrivateKeyWithExpires(keyRole, key, expires); err != nil { + privKey, err := key.MarshalPrivate() + if err != nil { + return []string{}, err + } + + if err = r.AddPrivateKeyWithExpires(keyRole, privKey, expires); err != nil { return []string{}, err } return key.PublicData().IDs(), nil } -func (r *Repo) AddPrivateKey(role string, key *keys.PrivateKey) error { +func (r *Repo) AddPrivateKey(role string, key *data.PrivateKey) error { return r.AddPrivateKeyWithExpires(role, key, data.DefaultExpires(role)) } -func (r *Repo) AddPrivateKeyWithExpires(keyRole string, key *sign.PrivateKey, expires time.Time) error { +func (r *Repo) AddPrivateKeyWithExpires(keyRole string, key *data.PrivateKey, expires time.Time) error { if !verify.ValidRole(keyRole) { return ErrInvalidRole{keyRole} } @@ -394,6 +398,7 @@ func validExpires(expires time.Time) bool { return expires.Sub(time.Now()) > 0 } +/* // UniqueKeys returns the unique keys for each associated role. // We might have multiple key IDs that correspond to the same key. func (r Root) UniqueKeys() map[string][]*data.Key { @@ -425,6 +430,7 @@ func (r Root) UniqueKeys() map[string][]*data.Key { } return keysByRole } +*/ func (r *Repo) RootKeys() ([]*data.Key, error) { root, err := r.root() @@ -640,7 +646,7 @@ func (r *Repo) AddOrUpdateSignature(roleFilename string, signature data.Signatur // been revoked are omitted), except for the root role in which case all local // keys are returned (revoked root keys still need to sign new root metadata so // clients can verify the new root.json and update their keys db accordingly). -func (r *Repo) getSigningKeys(name string) ([]sign.Signer, error) { +func (r *Repo) getSigningKeys(name string) ([]keys.Signer, error) { signingKeys, err := r.local.GetSigningKeys(name) if err != nil { return nil, err @@ -659,7 +665,7 @@ func (r *Repo) getSigningKeys(name string) ([]sign.Signer, error) { if len(role.KeyIDs) == 0 { return nil, nil } - keys := make([]sign.Signer, 0, len(role.KeyIDs)) + keys := make([]keys.Signer, 0, len(role.KeyIDs)) for _, key := range signingKeys { for _, id := range key.IDs() { if _, ok := role.KeyIDs[id]; ok { diff --git a/repo_test.go b/repo_test.go index 9956464f..eaa7ee82 100644 --- a/repo_test.go +++ b/repo_test.go @@ -15,6 +15,7 @@ import ( "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/encrypted" + "github.com/theupdateframework/go-tuf/keys" "github.com/theupdateframework/go-tuf/sign" "github.com/theupdateframework/go-tuf/util" "github.com/theupdateframework/go-tuf/verify" @@ -39,9 +40,41 @@ func (RepoSuite) TestNewRepoIndent(c *C) { }) } +// UniqueKeys returns the unique keys for each associated role. +// We might have multiple key IDs that correspond to the same key. +func UniqueKeys(r *data.Root) map[string][]*data.Key { + keysByRole := make(map[string][]*data.Key) + for name, role := range r.Roles { + seen := make(map[string]struct{}) + roleKeys := []*data.Key{} + for _, id := range role.KeyIDs { + // Double-check that there is actually a key with that ID. + if key, ok := r.Keys[id]; ok { + if kt, found := keys.KeyMap.Load(key.Type); found { + k := kt.(func() keys.SignerVerifier)() + if k.Verifier != nil { + err := k.Verifier.UnmarshalKey(key) + if err != nil { + val := k.Verifier.Public() + if _, ok := seen[val]; ok { + continue + } + seen[val] = struct{}{} + roleKeys = append(roleKeys, key) + } + + } + } + } + } + keysByRole[name] = roleKeys + } + return keysByRole +} + // AssertNumUniqueKeys verifies that the number of unique root keys for a given role is as expected. func (*RepoSuite) assertNumUniqueKeys(c *C, root *data.Root, role string, num int) { - c.Assert(root.UniqueKeys()[role], HasLen, num) + c.Assert(UniqueKeys(root)[role], HasLen, num) } func testNewRepo(c *C, newRepo func(local LocalStore, hashAlgorithms ...string) (*Repo, error)) { diff --git a/verify/db.go b/verify/db.go index d38bb3ee..8aa34a81 100644 --- a/verify/db.go +++ b/verify/db.go @@ -17,13 +17,13 @@ func (r *Role) ValidKey(id string) bool { type DB struct { roles map[string]*Role - keys map[string]*data.Key + keys map[string]*keys.Verifier } func NewDB() *DB { return &DB{ roles: make(map[string]*Role), - keys: make(map[string]*data.Key), + keys: make(map[string]*keys.Verifier), } } @@ -41,7 +41,7 @@ func (d *DelegationsVerifier) Unmarshal(b []byte, v interface{}, role string, mi func NewDelegationsVerifier(d *data.Delegations) (DelegationsVerifier, error) { db := &DB{ roles: make(map[string]*Role, len(d.Roles)), - keys: make(map[string]*data.Key, len(d.Keys)), + keys: make(map[string]*keys.Verifier, len(d.Keys)), } for _, r := range d.Roles { if _, ok := topLevelRoles[r.Name]; ok { @@ -65,15 +65,18 @@ func (db *DB) AddKey(id string, k *data.Key) error { if !ok { return nil } - v := vt.(func() keys.Verifier)() if !k.ContainsID(id) { return ErrWrongID{} } - if !v.ValidKey(k.Value) { + v := vt.(func() keys.SignerVerifier)() + if v.Verifier != nil && !v.Verifier.ValidKey(k.Value) { + return ErrInvalidKey + } + if err := v.Verifier.UnmarshalKey(k); err != nil { return ErrInvalidKey } - db.keys[id] = k + db.keys[id] = &v.Verifier return nil } @@ -122,8 +125,8 @@ func (db *DB) addRole(name string, r *data.Role) error { return nil } -func (db *DB) GetKey(id string) *data.Key { - return db.keys[id] +func (db *DB) GetKey(id string) keys.Verifier { + return *db.keys[id] } func (db *DB) GetRole(name string) *Role { From 37cf05fa1cd94ef5ca415ca78461b7ee75db21f6 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Wed, 1 Sep 2021 10:40:17 -0500 Subject: [PATCH 03/17] working Signed-off-by: Asra Ali --- client/client_test.go | 11 +- client/python_interop/python_interop_test.go | 19 +- .../testdata/go-tuf-transition-M3/generate.go | 43 +++-- .../testdata/go-tuf-transition-M4/generate.go | 28 ++- client/testdata/go-tuf/generator/generator.go | 45 +++-- client/testdata/tools/gen-keys.go | 10 +- data/types.go | 10 -- data/types_test.go | 20 ++- go.mod | 1 + go.sum | 2 + keys/ecdsa.go | 12 +- keys/ed25519.go | 18 +- keys/keys.go | 3 + keys/keys_test.go | 4 +- local_store.go | 1 + repo.go | 59 ++----- repo_test.go | 165 +++++++++++------- verify/db.go | 7 +- verify/verify.go | 4 +- verify/verify_test.go | 42 +++-- 20 files changed, 309 insertions(+), 195 deletions(-) diff --git a/client/client_test.go b/client/client_test.go index a8ca536f..6c5bf068 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -14,6 +14,7 @@ import ( cjson "github.com/tent/canonical-json-go" tuf "github.com/theupdateframework/go-tuf" "github.com/theupdateframework/go-tuf/data" + "github.com/theupdateframework/go-tuf/keys" "github.com/theupdateframework/go-tuf/sign" "github.com/theupdateframework/go-tuf/util" "github.com/theupdateframework/go-tuf/verify" @@ -352,7 +353,7 @@ func (s *ClientSuite) TestNewRoot(c *C) { for _, id := range ids { key := client.db.GetKey(id) c.Assert(key, NotNil) - c.Assert(key.IDs(), DeepEquals, ids) + c.Assert((*key).IDs(), DeepEquals, ids) } role := client.db.GetRole(name) c.Assert(role, NotNil) @@ -410,7 +411,7 @@ func (s *ClientSuite) TestNewTimestampKey(c *C) { for _, newID := range newIDs { key := client.db.GetKey(newID) c.Assert(key, NotNil) - c.Assert(key.IDs(), DeepEquals, newIDs) + c.Assert((*key).IDs(), DeepEquals, newIDs) } role := client.db.GetRole("timestamp") c.Assert(role, NotNil) @@ -449,7 +450,7 @@ func (s *ClientSuite) TestNewSnapshotKey(c *C) { for _, newID := range newIDs { key := client.db.GetKey(newID) c.Assert(key, NotNil) - c.Assert(key.IDs(), DeepEquals, newIDs) + c.Assert((*key).IDs(), DeepEquals, newIDs) } role := client.db.GetRole("snapshot") c.Assert(role, NotNil) @@ -491,7 +492,7 @@ func (s *ClientSuite) TestNewTargetsKey(c *C) { for _, newID := range newIDs { key := client.db.GetKey(newID) c.Assert(key, NotNil) - c.Assert(key.IDs(), DeepEquals, newIDs) + c.Assert((*key).IDs(), DeepEquals, newIDs) } role := client.db.GetRole("targets") c.Assert(role, NotNil) @@ -914,7 +915,7 @@ func (s *ClientSuite) TestUnknownKeyIDs(c *C) { c.Assert(json.Unmarshal(rootJSON, &root), IsNil) // update remote root.json to add a new key with an unknown id - key, err := sign.GenerateEd25519Key() + key, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) root.Signed.Keys["unknown-key-id"] = key.PublicData() diff --git a/client/python_interop/python_interop_test.go b/client/python_interop/python_interop_test.go index da2f2b63..95813653 100644 --- a/client/python_interop/python_interop_test.go +++ b/client/python_interop/python_interop_test.go @@ -15,6 +15,7 @@ import ( tuf "github.com/theupdateframework/go-tuf" client "github.com/theupdateframework/go-tuf/client" "github.com/theupdateframework/go-tuf/data" + "github.com/theupdateframework/go-tuf/keys" "github.com/theupdateframework/go-tuf/util" "golang.org/x/crypto/ed25519" . "gopkg.in/check.v1" @@ -42,6 +43,21 @@ func (t *testDestination) Delete() error { return nil } +func getVerifier(c *C, key *data.Key) keys.Verifier { + vt, ok := keys.KeyMap.Load(key.Type) + if !ok { + c.Errorf("error loading key implementation") + } + v := vt.(func() keys.SignerVerifier)() + if v.Verifier == nil { + c.Errorf("error loading verifier implementation") + } + if err := v.Verifier.UnmarshalKey(key); err != nil { + c.Errorf("error unmarshalling key") + } + return v.Verifier +} + func (InteropSuite) TestGoClientPythonGenerated(c *C) { // start file server cwd, err := os.Getwd() @@ -64,7 +80,8 @@ func (InteropSuite) TestGoClientPythonGenerated(c *C) { key := &data.Key{} c.Assert(json.NewDecoder(f).Decode(key), IsNil) c.Assert(key.Type, Equals, "ed25519") - c.Assert(key.Value.Public, HasLen, ed25519.PublicKeySize) + pk := getVerifier(c, key) + c.Assert(pk.Public(), HasLen, ed25519.PublicKeySize) client := client.NewClient(client.MemoryLocalStore(), remote) c.Assert(client.Init([]*data.Key{key}, 1), IsNil) diff --git a/client/testdata/go-tuf-transition-M3/generate.go b/client/testdata/go-tuf-transition-M3/generate.go index 43a1f2f5..fbbbb3db 100644 --- a/client/testdata/go-tuf-transition-M3/generate.go +++ b/client/testdata/go-tuf-transition-M3/generate.go @@ -11,14 +11,15 @@ import ( "time" tuf "github.com/theupdateframework/go-tuf" - "github.com/theupdateframework/go-tuf/sign" + "github.com/theupdateframework/go-tuf/data" + "github.com/theupdateframework/go-tuf/keys" ) var expirationDate = time.Date(2100, time.January, 1, 0, 0, 0, 0, time.UTC) type persistedKeys struct { Encrypted bool `json:"encrypted"` - Data []*sign.PrivateKey `json:"data"` + Data []*data.PrivateKey `json:"data"` } func assertNotNil(err error) { @@ -48,10 +49,19 @@ func commit(dir string, repo *tuf.Repo) { assertNotNil(os.RemoveAll(filepath.Join(dir, "keys"))) } -func addKeys(repo *tuf.Repo, roleKeys map[string][]*sign.PrivateKey) { - for role, keys := range roleKeys { - for _, key := range keys { - assertNotNil(repo.AddPrivateKeyWithExpires(role, key, expirationDate)) +func addKeys(repo *tuf.Repo, roleKeys map[string][]*data.PrivateKey) { + for role, keyList := range roleKeys { + for _, key := range keyList { + st, ok := keys.KeyMap.Load(key.Type) + if !ok { + panic(fmt.Printf("error loading key implementation")) + } + s := st.(func() keys.SignerVerifier)() + if s.Signer == nil { + panic(fmt.Printf("error loading signer implementation")) + } + assertNotNil(s.Signer.UnmarshalSigner(key)) + assertNotNil(repo.AddPrivateKeyWithExpires(role, s.Signer, expirationDate)) } } } @@ -67,9 +77,18 @@ func addTargets(repo *tuf.Repo, dir string, files map[string][]byte) { assertNotNil(repo.AddTargetsWithExpires(paths, nil, expirationDate)) } -func revokeKeys(repo *tuf.Repo, role string, keys []*sign.PrivateKey) { - for _, key := range keys { - assertNotNil(repo.RevokeKeyWithExpires(role, key.PublicData().IDs()[0], expirationDate)) +func revokeKeys(repo *tuf.Repo, role string, keyList []*data.PrivateKey) { + for _, key := range keyList { + st, ok := keys.KeyMap.Load(key.Type) + if !ok { + panic("error loading key implementation") + } + s := st.(func() keys.SignerVerifier)() + if s.Signer == nil { + panic("error loading signer implementation") + } + assertNotNil(s.Signer.UnmarshalSigner(key)) + assertNotNil(repo.RevokeKeyWithExpires(role, s.Signer.IDs()[0], expirationDate)) } } @@ -77,12 +96,12 @@ func generateRepos(dir string, consistentSnapshot bool) { f, err := os.Open("../keys.json") assertNotNil(err) - var roleKeys map[string][][]*sign.PrivateKey + var roleKeys map[string][][]*data.PrivateKey assertNotNil(json.NewDecoder(f).Decode(&roleKeys)) // Collect all the initial keys we'll use when creating repositories. // We'll modify this to reflect rotated keys. - keys := map[string][]*sign.PrivateKey{ + keys := map[string][]*data.PrivateKey{ "root": roleKeys["root"][0], "targets": roleKeys["targets"][0], "snapshot": roleKeys["snapshot"][0], @@ -110,7 +129,7 @@ func generateRepos(dir string, consistentSnapshot bool) { // Actually rotate the keys revokeKeys(repo, role, roleKeys[role][0]) - addKeys(repo, map[string][]*sign.PrivateKey{ + addKeys(repo, map[string][]*data.PrivateKey{ role: roleKeys[role][1], }) keys[role] = roleKeys[role][1] diff --git a/client/testdata/go-tuf-transition-M4/generate.go b/client/testdata/go-tuf-transition-M4/generate.go index 43a1f2f5..0e71ab55 100644 --- a/client/testdata/go-tuf-transition-M4/generate.go +++ b/client/testdata/go-tuf-transition-M4/generate.go @@ -11,14 +11,15 @@ import ( "time" tuf "github.com/theupdateframework/go-tuf" - "github.com/theupdateframework/go-tuf/sign" + "github.com/theupdateframework/go-tuf/data" + "github.com/theupdateframework/go-tuf/keys" ) var expirationDate = time.Date(2100, time.January, 1, 0, 0, 0, 0, time.UTC) type persistedKeys struct { Encrypted bool `json:"encrypted"` - Data []*sign.PrivateKey `json:"data"` + Data []*data.PrivateKey `json:"data"` } func assertNotNil(err error) { @@ -48,7 +49,7 @@ func commit(dir string, repo *tuf.Repo) { assertNotNil(os.RemoveAll(filepath.Join(dir, "keys"))) } -func addKeys(repo *tuf.Repo, roleKeys map[string][]*sign.PrivateKey) { +func addKeys(repo *tuf.Repo, roleKeys map[string][]*data.PrivateKey) { for role, keys := range roleKeys { for _, key := range keys { assertNotNil(repo.AddPrivateKeyWithExpires(role, key, expirationDate)) @@ -67,9 +68,18 @@ func addTargets(repo *tuf.Repo, dir string, files map[string][]byte) { assertNotNil(repo.AddTargetsWithExpires(paths, nil, expirationDate)) } -func revokeKeys(repo *tuf.Repo, role string, keys []*sign.PrivateKey) { - for _, key := range keys { - assertNotNil(repo.RevokeKeyWithExpires(role, key.PublicData().IDs()[0], expirationDate)) +func revokeKeys(repo *tuf.Repo, role string, keyList []*data.PrivateKey) { + for _, key := range keyList { + st, ok := keys.KeyMap.Load(key.Type) + if !ok { + panic("error loading key implementation") + } + s := st.(func() keys.SignerVerifier)() + if s.Signer == nil { + panic("error loading signer implementation") + } + assertNotNil(s.Signer.UnmarshalSigner(key)) + assertNotNil(repo.RevokeKeyWithExpires(role, s.Signer.PublicData().IDs()[0], expirationDate)) } } @@ -77,12 +87,12 @@ func generateRepos(dir string, consistentSnapshot bool) { f, err := os.Open("../keys.json") assertNotNil(err) - var roleKeys map[string][][]*sign.PrivateKey + var roleKeys map[string][][]*data.PrivateKey assertNotNil(json.NewDecoder(f).Decode(&roleKeys)) // Collect all the initial keys we'll use when creating repositories. // We'll modify this to reflect rotated keys. - keys := map[string][]*sign.PrivateKey{ + keys := map[string][]*data.PrivateKey{ "root": roleKeys["root"][0], "targets": roleKeys["targets"][0], "snapshot": roleKeys["snapshot"][0], @@ -110,7 +120,7 @@ func generateRepos(dir string, consistentSnapshot bool) { // Actually rotate the keys revokeKeys(repo, role, roleKeys[role][0]) - addKeys(repo, map[string][]*sign.PrivateKey{ + addKeys(repo, map[string][]*data.PrivateKey{ role: roleKeys[role][1], }) keys[role] = roleKeys[role][1] diff --git a/client/testdata/go-tuf/generator/generator.go b/client/testdata/go-tuf/generator/generator.go index a1a616ee..9b27c80e 100644 --- a/client/testdata/go-tuf/generator/generator.go +++ b/client/testdata/go-tuf/generator/generator.go @@ -11,14 +11,15 @@ import ( "time" tuf "github.com/theupdateframework/go-tuf" - "github.com/theupdateframework/go-tuf/sign" + "github.com/theupdateframework/go-tuf/data" + "github.com/theupdateframework/go-tuf/keys" ) var expirationDate = time.Date(2100, time.January, 1, 0, 0, 0, 0, time.UTC) type persistedKeys struct { Encrypted bool `json:"encrypted"` - Data []*sign.PrivateKey `json:"data"` + Data []*data.PrivateKey `json:"data"` } func assertNotNil(err error) { @@ -48,10 +49,19 @@ func commit(dir string, repo *tuf.Repo) { assertNotNil(os.RemoveAll(filepath.Join(dir, "keys"))) } -func addKeys(repo *tuf.Repo, roleKeys map[string][]*sign.PrivateKey) { - for role, keys := range roleKeys { - for _, key := range keys { - assertNotNil(repo.AddPrivateKeyWithExpires(role, key, expirationDate)) +func addKeys(repo *tuf.Repo, roleKeys map[string][]*data.PrivateKey) { + for role, keyList := range roleKeys { + for _, key := range keyList { + st, ok := keys.KeyMap.Load(key.Type) + if !ok { + panic("error loading key implementation") + } + s := st.(func() keys.SignerVerifier)() + if s.Signer == nil { + panic("error loading signer implementation") + } + assertNotNil(s.Signer.UnmarshalSigner(key)) + assertNotNil(repo.AddPrivateKeyWithExpires(role, s.Signer, expirationDate)) } } } @@ -67,16 +77,25 @@ func addTargets(repo *tuf.Repo, dir string, files map[string][]byte) { assertNotNil(repo.AddTargetsWithExpires(paths, nil, expirationDate)) } -func revokeKeys(repo *tuf.Repo, role string, keys []*sign.PrivateKey) { - for _, key := range keys { - assertNotNil(repo.RevokeKeyWithExpires(role, key.PublicData().IDs()[0], expirationDate)) +func revokeKeys(repo *tuf.Repo, role string, keyList []*data.PrivateKey) { + for _, key := range keyList { + st, ok := keys.KeyMap.Load(key.Type) + if !ok { + panic("error loading key implementation") + } + s := st.(func() keys.SignerVerifier)() + if s.Signer == nil { + panic("error loading signer implementation") + } + assertNotNil(s.Signer.UnmarshalSigner(key)) + assertNotNil(repo.RevokeKeyWithExpires(role, s.Signer.IDs()[0], expirationDate)) } } -func generateRepos(dir string, roleKeys map[string][][]*sign.PrivateKey, consistentSnapshot bool) { +func generateRepos(dir string, roleKeys map[string][][]*data.PrivateKey, consistentSnapshot bool) { // Collect all the initial keys we'll use when creating repositories. // We'll modify this to reflect rotated keys. - keys := map[string][]*sign.PrivateKey{ + keys := map[string][]*data.PrivateKey{ "root": roleKeys["root"][0], "targets": roleKeys["targets"][0], "snapshot": roleKeys["snapshot"][0], @@ -104,7 +123,7 @@ func generateRepos(dir string, roleKeys map[string][][]*sign.PrivateKey, consist // Actually rotate the keys revokeKeys(repo, role, roleKeys[role][0]) - addKeys(repo, map[string][]*sign.PrivateKey{ + addKeys(repo, map[string][]*data.PrivateKey{ role: roleKeys[role][1], }) keys[role] = roleKeys[role][1] @@ -131,7 +150,7 @@ func Generate(dir string, keysPath string, consistentSnapshot bool) { f, err := os.Open(keysPath) assertNotNil(err) - var roleKeys map[string][][]*sign.PrivateKey + var roleKeys map[string][][]*data.PrivateKey assertNotNil(json.NewDecoder(f).Decode(&roleKeys)) log.Printf("generating %s", dir) diff --git a/client/testdata/tools/gen-keys.go b/client/testdata/tools/gen-keys.go index 5602d055..64838265 100644 --- a/client/testdata/tools/gen-keys.go +++ b/client/testdata/tools/gen-keys.go @@ -10,7 +10,7 @@ import ( "io/ioutil" "time" - sign "github.com/theupdateframework/go-tuf/sign" + "github.com/theupdateframework/go-tuf/data" ) var expirationDate = time.Date(2100, time.January, 1, 0, 0, 0, 0, time.UTC) @@ -23,15 +23,15 @@ func main() { "timestamp", } - roles := make(map[string][][]*sign.PrivateKey) + roles := make(map[string][][]*data.PrivateKey) for _, name := range rolenames { - keys := [][]*sign.PrivateKey{} + keys := [][]*data.PrivateKey{} for i := 0; i < 2; i++ { - key, err := sign.GenerateEd25519Key() + key, err := keys.GenerateEd25519Key() assertNotNil(err) - keys = append(keys, []*sign.PrivateKey{key}) + keys = append(keys, []*data.PrivateKey{key}) } roles[name] = keys diff --git a/data/types.go b/data/types.go index 00da1a16..ed1b45cc 100644 --- a/data/types.go +++ b/data/types.go @@ -51,16 +51,6 @@ type PrivateKey struct { Scheme string `json:"scheme,omitempty"` Algorithms []string `json:"keyid_hash_algorithms,omitempty"` Value json.RawMessage `json:"keyval"` - Private json.RawMessage -} - -func (k *PrivateKey) PublicData() *Key { - return &Key{ - Type: k.Type, - Scheme: k.Scheme, - Algorithms: k.Algorithms, - Value: k.Value, - } } func (k *Key) IDs() []string { diff --git a/data/types_test.go b/data/types_test.go index 4b64cec8..31a7856b 100644 --- a/data/types_test.go +++ b/data/types_test.go @@ -23,15 +23,21 @@ type TypesSuite struct{} var _ = Suite(&TypesSuite{}) +type ed25519Public struct { + PublicKey HexBytes `json:"public"` +} + func (TypesSuite) TestKeyIDs(c *C) { var hexbytes HexBytes err := json.Unmarshal([]byte(public), &hexbytes) c.Assert(err, IsNil) + keyValBytes, err := json.Marshal(ed25519Public{PublicKey: hexbytes}) + c.Assert(err, IsNil) key := Key{ Type: KeyTypeEd25519, Scheme: KeySchemeEd25519, - Value: KeyValue{Public: hexbytes}, + Value: keyValBytes, } c.Assert(key.IDs(), DeepEquals, []string{keyid10}) @@ -39,7 +45,7 @@ func (TypesSuite) TestKeyIDs(c *C) { Type: KeyTypeEd25519, Scheme: KeySchemeEd25519, Algorithms: KeyAlgorithms, - Value: KeyValue{Public: hexbytes}, + Value: keyValBytes, } c.Assert(key.IDs(), DeepEquals, []string{keyid10algos}) } @@ -48,11 +54,13 @@ func (TypesSuite) TestRootAddKey(c *C) { var hexbytes HexBytes err := json.Unmarshal([]byte(public), &hexbytes) c.Assert(err, IsNil) + keyValBytes, _ := json.Marshal(ed25519Public{PublicKey: hexbytes}) + c.Assert(err, IsNil) key := &Key{ Type: KeyTypeEd25519, Scheme: KeySchemeEd25519, - Value: KeyValue{Public: hexbytes}, + Value: keyValBytes, } root := NewRoot() @@ -65,11 +73,13 @@ func (TypesSuite) TestRoleAddKeyIDs(c *C) { var hexbytes HexBytes err := json.Unmarshal([]byte(public), &hexbytes) c.Assert(err, IsNil) + keyValBytes, err := json.Marshal(ed25519Public{PublicKey: hexbytes}) + c.Assert(err, IsNil) key := &Key{ Type: KeyTypeEd25519, Scheme: KeySchemeEd25519, - Value: KeyValue{Public: hexbytes}, + Value: keyValBytes, } role := &Role{} @@ -87,7 +97,7 @@ func (TypesSuite) TestRoleAddKeyIDs(c *C) { Type: KeyTypeEd25519, Scheme: KeySchemeEd25519, Algorithms: KeyAlgorithms, - Value: KeyValue{Public: hexbytes}, + Value: keyValBytes, } // Adding the key again doesn't modify the array. diff --git a/go.mod b/go.mod index 47b72185..ccc2031e 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/dustin/go-humanize v1.0.0 github.com/flynn/go-docopt v0.0.0-20140912013429-f6dd2ebbb31e github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.7.0 // indirect github.com/syndtr/goleveldb v1.0.0 github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 diff --git a/go.sum b/go.sum index 7dd8a821..8fef189e 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/keys/ecdsa.go b/keys/ecdsa.go index 31b2ca10..f5041ced 100644 --- a/keys/ecdsa.go +++ b/keys/ecdsa.go @@ -58,17 +58,21 @@ func (p p256Verifier) Verify(msg, sigBytes []byte) error { return nil } -func (p p256Verifier) ValidKey(v json.RawMessage) bool { - if err := json.Unmarshal(v, &p.PublicKey); err != nil { +func (p *p256Verifier) ValidKey(v json.RawMessage) bool { + if err := json.Unmarshal(v, p); err != nil { return false } x, _ := elliptic.Unmarshal(elliptic.P256(), p.PublicKey) return x != nil } -func (p p256Verifier) UnmarshalKey(key *data.Key) error { +func (p p256Verifier) Key() *data.Key { + return p.key +} + +func (p *p256Verifier) UnmarshalKey(key *data.Key) error { p.key = key - return json.Unmarshal(key.Value, &p.PublicKey) + return json.Unmarshal(key.Value, p) } func (p *p256Verifier) IDs() []string { diff --git a/keys/ed25519.go b/keys/ed25519.go index 12cc111a..e8069db7 100644 --- a/keys/ed25519.go +++ b/keys/ed25519.go @@ -37,16 +37,20 @@ func (e ed25519Verifier) Verify(msg, sig []byte) error { return nil } -func (e ed25519Verifier) ValidKey(v json.RawMessage) bool { - if err := json.Unmarshal(v, &e.PublicKey); err != nil { +func (e *ed25519Verifier) ValidKey(v json.RawMessage) bool { + if err := json.Unmarshal(v, e); err != nil { return false } return len(e.PublicKey) == ed25519.PublicKeySize } -func (e ed25519Verifier) UnmarshalKey(key *data.Key) error { +func (e ed25519Verifier) Key() *data.Key { + return e.key +} + +func (e *ed25519Verifier) UnmarshalKey(key *data.Key) error { e.key = key - return json.Unmarshal(key.Value, &e.PublicKey) + return json.Unmarshal(key.Value, e) } func (e ed25519Verifier) IDs() []string { @@ -90,13 +94,13 @@ func (e ed25519Signer) MarshalPrivate() (*data.PrivateKey, error) { }, nil } -func (e ed25519Signer) UnmarshalSigner(key *data.PrivateKey) error { +func (e *ed25519Signer) UnmarshalSigner(key *data.PrivateKey) error { keyValue := &ed25519PrivateKeyValue{} if err := json.Unmarshal(key.Value, keyValue); err != nil { return err } - e = ed25519Signer{ - PrivateKey: ed25519.PrivateKey(keyValue.Private), + *e = ed25519Signer{ + PrivateKey: ed25519.PrivateKey(data.HexBytes(keyValue.Private)), keyType: key.Type, keyScheme: key.Scheme, keyAlgorithms: key.Algorithms, diff --git a/keys/keys.go b/keys/keys.go index ad1c6757..8198cd9a 100644 --- a/keys/keys.go +++ b/keys/keys.go @@ -40,6 +40,9 @@ type Verifier interface { // ValidKey returns true if the provided public key is valid and usable to // verify signatures with this verifier. ValidKey(value json.RawMessage) bool + + // Key returns the data.Key object associated with the verifier. + Key() *data.Key } type Signer interface { diff --git a/keys/keys_test.go b/keys/keys_test.go index fe6497ea..481fc107 100644 --- a/keys/keys_test.go +++ b/keys/keys_test.go @@ -24,7 +24,7 @@ func (KeysSuite) TestSignerKeyIDs(c *C) { privKey, err := key.MarshalPrivate() c.Assert(err, IsNil) privKey.Scheme = "" - err = key.UnmarshalSigner(*privKey) + err = key.UnmarshalSigner(privKey) c.Assert(err, IsNil) c.Assert(key.PublicData().IDs(), DeepEquals, key.IDs()) @@ -35,7 +35,7 @@ func (KeysSuite) TestSignerKeyIDs(c *C) { privKey, err = key.MarshalPrivate() c.Assert(err, IsNil) privKey.Algorithms = []string{} - err = key.UnmarshalSigner(*privKey) + err = key.UnmarshalSigner(privKey) c.Assert(err, IsNil) c.Assert(key.PublicData().IDs(), DeepEquals, key.IDs()) } diff --git a/local_store.go b/local_store.go index 594e663e..43b7e361 100644 --- a/local_store.go +++ b/local_store.go @@ -30,6 +30,7 @@ func privateKeySigners(privateKeys []*data.PrivateKey) []keys.Signer { continue } res[i] = sv.Signer + _ = sv.Signer.IDs() } return res } diff --git a/repo.go b/repo.go index 37b9e7a0..fb76a3a8 100644 --- a/repo.go +++ b/repo.go @@ -324,23 +324,18 @@ func (r *Repo) GenKeyWithExpires(keyRole string, expires time.Time) ([]string, e return []string{}, err } - privKey, err := key.MarshalPrivate() - if err != nil { - return []string{}, err - } - - if err = r.AddPrivateKeyWithExpires(keyRole, privKey, expires); err != nil { + if err = r.AddPrivateKeyWithExpires(keyRole, key, expires); err != nil { return []string{}, err } return key.PublicData().IDs(), nil } -func (r *Repo) AddPrivateKey(role string, key *data.PrivateKey) error { +func (r *Repo) AddPrivateKey(role string, key keys.Signer) error { return r.AddPrivateKeyWithExpires(role, key, data.DefaultExpires(role)) } -func (r *Repo) AddPrivateKeyWithExpires(keyRole string, key *data.PrivateKey, expires time.Time) error { +func (r *Repo) AddPrivateKeyWithExpires(keyRole string, key keys.Signer, expires time.Time) error { if !verify.ValidRole(keyRole) { return ErrInvalidRole{keyRole} } @@ -349,12 +344,20 @@ func (r *Repo) AddPrivateKeyWithExpires(keyRole string, key *data.PrivateKey, ex return ErrInvalidExpires{expires} } - if err := r.local.SavePrivateKey(keyRole, key); err != nil { + privKey, err := key.MarshalPrivate() + if err != nil { + return err + } + + if err := r.local.SavePrivateKey(keyRole, privKey); err != nil { return err } - pk := key.PublicData() - return r.AddVerificationKeyWithExpiration(keyRole, pk, expires) + if err = r.AddVerificationKeyWithExpiration(keyRole, key.PublicData(), expires); err != nil { + return err + } + + return nil } func (r *Repo) AddVerificationKey(keyRole string, pk *data.Key) error { @@ -399,38 +402,8 @@ func validExpires(expires time.Time) bool { } /* -// UniqueKeys returns the unique keys for each associated role. -// We might have multiple key IDs that correspond to the same key. -func (r Root) UniqueKeys() map[string][]*data.Key { - keysByRole := make(map[string][]*data.Key) - for name, role := range r.Roles { - seen := make(map[string]struct{}) - keys := []*data.Key{} - for _, id := range role.KeyIDs { - // Double-check that there is actually a key with that ID. - if key, ok := r.Keys[id]; ok { - if kt, found := tkeys.KeyMap.Load(key.Type); found { - k := kt.(func() tkeys.Verifier)() - if k != nil { - key, err := k.UnmarshalKey(key) - if err != nil { - val := key.Public() - if _, ok := seen[val]; ok { - continue - } - seen[val] = struct{}{} - keys = append(keys, key) - } - - } - } - } - } - keysByRole[name] = keys - } - return keysByRole -} -*/ + + */ func (r *Repo) RootKeys() ([]*data.Key, error) { root, err := r.root() diff --git a/repo_test.go b/repo_test.go index eaa7ee82..94dd5bcb 100644 --- a/repo_test.go +++ b/repo_test.go @@ -16,7 +16,6 @@ import ( "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/encrypted" "github.com/theupdateframework/go-tuf/keys" - "github.com/theupdateframework/go-tuf/sign" "github.com/theupdateframework/go-tuf/util" "github.com/theupdateframework/go-tuf/verify" "golang.org/x/crypto/ed25519" @@ -54,7 +53,7 @@ func UniqueKeys(r *data.Root) map[string][]*data.Key { k := kt.(func() keys.SignerVerifier)() if k.Verifier != nil { err := k.Verifier.UnmarshalKey(key) - if err != nil { + if err == nil { val := k.Verifier.Public() if _, ok := seen[val]; ok { continue @@ -62,7 +61,6 @@ func UniqueKeys(r *data.Root) map[string][]*data.Key { seen[val] = struct{}{} roleKeys = append(roleKeys, key) } - } } } @@ -77,6 +75,36 @@ func (*RepoSuite) assertNumUniqueKeys(c *C, root *data.Root, role string, num in c.Assert(UniqueKeys(root)[role], HasLen, num) } +func (*RepoSuite) getVerifier(c *C, key *data.Key) keys.Verifier { + vt, ok := keys.KeyMap.Load(key.Type) + if !ok { + c.Errorf("error loading key implementation") + } + v := vt.(func() keys.SignerVerifier)() + if v.Verifier == nil { + c.Errorf("error loading verifier implementation") + } + if err := v.Verifier.UnmarshalKey(key); err != nil { + c.Errorf("error unmarshalling key") + } + return v.Verifier +} + +func getSigner(c *C, key *data.PrivateKey) keys.Signer { + vt, ok := keys.KeyMap.Load(key.Type) + if !ok { + c.Errorf("error loading key implementation") + } + v := vt.(func() keys.SignerVerifier)() + if v.Signer == nil { + c.Errorf("error loading signer implementation") + } + if err := v.Signer.UnmarshalSigner(key); err != nil { + c.Errorf("error unmarshalling key") + } + return v.Signer +} + func testNewRepo(c *C, newRepo func(local LocalStore, hashAlgorithms ...string) (*Repo, error)) { meta := map[string]json.RawMessage{ "root.json": []byte(`{ @@ -208,7 +236,8 @@ func (rs *RepoSuite) TestGenKey(c *C) { c.Fatal("missing key") } c.Assert(k.IDs(), DeepEquals, ids) - c.Assert(k.Value.Public, HasLen, ed25519.PublicKeySize) + pk := rs.getVerifier(c, k) + c.Assert(pk.Public(), HasLen, ed25519.PublicKeySize) } // check root key + role are in db @@ -217,7 +246,7 @@ func (rs *RepoSuite) TestGenKey(c *C) { for _, keyID := range ids { rootKey := db.GetKey(keyID) c.Assert(rootKey, NotNil) - c.Assert(rootKey.IDs(), DeepEquals, ids) + c.Assert((*rootKey).IDs(), DeepEquals, ids) role := db.GetRole("root") c.Assert(role.KeyIDs, DeepEquals, util.StringSliceToSet(ids)) @@ -231,8 +260,9 @@ func (rs *RepoSuite) TestGenKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) - c.Assert(rootKeys[0].Value.Public, DeepEquals, rootKey.Value.Public) + c.Assert(rootKeys[0].IDs(), DeepEquals, (*rootKey).IDs()) + pk := rs.getVerifier(c, rootKeys[0]) + c.Assert(pk.Public(), DeepEquals, (*rootKey).Public()) } rootKey := db.GetKey(ids[0]) @@ -264,7 +294,7 @@ func (rs *RepoSuite) TestGenKey(c *C) { } key := db.GetKey(id) c.Assert(key, NotNil) - c.Assert(key.ContainsID(id), Equals, true) + c.Assert((*key).Key().ContainsID(id), Equals, true) } role := db.GetRole("targets") c.Assert(role.KeyIDs, DeepEquals, targetKeyIDs) @@ -273,7 +303,7 @@ func (rs *RepoSuite) TestGenKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, (*rootKey).IDs()) // check the keys were saved correctly localKeys, err := local.GetSigningKeys("targets") @@ -320,7 +350,7 @@ func (rs *RepoSuite) TestGenKey(c *C) { c.Assert(stagedRoot.Roles, DeepEquals, root.Roles) } -func addPrivateKey(c *C, r *Repo, role string, key *sign.PrivateKey) []string { +func addPrivateKey(c *C, r *Repo, role string, key keys.Signer) []string { err := r.AddPrivateKey(role, key) c.Assert(err, IsNil) keyids := key.PublicData().IDs() @@ -329,7 +359,7 @@ func addPrivateKey(c *C, r *Repo, role string, key *sign.PrivateKey) []string { } func addGeneratedPrivateKey(c *C, r *Repo, role string) []string { - key, err := sign.GenerateEd25519Key() + key, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) return addPrivateKey(c, r, role, key) } @@ -340,7 +370,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { c.Assert(err, IsNil) // generate a key for an unknown role - key, err := sign.GenerateEd25519Key() + key, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) err = r.AddPrivateKey("foo", key) c.Assert(err, Equals, ErrInvalidRole{"foo"}) @@ -367,7 +397,8 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { c.Fatalf("missing key %s", keyID) } c.Assert(k.IDs(), DeepEquals, ids) - c.Assert(k.Value.Public, HasLen, ed25519.PublicKeySize) + pk := rs.getVerifier(c, k) + c.Assert(pk.Public(), HasLen, ed25519.PublicKeySize) } // check root key + role are in db @@ -376,7 +407,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { for _, keyID := range ids { rootKey := db.GetKey(keyID) c.Assert(rootKey, NotNil) - c.Assert(rootKey.IDs(), DeepEquals, ids) + c.Assert((*rootKey).IDs(), DeepEquals, ids) role := db.GetRole("root") c.Assert(role.KeyIDs, DeepEquals, util.StringSliceToSet(ids)) @@ -390,8 +421,9 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) - c.Assert(rootKeys[0].Value.Public, DeepEquals, rootKey.Value.Public) + c.Assert(rootKeys[0].IDs(), DeepEquals, (*rootKey).IDs()) + pk := rs.getVerifier(c, rootKeys[0]) + c.Assert(pk.Public(), DeepEquals, (*rootKey).Public()) } rootKey := db.GetKey(ids[0]) @@ -423,7 +455,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { } key := db.GetKey(id) c.Assert(key, NotNil) - c.Assert(key.ContainsID(id), Equals, true) + c.Assert((*key).Key().ContainsID(id), Equals, true) } role := db.GetRole("targets") c.Assert(role.KeyIDs, DeepEquals, targetKeyIDs) @@ -432,7 +464,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, (*rootKey).IDs()) // check the keys were saved correctly localKeys, err := local.GetSigningKeys("targets") @@ -582,9 +614,11 @@ func (rs *RepoSuite) TestSign(c *C) { } // signing with an available key generates a signature - key, err := sign.GenerateEd25519Key() + key, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - c.Assert(local.SavePrivateKey("root", key), IsNil) + privateKey, err := key.MarshalPrivate() + c.Assert(err, IsNil) + c.Assert(local.SavePrivateKey("root", privateKey), IsNil) c.Assert(r.Sign("root.json"), IsNil) checkSigIDs(key.PublicData().IDs()...) @@ -593,9 +627,11 @@ func (rs *RepoSuite) TestSign(c *C) { checkSigIDs(key.PublicData().IDs()...) // signing with a new available key generates another signature - newKey, err := sign.GenerateEd25519Key() + newKey, err := keys.GenerateEd25519Key() + c.Assert(err, IsNil) + newPrivateKey, err := newKey.MarshalPrivate() c.Assert(err, IsNil) - c.Assert(local.SavePrivateKey("root", newKey), IsNil) + c.Assert(local.SavePrivateKey("root", newPrivateKey), IsNil) c.Assert(r.Sign("root.json"), IsNil) checkSigIDs(append(key.PublicData().IDs(), newKey.PublicData().IDs()...)...) } @@ -1190,13 +1226,13 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) { passphrase := []byte("s3cr3t") store := FileSystemStore(tmp.path, testPassphraseFunc(passphrase)) - assertKeys := func(role string, enc bool, expected []*sign.PrivateKey) { + assertKeys := func(role string, enc bool, expected []*data.PrivateKey) { keysJSON := tmp.readFile("keys/" + role + ".json") pk := &persistedKeys{} c.Assert(json.Unmarshal(keysJSON, pk), IsNil) // check the persisted keys are correct - var actual []*sign.PrivateKey + var actual []*data.PrivateKey if enc { c.Assert(pk.Encrypted, Equals, true) decrypted, err := encrypted.Decrypt(pk.Data, passphrase) @@ -1216,33 +1252,42 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) { c.Assert(err, IsNil) c.Assert(signers, HasLen, len(expected)) for i, s := range signers { - c.Assert(s.IDs(), DeepEquals, expected[i].PublicData().IDs()) + v := getSigner(c, expected[i]) + c.Assert(s.IDs(), DeepEquals, v.IDs()) } } // save a key and check it gets encrypted - key, err := sign.GenerateEd25519Key() + key, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - c.Assert(store.SavePrivateKey("root", key), IsNil) - assertKeys("root", true, []*sign.PrivateKey{key}) + privateKey, err := key.MarshalPrivate() + c.Assert(err, IsNil) + c.Assert(store.SavePrivateKey("root", privateKey), IsNil) + assertKeys("root", true, []*data.PrivateKey{privateKey}) // save another key and check it gets added to the existing keys - newKey, err := sign.GenerateEd25519Key() + newKey, err := keys.GenerateEd25519Key() + c.Assert(err, IsNil) + newPrivateKey, err := newKey.MarshalPrivate() c.Assert(err, IsNil) - c.Assert(store.SavePrivateKey("root", newKey), IsNil) - assertKeys("root", true, []*sign.PrivateKey{key, newKey}) + c.Assert(store.SavePrivateKey("root", newPrivateKey), IsNil) + assertKeys("root", true, []*data.PrivateKey{privateKey, newPrivateKey}) // check saving a key to an encrypted file without a passphrase fails insecureStore := FileSystemStore(tmp.path, nil) - key, err = sign.GenerateEd25519Key() + key, err = keys.GenerateEd25519Key() c.Assert(err, IsNil) - c.Assert(insecureStore.SavePrivateKey("root", key), Equals, ErrPassphraseRequired{"root"}) + privateKey, err = key.MarshalPrivate() + c.Assert(err, IsNil) + c.Assert(insecureStore.SavePrivateKey("root", privateKey), Equals, ErrPassphraseRequired{"root"}) // save a key to an insecure store and check it is not encrypted - key, err = sign.GenerateEd25519Key() + key, err = keys.GenerateEd25519Key() + c.Assert(err, IsNil) + privateKey, err = key.MarshalPrivate() c.Assert(err, IsNil) - c.Assert(insecureStore.SavePrivateKey("targets", key), IsNil) - assertKeys("targets", false, []*sign.PrivateKey{key}) + c.Assert(insecureStore.SavePrivateKey("targets", privateKey), IsNil) + assertKeys("targets", false, []*data.PrivateKey{privateKey}) } func (rs *RepoSuite) TestManageMultipleTargets(c *C) { @@ -1358,7 +1403,7 @@ func (rs *RepoSuite) TestUnknownKeyIDs(c *C) { genKey(c, r, "timestamp") // add a new key to the root metadata with an unknown key id. - key, err := sign.GenerateEd25519Key() + key, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) root, err := r.root() @@ -1477,25 +1522,25 @@ func (rs *RepoSuite) TestAddOrUpdateSignatures(c *C) { c.Assert(r.Init(false), IsNil) // generate root key offline and add as a verification key - rootKey, err := sign.GenerateEd25519Key() + rootKey, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) c.Assert(r.AddVerificationKey("root", rootKey.PublicData()), IsNil) - targetsKey, err := sign.GenerateEd25519Key() + targetsKey, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) c.Assert(r.AddVerificationKey("targets", targetsKey.PublicData()), IsNil) - snapshotKey, err := sign.GenerateEd25519Key() + snapshotKey, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) c.Assert(r.AddVerificationKey("snapshot", snapshotKey.PublicData()), IsNil) - timestampKey, err := sign.GenerateEd25519Key() + timestampKey, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) c.Assert(r.AddVerificationKey("timestamp", timestampKey.PublicData()), IsNil) // generate signatures externally and append rootMeta, err := r.SignedMeta("root.json") c.Assert(err, IsNil) - rootSig, err := rootKey.Signer().Sign(rand.Reader, rootMeta.Signed, crypto.Hash(0)) + rootSig, err := rootKey.Sign(rand.Reader, rootMeta.Signed, crypto.Hash(0)) c.Assert(err, IsNil) - for _, id := range rootKey.Signer().IDs() { + for _, id := range rootKey.IDs() { c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{ KeyID: id, Signature: rootSig}), IsNil) @@ -1505,9 +1550,9 @@ func (rs *RepoSuite) TestAddOrUpdateSignatures(c *C) { c.Assert(r.AddTarget("foo.txt", nil), IsNil) targetsMeta, err := r.SignedMeta("targets.json") c.Assert(err, IsNil) - targetsSig, err := targetsKey.Signer().Sign(rand.Reader, targetsMeta.Signed, crypto.Hash(0)) + targetsSig, err := targetsKey.Sign(rand.Reader, targetsMeta.Signed, crypto.Hash(0)) c.Assert(err, IsNil) - for _, id := range targetsKey.Signer().IDs() { + for _, id := range targetsKey.IDs() { r.AddOrUpdateSignature("targets.json", data.Signature{ KeyID: id, Signature: targetsSig}) @@ -1517,9 +1562,9 @@ func (rs *RepoSuite) TestAddOrUpdateSignatures(c *C) { c.Assert(r.Snapshot(CompressionTypeNone), IsNil) snapshotMeta, err := r.SignedMeta("snapshot.json") c.Assert(err, IsNil) - snapshotSig, err := snapshotKey.Signer().Sign(rand.Reader, snapshotMeta.Signed, crypto.Hash(0)) + snapshotSig, err := snapshotKey.Sign(rand.Reader, snapshotMeta.Signed, crypto.Hash(0)) c.Assert(err, IsNil) - for _, id := range snapshotKey.Signer().IDs() { + for _, id := range snapshotKey.IDs() { r.AddOrUpdateSignature("snapshot.json", data.Signature{ KeyID: id, Signature: snapshotSig}) @@ -1528,9 +1573,9 @@ func (rs *RepoSuite) TestAddOrUpdateSignatures(c *C) { c.Assert(r.Timestamp(), IsNil) timestampMeta, err := r.SignedMeta("timestamp.json") c.Assert(err, IsNil) - timestampSig, err := timestampKey.Signer().Sign(rand.Reader, timestampMeta.Signed, crypto.Hash(0)) + timestampSig, err := timestampKey.Sign(rand.Reader, timestampMeta.Signed, crypto.Hash(0)) c.Assert(err, IsNil) - for _, id := range timestampKey.Signer().IDs() { + for _, id := range timestampKey.IDs() { r.AddOrUpdateSignature("timestamp.json", data.Signature{ KeyID: id, Signature: timestampSig}) @@ -1550,48 +1595,48 @@ func (rs *RepoSuite) TestBadAddOrUpdateSignatures(c *C) { c.Assert(r.Init(false), IsNil) // generate root key offline and add as a verification key - rootKey, err := sign.GenerateEd25519Key() + rootKey, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) c.Assert(r.AddVerificationKey("root", rootKey.PublicData()), IsNil) - targetsKey, err := sign.GenerateEd25519Key() + targetsKey, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) c.Assert(r.AddVerificationKey("targets", targetsKey.PublicData()), IsNil) - snapshotKey, err := sign.GenerateEd25519Key() + snapshotKey, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) c.Assert(r.AddVerificationKey("snapshot", snapshotKey.PublicData()), IsNil) - timestampKey, err := sign.GenerateEd25519Key() + timestampKey, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) c.Assert(r.AddVerificationKey("timestamp", timestampKey.PublicData()), IsNil) // add a signature with a bad role rootMeta, err := r.SignedMeta("root.json") c.Assert(err, IsNil) - rootSig, err := rootKey.Signer().Sign(rand.Reader, rootMeta.Signed, crypto.Hash(0)) + rootSig, err := rootKey.Sign(rand.Reader, rootMeta.Signed, crypto.Hash(0)) c.Assert(err, IsNil) - for _, id := range rootKey.Signer().IDs() { + for _, id := range rootKey.IDs() { c.Assert(r.AddOrUpdateSignature("invalid_root.json", data.Signature{ KeyID: id, Signature: rootSig}), Equals, ErrInvalidRole{"invalid_root"}) } // add a root signature with an key ID that is for the targets role - for _, id := range targetsKey.Signer().IDs() { + for _, id := range targetsKey.IDs() { c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{ KeyID: id, Signature: rootSig}), Equals, verify.ErrInvalidKey) } // attempt to add a bad signature to root - badSig, err := rootKey.Signer().Sign(rand.Reader, []byte(""), crypto.Hash(0)) + badSig, err := rootKey.Sign(rand.Reader, []byte(""), crypto.Hash(0)) c.Assert(err, IsNil) - for _, id := range rootKey.Signer().IDs() { + for _, id := range rootKey.IDs() { c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{ KeyID: id, Signature: badSig}), Equals, verify.ErrInvalid) } // add the correct root signature - for _, id := range rootKey.Signer().IDs() { + for _, id := range rootKey.IDs() { c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{ KeyID: id, Signature: rootSig}), IsNil) @@ -1616,7 +1661,7 @@ func (rs *RepoSuite) TestBadAddOrUpdateSignatures(c *C) { // re-adding should not duplicate. this is checked by verifying // signature key IDs match with the map of role key IDs. - for _, id := range rootKey.Signer().IDs() { + for _, id := range rootKey.IDs() { c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{ KeyID: id, Signature: rootSig}), IsNil) diff --git a/verify/db.go b/verify/db.go index 8aa34a81..0cfe594e 100644 --- a/verify/db.go +++ b/verify/db.go @@ -69,13 +69,12 @@ func (db *DB) AddKey(id string, k *data.Key) error { return ErrWrongID{} } v := vt.(func() keys.SignerVerifier)() - if v.Verifier != nil && !v.Verifier.ValidKey(k.Value) { + if v.Verifier == nil || !v.Verifier.ValidKey(k.Value) { return ErrInvalidKey } if err := v.Verifier.UnmarshalKey(k); err != nil { return ErrInvalidKey } - db.keys[id] = &v.Verifier return nil @@ -125,8 +124,8 @@ func (db *DB) addRole(name string, r *data.Role) error { return nil } -func (db *DB) GetKey(id string) keys.Verifier { - return *db.keys[id] +func (db *DB) GetKey(id string) *keys.Verifier { + return db.keys[id] } func (db *DB) GetRole(name string) *Role { diff --git a/verify/verify.go b/verify/verify.go index 98a6c158..f8490daf 100644 --- a/verify/verify.go +++ b/verify/verify.go @@ -86,14 +86,14 @@ func (db *DB) VerifySignatures(s *data.Signed, role string) error { continue } - if err := key.Verify(msg, sig.Signature); err != nil { + if err := (*key).Verify(msg, sig.Signature); err != nil { return ErrInvalid } // Only consider this key valid if we haven't seen any of it's // key ids before. if _, ok := seen[sig.KeyID]; !ok { - for _, id := range key.IDs() { + for _, id := range (*key).IDs() { seen[id] = struct{}{} } diff --git a/verify/verify_test.go b/verify/verify_test.go index 50776e8d..440e2afa 100644 --- a/verify/verify_test.go +++ b/verify/verify_test.go @@ -6,11 +6,14 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/sha256" + "encoding/json" + "errors" "io" "testing" "time" "github.com/theupdateframework/go-tuf/data" + "github.com/theupdateframework/go-tuf/keys" "github.com/theupdateframework/go-tuf/sign" "golang.org/x/crypto/ed25519" @@ -28,13 +31,18 @@ type ecdsaSigner struct { *ecdsa.PrivateKey } +type ecdsaPublic struct { + PublicKey data.HexBytes `json:"public"` +} + func (s ecdsaSigner) PublicData() *data.Key { pub := s.Public().(*ecdsa.PublicKey) + keyValBytes, _ := json.Marshal(ecdsaPublic{PublicKey: elliptic.Marshal(pub.Curve, pub.X, pub.Y)}) return &data.Key{ Type: data.KeyTypeECDSA_SHA2_P256, Scheme: data.KeySchemeECDSA_SHA2_P256, Algorithms: data.KeyAlgorithms, - Value: data.KeyValue{Public: elliptic.Marshal(pub.Curve, pub.X, pub.Y)}, + Value: keyValBytes, } } @@ -59,6 +67,14 @@ func (ecdsaSigner) Scheme() string { return data.KeySchemeECDSA_SHA2_P256 } +func (ecdsaSigner) MarshalPrivate() (*data.PrivateKey, error) { + return nil, errors.New("not implemented") +} + +func (ecdsaSigner) UnmarshalSigner(key *data.PrivateKey) error { + return errors.New("not implemented") +} + func (VerifySuite) Test(c *C) { type test struct { name string @@ -112,8 +128,8 @@ func (VerifySuite) Test(c *C) { { name: "more than enough signatures", mut: func(t *test) { - k, _ := sign.GenerateEd25519Key() - sign.Sign(t.s, k.Signer()) + k, _ := keys.GenerateEd25519Key() + sign.Sign(t.s, k) t.keys = append(t.keys, k.PublicData()) t.roles["root"].KeyIDs = append(t.roles["root"].KeyIDs, k.PublicData().IDs()...) }, @@ -129,15 +145,15 @@ func (VerifySuite) Test(c *C) { { name: "unknown key", mut: func(t *test) { - k, _ := sign.GenerateEd25519Key() - sign.Sign(t.s, k.Signer()) + k, _ := keys.GenerateEd25519Key() + sign.Sign(t.s, k) }, }, { name: "unknown key below threshold", mut: func(t *test) { - k, _ := sign.GenerateEd25519Key() - sign.Sign(t.s, k.Signer()) + k, _ := keys.GenerateEd25519Key() + sign.Sign(t.s, k) t.roles["root"].Threshold = 2 }, err: ErrRoleThreshold{2, 1}, @@ -145,16 +161,16 @@ func (VerifySuite) Test(c *C) { { name: "unknown keys in db", mut: func(t *test) { - k, _ := sign.GenerateEd25519Key() - sign.Sign(t.s, k.Signer()) + k, _ := keys.GenerateEd25519Key() + sign.Sign(t.s, k) t.keys = append(t.keys, k.PublicData()) }, }, { name: "unknown keys in db below threshold", mut: func(t *test) { - k, _ := sign.GenerateEd25519Key() - sign.Sign(t.s, k.Signer()) + k, _ := keys.GenerateEd25519Key() + sign.Sign(t.s, k) t.keys = append(t.keys, k.PublicData()) t.roles["root"].Threshold = 2 }, @@ -214,8 +230,8 @@ func (VerifySuite) Test(c *C) { t.typ = t.role } if t.keys == nil && t.s == nil { - k, _ := sign.GenerateEd25519Key() - t.s, _ = sign.Marshal(&signedMeta{Type: t.typ, Version: t.ver, Expires: *t.exp}, k.Signer()) + k, _ := keys.GenerateEd25519Key() + t.s, _ = sign.Marshal(&signedMeta{Type: t.typ, Version: t.ver, Expires: *t.exp}, k) t.keys = []*data.Key{k.PublicData()} } if t.roles == nil { From 1aaa52abb6dfc369264dd333489cb31fda1a1267 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Thu, 2 Sep 2021 14:52:09 -0500 Subject: [PATCH 04/17] address comments Signed-off-by: Asra Ali --- client/client_test.go | 36 +++++++++++++++++++---------------- data/types_test.go | 2 +- keys/ecdsa.go | 6 +++--- keys/ed25519.go | 12 ++++++------ local_store.go | 9 +++++---- repo_test.go | 44 +++++++++++++++++++++---------------------- verify/db.go | 16 ++++++++++------ verify/verifiers.go | 1 - verify/verify.go | 8 ++++---- 9 files changed, 71 insertions(+), 63 deletions(-) delete mode 100644 verify/verifiers.go diff --git a/client/client_test.go b/client/client_test.go index 6c5bf068..9ce10f05 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -343,7 +343,8 @@ func (s *ClientSuite) TestNewRoot(c *C) { for _, ids := range s.keyIDs { c.Assert(len(ids) > 0, Equals, true) for _, id := range ids { - c.Assert(client.db.GetKey(id), IsNil) + _, err := client.db.GetKey(id) + c.Assert(err, NotNil) } } @@ -351,9 +352,9 @@ func (s *ClientSuite) TestNewRoot(c *C) { for name, ids := range newKeyIDs { c.Assert(len(ids) > 0, Equals, true) for _, id := range ids { - key := client.db.GetKey(id) - c.Assert(key, NotNil) - c.Assert((*key).IDs(), DeepEquals, ids) + key, err := client.db.GetKey(id) + c.Assert(err, IsNil) + c.Assert(key.IDs(), DeepEquals, ids) } role := client.db.GetRole(name) c.Assert(role, NotNil) @@ -406,12 +407,13 @@ func (s *ClientSuite) TestNewTimestampKey(c *C) { // check key has been replaced in db for _, oldID := range oldIDs { - c.Assert(client.db.GetKey(oldID), IsNil) + _, err := client.db.GetKey(oldID) + c.Assert(err, NotNil) } for _, newID := range newIDs { - key := client.db.GetKey(newID) - c.Assert(key, NotNil) - c.Assert((*key).IDs(), DeepEquals, newIDs) + key, err := client.db.GetKey(newID) + c.Assert(err, IsNil) + c.Assert(key.IDs(), DeepEquals, newIDs) } role := client.db.GetRole("timestamp") c.Assert(role, NotNil) @@ -445,12 +447,13 @@ func (s *ClientSuite) TestNewSnapshotKey(c *C) { // check key has been replaced in db for _, oldID := range oldIDs { - c.Assert(client.db.GetKey(oldID), IsNil) + _, err := client.db.GetKey(oldID) + c.Assert(err, NotNil) } for _, newID := range newIDs { - key := client.db.GetKey(newID) - c.Assert(key, NotNil) - c.Assert((*key).IDs(), DeepEquals, newIDs) + key, err := client.db.GetKey(newID) + c.Assert(err, IsNil) + c.Assert(key.IDs(), DeepEquals, newIDs) } role := client.db.GetRole("snapshot") c.Assert(role, NotNil) @@ -487,12 +490,13 @@ func (s *ClientSuite) TestNewTargetsKey(c *C) { // check key has been replaced in db for _, oldID := range oldIDs { - c.Assert(client.db.GetKey(oldID), IsNil) + _, err := client.db.GetKey(oldID) + c.Assert(err, NotNil) } for _, newID := range newIDs { - key := client.db.GetKey(newID) - c.Assert(key, NotNil) - c.Assert((*key).IDs(), DeepEquals, newIDs) + key, err := client.db.GetKey(newID) + c.Assert(err, IsNil) + c.Assert(key.IDs(), DeepEquals, newIDs) } role := client.db.GetRole("targets") c.Assert(role, NotNil) diff --git a/data/types_test.go b/data/types_test.go index 31a7856b..c3f305e0 100644 --- a/data/types_test.go +++ b/data/types_test.go @@ -54,7 +54,7 @@ func (TypesSuite) TestRootAddKey(c *C) { var hexbytes HexBytes err := json.Unmarshal([]byte(public), &hexbytes) c.Assert(err, IsNil) - keyValBytes, _ := json.Marshal(ed25519Public{PublicKey: hexbytes}) + keyValBytes, err := json.Marshal(ed25519Public{PublicKey: hexbytes}) c.Assert(err, IsNil) key := &Key{ diff --git a/keys/ecdsa.go b/keys/ecdsa.go index f5041ced..045b7a7a 100644 --- a/keys/ecdsa.go +++ b/keys/ecdsa.go @@ -33,11 +33,11 @@ type p256Verifier struct { key *data.Key } -func (p p256Verifier) Public() string { +func (p *p256Verifier) Public() string { return p.PublicKey.String() } -func (p p256Verifier) Verify(msg, sigBytes []byte) error { +func (p *p256Verifier) Verify(msg, sigBytes []byte) error { x, y := elliptic.Unmarshal(elliptic.P256(), p.PublicKey) k := &ecdsa.PublicKey{ Curve: elliptic.P256(), @@ -66,7 +66,7 @@ func (p *p256Verifier) ValidKey(v json.RawMessage) bool { return x != nil } -func (p p256Verifier) Key() *data.Key { +func (p *p256Verifier) Key() *data.Key { return p.key } diff --git a/keys/ed25519.go b/keys/ed25519.go index e8069db7..8570078a 100644 --- a/keys/ed25519.go +++ b/keys/ed25519.go @@ -26,11 +26,11 @@ type ed25519Verifier struct { key *data.Key } -func (e ed25519Verifier) Public() string { +func (e *ed25519Verifier) Public() string { return string(e.PublicKey) } -func (e ed25519Verifier) Verify(msg, sig []byte) error { +func (e *ed25519Verifier) Verify(msg, sig []byte) error { if !ed25519.Verify([]byte(e.PublicKey), msg, sig) { return ErrInvalid } @@ -44,7 +44,7 @@ func (e *ed25519Verifier) ValidKey(v json.RawMessage) bool { return len(e.PublicKey) == ed25519.PublicKeySize } -func (e ed25519Verifier) Key() *data.Key { +func (e *ed25519Verifier) Key() *data.Key { return e.key } @@ -53,7 +53,7 @@ func (e *ed25519Verifier) UnmarshalKey(key *data.Key) error { return json.Unmarshal(key.Value, e) } -func (e ed25519Verifier) IDs() []string { +func (e *ed25519Verifier) IDs() []string { return e.key.IDs() } @@ -78,7 +78,7 @@ func GenerateEd25519Key() (*ed25519Signer, error) { }, nil } -func (e ed25519Signer) MarshalPrivate() (*data.PrivateKey, error) { +func (e *ed25519Signer) MarshalPrivate() (*data.PrivateKey, error) { valueBytes, err := json.Marshal(ed25519PrivateKeyValue{ Public: data.HexBytes([]byte(e.PrivateKey.Public().(ed25519.PublicKey))), Private: data.HexBytes(e.PrivateKey), @@ -108,7 +108,7 @@ func (e *ed25519Signer) UnmarshalSigner(key *data.PrivateKey) error { return nil } -func (e ed25519Signer) PublicData() *data.Key { +func (e *ed25519Signer) PublicData() *data.Key { keyValBytes, _ := json.Marshal(ed25519Verifier{PublicKey: []byte(e.PrivateKey.Public().(ed25519.PublicKey))}) return &data.Key{ Type: e.keyType, diff --git a/local_store.go b/local_store.go index 43b7e361..df3246ab 100644 --- a/local_store.go +++ b/local_store.go @@ -43,7 +43,7 @@ func MemoryStore(meta map[string]json.RawMessage, files map[string][]byte) Local meta: meta, stagedMeta: make(map[string]json.RawMessage), files: files, - signers: make(map[string][]*data.PrivateKey), + signers: make(map[string][]keys.Signer), } } @@ -51,7 +51,7 @@ type memoryStore struct { meta map[string]json.RawMessage stagedMeta map[string]json.RawMessage files map[string][]byte - signers map[string][]*data.PrivateKey + signers map[string][]keys.Signer } func (m *memoryStore) GetMeta() (map[string]json.RawMessage, error) { @@ -103,11 +103,12 @@ func (m *memoryStore) Commit(consistentSnapshot bool, versions map[string]int, h } func (m *memoryStore) GetSigningKeys(role string) ([]keys.Signer, error) { - return privateKeySigners(m.signers[role]), nil + return m.signers[role], nil } func (m *memoryStore) SavePrivateKey(role string, key *data.PrivateKey) error { - m.signers[role] = append(m.signers[role], key) + signers := privateKeySigners([]*data.PrivateKey{key}) + m.signers[role] = append(m.signers[role], signers...) return nil } diff --git a/repo_test.go b/repo_test.go index 94dd5bcb..04ef15b7 100644 --- a/repo_test.go +++ b/repo_test.go @@ -244,9 +244,9 @@ func (rs *RepoSuite) TestGenKey(c *C) { db, err := r.db() c.Assert(err, IsNil) for _, keyID := range ids { - rootKey := db.GetKey(keyID) - c.Assert(rootKey, NotNil) - c.Assert((*rootKey).IDs(), DeepEquals, ids) + rootKey, err := db.GetKey(keyID) + c.Assert(err, IsNil) + c.Assert(rootKey.IDs(), DeepEquals, ids) role := db.GetRole("root") c.Assert(role.KeyIDs, DeepEquals, util.StringSliceToSet(ids)) @@ -260,13 +260,13 @@ func (rs *RepoSuite) TestGenKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, (*rootKey).IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) pk := rs.getVerifier(c, rootKeys[0]) - c.Assert(pk.Public(), DeepEquals, (*rootKey).Public()) + c.Assert(pk.Public(), DeepEquals, rootKey.Public()) } - rootKey := db.GetKey(ids[0]) - c.Assert(rootKey, NotNil) + rootKey, err := db.GetKey(ids[0]) + c.Assert(err, IsNil) // generate two targets keys genKey(c, r, "targets") @@ -292,9 +292,9 @@ func (rs *RepoSuite) TestGenKey(c *C) { if !ok { c.Fatal("missing key") } - key := db.GetKey(id) - c.Assert(key, NotNil) - c.Assert((*key).Key().ContainsID(id), Equals, true) + key, err := db.GetKey(id) + c.Assert(err, IsNil) + c.Assert(key.Key().ContainsID(id), Equals, true) } role := db.GetRole("targets") c.Assert(role.KeyIDs, DeepEquals, targetKeyIDs) @@ -303,7 +303,7 @@ func (rs *RepoSuite) TestGenKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, (*rootKey).IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) // check the keys were saved correctly localKeys, err := local.GetSigningKeys("targets") @@ -405,9 +405,9 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { db, err := r.db() c.Assert(err, IsNil) for _, keyID := range ids { - rootKey := db.GetKey(keyID) - c.Assert(rootKey, NotNil) - c.Assert((*rootKey).IDs(), DeepEquals, ids) + rootKey, err := db.GetKey(keyID) + c.Assert(err, IsNil) + c.Assert(rootKey.IDs(), DeepEquals, ids) role := db.GetRole("root") c.Assert(role.KeyIDs, DeepEquals, util.StringSliceToSet(ids)) @@ -421,13 +421,13 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, (*rootKey).IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) pk := rs.getVerifier(c, rootKeys[0]) - c.Assert(pk.Public(), DeepEquals, (*rootKey).Public()) + c.Assert(pk.Public(), DeepEquals, rootKey.Public()) } - rootKey := db.GetKey(ids[0]) - c.Assert(rootKey, NotNil) + rootKey, err := db.GetKey(ids[0]) + c.Assert(err, IsNil) // generate two targets keys addGeneratedPrivateKey(c, r, "targets") @@ -453,9 +453,9 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { if !ok { c.Fatal("missing key") } - key := db.GetKey(id) - c.Assert(key, NotNil) - c.Assert((*key).Key().ContainsID(id), Equals, true) + key, err := db.GetKey(id) + c.Assert(err, IsNil) + c.Assert(key.Key().ContainsID(id), Equals, true) } role := db.GetRole("targets") c.Assert(role.KeyIDs, DeepEquals, targetKeyIDs) @@ -464,7 +464,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, (*rootKey).IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) // check the keys were saved correctly localKeys, err := local.GetSigningKeys("targets") diff --git a/verify/db.go b/verify/db.go index 0cfe594e..8311b456 100644 --- a/verify/db.go +++ b/verify/db.go @@ -17,13 +17,13 @@ func (r *Role) ValidKey(id string) bool { type DB struct { roles map[string]*Role - keys map[string]*keys.Verifier + keys map[string]keys.Verifier } func NewDB() *DB { return &DB{ roles: make(map[string]*Role), - keys: make(map[string]*keys.Verifier), + keys: make(map[string]keys.Verifier), } } @@ -41,7 +41,7 @@ func (d *DelegationsVerifier) Unmarshal(b []byte, v interface{}, role string, mi func NewDelegationsVerifier(d *data.Delegations) (DelegationsVerifier, error) { db := &DB{ roles: make(map[string]*Role, len(d.Roles)), - keys: make(map[string]*keys.Verifier, len(d.Keys)), + keys: make(map[string]keys.Verifier, len(d.Keys)), } for _, r := range d.Roles { if _, ok := topLevelRoles[r.Name]; ok { @@ -75,7 +75,7 @@ func (db *DB) AddKey(id string, k *data.Key) error { if err := v.Verifier.UnmarshalKey(k); err != nil { return ErrInvalidKey } - db.keys[id] = &v.Verifier + db.keys[id] = v.Verifier return nil } @@ -124,8 +124,12 @@ func (db *DB) addRole(name string, r *data.Role) error { return nil } -func (db *DB) GetKey(id string) *keys.Verifier { - return db.keys[id] +func (db *DB) GetKey(id string) (keys.Verifier, error) { + k, ok := db.keys[id] + if !ok { + return nil, ErrMissingKey + } + return k, nil } func (db *DB) GetRole(name string) *Role { diff --git a/verify/verifiers.go b/verify/verifiers.go deleted file mode 100644 index efc7e18c..00000000 --- a/verify/verifiers.go +++ /dev/null @@ -1 +0,0 @@ -package verify diff --git a/verify/verify.go b/verify/verify.go index f8490daf..3bcb4108 100644 --- a/verify/verify.go +++ b/verify/verify.go @@ -81,19 +81,19 @@ func (db *DB) VerifySignatures(s *data.Signed, role string) error { if !roleData.ValidKey(sig.KeyID) { continue } - key := db.GetKey(sig.KeyID) - if key == nil { + key, err := db.GetKey(sig.KeyID) + if err != nil { continue } - if err := (*key).Verify(msg, sig.Signature); err != nil { + if err := key.Verify(msg, sig.Signature); err != nil { return ErrInvalid } // Only consider this key valid if we haven't seen any of it's // key ids before. if _, ok := seen[sig.KeyID]; !ok { - for _, id := range (*key).IDs() { + for _, id := range key.IDs() { seen[id] = struct{}{} } From d5bb678e001de18be088dc75f73beaac54fc00da Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Thu, 2 Sep 2021 15:32:42 -0500 Subject: [PATCH 05/17] factor to helper Signed-off-by: Asra Ali --- client/python_interop/python_interop_test.go | 18 +---- .../testdata/go-tuf-transition-M3/generate.go | 26 ++----- .../testdata/go-tuf-transition-M4/generate.go | 13 +--- client/testdata/go-tuf/generator/generator.go | 26 ++----- keys/ecdsa.go | 19 +++--- keys/ed25519.go | 16 ++--- keys/keys.go | 40 +++++++++-- local_store.go | 14 +--- repo_test.go | 67 ++++++------------- verify/db.go | 14 +--- 10 files changed, 93 insertions(+), 160 deletions(-) diff --git a/client/python_interop/python_interop_test.go b/client/python_interop/python_interop_test.go index 95813653..b047e959 100644 --- a/client/python_interop/python_interop_test.go +++ b/client/python_interop/python_interop_test.go @@ -43,21 +43,6 @@ func (t *testDestination) Delete() error { return nil } -func getVerifier(c *C, key *data.Key) keys.Verifier { - vt, ok := keys.KeyMap.Load(key.Type) - if !ok { - c.Errorf("error loading key implementation") - } - v := vt.(func() keys.SignerVerifier)() - if v.Verifier == nil { - c.Errorf("error loading verifier implementation") - } - if err := v.Verifier.UnmarshalKey(key); err != nil { - c.Errorf("error unmarshalling key") - } - return v.Verifier -} - func (InteropSuite) TestGoClientPythonGenerated(c *C) { // start file server cwd, err := os.Getwd() @@ -80,7 +65,8 @@ func (InteropSuite) TestGoClientPythonGenerated(c *C) { key := &data.Key{} c.Assert(json.NewDecoder(f).Decode(key), IsNil) c.Assert(key.Type, Equals, "ed25519") - pk := getVerifier(c, key) + pk, err := keys.GetVerifier(key) + c.Assert(err, IsNil) c.Assert(pk.Public(), HasLen, ed25519.PublicKeySize) client := client.NewClient(client.MemoryLocalStore(), remote) c.Assert(client.Init([]*data.Key{key}, 1), IsNil) diff --git a/client/testdata/go-tuf-transition-M3/generate.go b/client/testdata/go-tuf-transition-M3/generate.go index fbbbb3db..116adf6e 100644 --- a/client/testdata/go-tuf-transition-M3/generate.go +++ b/client/testdata/go-tuf-transition-M3/generate.go @@ -52,16 +52,9 @@ func commit(dir string, repo *tuf.Repo) { func addKeys(repo *tuf.Repo, roleKeys map[string][]*data.PrivateKey) { for role, keyList := range roleKeys { for _, key := range keyList { - st, ok := keys.KeyMap.Load(key.Type) - if !ok { - panic(fmt.Printf("error loading key implementation")) - } - s := st.(func() keys.SignerVerifier)() - if s.Signer == nil { - panic(fmt.Printf("error loading signer implementation")) - } - assertNotNil(s.Signer.UnmarshalSigner(key)) - assertNotNil(repo.AddPrivateKeyWithExpires(role, s.Signer, expirationDate)) + signer, err := keys.GetSigner(key) + assertNotNil(err) + assertNotNil(repo.AddPrivateKeyWithExpires(role, signer, expirationDate)) } } } @@ -79,16 +72,9 @@ func addTargets(repo *tuf.Repo, dir string, files map[string][]byte) { func revokeKeys(repo *tuf.Repo, role string, keyList []*data.PrivateKey) { for _, key := range keyList { - st, ok := keys.KeyMap.Load(key.Type) - if !ok { - panic("error loading key implementation") - } - s := st.(func() keys.SignerVerifier)() - if s.Signer == nil { - panic("error loading signer implementation") - } - assertNotNil(s.Signer.UnmarshalSigner(key)) - assertNotNil(repo.RevokeKeyWithExpires(role, s.Signer.IDs()[0], expirationDate)) + signer, err := keys.GetSigner(key) + assertNotNil(err) + assertNotNil(repo.RevokeKeyWithExpires(role, signer.IDs()[0], expirationDate)) } } diff --git a/client/testdata/go-tuf-transition-M4/generate.go b/client/testdata/go-tuf-transition-M4/generate.go index 0e71ab55..9206a03a 100644 --- a/client/testdata/go-tuf-transition-M4/generate.go +++ b/client/testdata/go-tuf-transition-M4/generate.go @@ -70,16 +70,9 @@ func addTargets(repo *tuf.Repo, dir string, files map[string][]byte) { func revokeKeys(repo *tuf.Repo, role string, keyList []*data.PrivateKey) { for _, key := range keyList { - st, ok := keys.KeyMap.Load(key.Type) - if !ok { - panic("error loading key implementation") - } - s := st.(func() keys.SignerVerifier)() - if s.Signer == nil { - panic("error loading signer implementation") - } - assertNotNil(s.Signer.UnmarshalSigner(key)) - assertNotNil(repo.RevokeKeyWithExpires(role, s.Signer.PublicData().IDs()[0], expirationDate)) + signer, err := keys.GetSigner(key) + assertNotNil(err) + assertNotNil(repo.RevokeKeyWithExpires(role, signer.PublicData().IDs()[0], expirationDate)) } } diff --git a/client/testdata/go-tuf/generator/generator.go b/client/testdata/go-tuf/generator/generator.go index 9b27c80e..b71b7445 100644 --- a/client/testdata/go-tuf/generator/generator.go +++ b/client/testdata/go-tuf/generator/generator.go @@ -52,16 +52,9 @@ func commit(dir string, repo *tuf.Repo) { func addKeys(repo *tuf.Repo, roleKeys map[string][]*data.PrivateKey) { for role, keyList := range roleKeys { for _, key := range keyList { - st, ok := keys.KeyMap.Load(key.Type) - if !ok { - panic("error loading key implementation") - } - s := st.(func() keys.SignerVerifier)() - if s.Signer == nil { - panic("error loading signer implementation") - } - assertNotNil(s.Signer.UnmarshalSigner(key)) - assertNotNil(repo.AddPrivateKeyWithExpires(role, s.Signer, expirationDate)) + signer, err := keys.GetSigner(key) + assertNotNil(err) + assertNotNil(repo.AddPrivateKeyWithExpires(role, signer, expirationDate)) } } } @@ -79,16 +72,9 @@ func addTargets(repo *tuf.Repo, dir string, files map[string][]byte) { func revokeKeys(repo *tuf.Repo, role string, keyList []*data.PrivateKey) { for _, key := range keyList { - st, ok := keys.KeyMap.Load(key.Type) - if !ok { - panic("error loading key implementation") - } - s := st.(func() keys.SignerVerifier)() - if s.Signer == nil { - panic("error loading signer implementation") - } - assertNotNil(s.Signer.UnmarshalSigner(key)) - assertNotNil(repo.RevokeKeyWithExpires(role, s.Signer.IDs()[0], expirationDate)) + signer, err := keys.GetSigner(key) + assertNotNil(err) + assertNotNil(repo.RevokeKeyWithExpires(role, signer.IDs()[0], expirationDate)) } } diff --git a/keys/ecdsa.go b/keys/ecdsa.go index 045b7a7a..de78c2d6 100644 --- a/keys/ecdsa.go +++ b/keys/ecdsa.go @@ -53,26 +53,25 @@ func (p *p256Verifier) Verify(msg, sigBytes []byte) error { hash := sha256.Sum256(msg) if !ecdsa.Verify(k, hash[:], sig.R, sig.S) { - return errors.New("verifyig ecdsa signature") + return errors.New("verifying ecdsa signature") } return nil } -func (p *p256Verifier) ValidKey(v json.RawMessage) bool { - if err := json.Unmarshal(v, p); err != nil { - return false - } - x, _ := elliptic.Unmarshal(elliptic.P256(), p.PublicKey) - return x != nil -} - func (p *p256Verifier) Key() *data.Key { return p.key } func (p *p256Verifier) UnmarshalKey(key *data.Key) error { + if err := json.Unmarshal(key.Value, p); err != nil { + return errors.New("unmarshalling key") + } + x, _ := elliptic.Unmarshal(elliptic.P256(), p.PublicKey) + if x == nil { + return errors.New("unmarshalling key") + } p.key = key - return json.Unmarshal(key.Value, p) + return nil } func (p *p256Verifier) IDs() []string { diff --git a/keys/ed25519.go b/keys/ed25519.go index 8570078a..110bfa2b 100644 --- a/keys/ed25519.go +++ b/keys/ed25519.go @@ -4,6 +4,7 @@ import ( "crypto/ed25519" "crypto/rand" "encoding/json" + "errors" "sync" "github.com/theupdateframework/go-tuf/data" @@ -37,20 +38,19 @@ func (e *ed25519Verifier) Verify(msg, sig []byte) error { return nil } -func (e *ed25519Verifier) ValidKey(v json.RawMessage) bool { - if err := json.Unmarshal(v, e); err != nil { - return false - } - return len(e.PublicKey) == ed25519.PublicKeySize -} - func (e *ed25519Verifier) Key() *data.Key { return e.key } func (e *ed25519Verifier) UnmarshalKey(key *data.Key) error { e.key = key - return json.Unmarshal(key.Value, e) + if err := json.Unmarshal(key.Value, e); err != nil { + return errors.New("unmarshalling key") + } + if len(e.PublicKey) != ed25519.PublicKeySize { + return errors.New("unmarshalling key") + } + return nil } func (e *ed25519Verifier) IDs() []string { diff --git a/keys/keys.go b/keys/keys.go index 8198cd9a..112c921c 100644 --- a/keys/keys.go +++ b/keys/keys.go @@ -2,7 +2,6 @@ package keys import ( "crypto" - "encoding/json" "errors" "sync" @@ -18,12 +17,15 @@ type SignerVerifier struct { } var ( - ErrInvalid = errors.New("tuf: signature verification failed") + ErrInvalid = errors.New("tuf: signature verification failed") + ErrInvalidKey = errors.New("invalid key") ) // A Verifier verifies public key signatures. type Verifier interface { // UnmarshalKey takes key data to a working verifier implementation for the key type. + // This performs any validation over the data.Key to ensure that the verifier is usable + // to verify signatures. UnmarshalKey(key *data.Key) error // This is the public string used as a unique identifier for the verifier instance. @@ -37,10 +39,6 @@ type Verifier interface { // key and message. Verify(msg, sig []byte) error - // ValidKey returns true if the provided public key is valid and usable to - // verify signatures with this verifier. - ValidKey(value json.RawMessage) bool - // Key returns the data.Key object associated with the verifier. Key() *data.Key } @@ -72,3 +70,33 @@ type Signer interface { // provided as the message to Sign with a zero opts.HashFunc(). crypto.Signer } + +func GetVerifier(key *data.Key) (Verifier, error) { + st, ok := KeyMap.Load(key.Type) + if !ok { + return nil, ErrInvalidKey + } + s := st.(func() SignerVerifier)() + if s.Verifier == nil { + return nil, ErrInvalidKey + } + if err := s.Verifier.UnmarshalKey(key); err != nil { + return nil, ErrInvalidKey + } + return s.Verifier, nil +} + +func GetSigner(key *data.PrivateKey) (Signer, error) { + st, ok := KeyMap.Load(key.Type) + if !ok { + return nil, ErrInvalidKey + } + s := st.(func() SignerVerifier)() + if s.Signer == nil { + return nil, ErrInvalidKey + } + if err := s.Signer.UnmarshalSigner(key); err != nil { + return nil, ErrInvalidKey + } + return s.Signer, nil +} diff --git a/local_store.go b/local_store.go index df3246ab..69faec70 100644 --- a/local_store.go +++ b/local_store.go @@ -18,19 +18,11 @@ import ( func privateKeySigners(privateKeys []*data.PrivateKey) []keys.Signer { res := make([]keys.Signer, len(privateKeys)) for i, k := range privateKeys { - svt, ok := keys.KeyMap.Load(k.Type) - if !ok { - continue - } - sv := svt.(func() keys.SignerVerifier)() - if sv.Signer == nil { - continue - } - if err := sv.Signer.UnmarshalSigner(k); err != nil { + signer, err := keys.GetSigner(k) + if err != nil { continue } - res[i] = sv.Signer - _ = sv.Signer.IDs() + res[i] = signer } return res } diff --git a/repo_test.go b/repo_test.go index 04ef15b7..ee97c792 100644 --- a/repo_test.go +++ b/repo_test.go @@ -49,20 +49,16 @@ func UniqueKeys(r *data.Root) map[string][]*data.Key { for _, id := range role.KeyIDs { // Double-check that there is actually a key with that ID. if key, ok := r.Keys[id]; ok { - if kt, found := keys.KeyMap.Load(key.Type); found { - k := kt.(func() keys.SignerVerifier)() - if k.Verifier != nil { - err := k.Verifier.UnmarshalKey(key) - if err == nil { - val := k.Verifier.Public() - if _, ok := seen[val]; ok { - continue - } - seen[val] = struct{}{} - roleKeys = append(roleKeys, key) - } - } + verifier, err := keys.GetVerifier(key) + if err != nil { + continue } + val := verifier.Public() + if _, ok := seen[val]; ok { + continue + } + seen[val] = struct{}{} + roleKeys = append(roleKeys, key) } } keysByRole[name] = roleKeys @@ -75,36 +71,6 @@ func (*RepoSuite) assertNumUniqueKeys(c *C, root *data.Root, role string, num in c.Assert(UniqueKeys(root)[role], HasLen, num) } -func (*RepoSuite) getVerifier(c *C, key *data.Key) keys.Verifier { - vt, ok := keys.KeyMap.Load(key.Type) - if !ok { - c.Errorf("error loading key implementation") - } - v := vt.(func() keys.SignerVerifier)() - if v.Verifier == nil { - c.Errorf("error loading verifier implementation") - } - if err := v.Verifier.UnmarshalKey(key); err != nil { - c.Errorf("error unmarshalling key") - } - return v.Verifier -} - -func getSigner(c *C, key *data.PrivateKey) keys.Signer { - vt, ok := keys.KeyMap.Load(key.Type) - if !ok { - c.Errorf("error loading key implementation") - } - v := vt.(func() keys.SignerVerifier)() - if v.Signer == nil { - c.Errorf("error loading signer implementation") - } - if err := v.Signer.UnmarshalSigner(key); err != nil { - c.Errorf("error unmarshalling key") - } - return v.Signer -} - func testNewRepo(c *C, newRepo func(local LocalStore, hashAlgorithms ...string) (*Repo, error)) { meta := map[string]json.RawMessage{ "root.json": []byte(`{ @@ -236,7 +202,8 @@ func (rs *RepoSuite) TestGenKey(c *C) { c.Fatal("missing key") } c.Assert(k.IDs(), DeepEquals, ids) - pk := rs.getVerifier(c, k) + pk, err := keys.GetVerifier(k) + c.Assert(err, IsNil) c.Assert(pk.Public(), HasLen, ed25519.PublicKeySize) } @@ -261,7 +228,8 @@ func (rs *RepoSuite) TestGenKey(c *C) { c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) - pk := rs.getVerifier(c, rootKeys[0]) + pk, err := keys.GetVerifier(rootKeys[0]) + c.Assert(err, IsNil) c.Assert(pk.Public(), DeepEquals, rootKey.Public()) } @@ -397,7 +365,8 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { c.Fatalf("missing key %s", keyID) } c.Assert(k.IDs(), DeepEquals, ids) - pk := rs.getVerifier(c, k) + pk, err := keys.GetVerifier(k) + c.Assert(err, IsNil) c.Assert(pk.Public(), HasLen, ed25519.PublicKeySize) } @@ -422,7 +391,8 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) - pk := rs.getVerifier(c, rootKeys[0]) + pk, err := keys.GetVerifier(rootKeys[0]) + c.Assert(err, IsNil) c.Assert(pk.Public(), DeepEquals, rootKey.Public()) } @@ -1252,7 +1222,8 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) { c.Assert(err, IsNil) c.Assert(signers, HasLen, len(expected)) for i, s := range signers { - v := getSigner(c, expected[i]) + v, err := keys.GetSigner(expected[i]) + c.Assert(err, IsNil) c.Assert(s.IDs(), DeepEquals, v.IDs()) } } diff --git a/verify/db.go b/verify/db.go index 8311b456..ff726587 100644 --- a/verify/db.go +++ b/verify/db.go @@ -61,22 +61,14 @@ func NewDelegationsVerifier(d *data.Delegations) (DelegationsVerifier, error) { } func (db *DB) AddKey(id string, k *data.Key) error { - vt, ok := keys.KeyMap.Load(k.Type) - if !ok { - return nil - } if !k.ContainsID(id) { return ErrWrongID{} } - v := vt.(func() keys.SignerVerifier)() - if v.Verifier == nil || !v.Verifier.ValidKey(k.Value) { + verifier, err := keys.GetVerifier(k) + if err != nil { return ErrInvalidKey } - if err := v.Verifier.UnmarshalKey(k); err != nil { - return ErrInvalidKey - } - db.keys[id] = v.Verifier - + db.keys[id] = verifier return nil } From 632394817d83c7e94def55562ff59c88d61dc127 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Tue, 7 Sep 2021 10:50:41 -0500 Subject: [PATCH 06/17] simplify key interface Signed-off-by: Asra Ali --- client/client_test.go | 8 +-- .../testdata/go-tuf-transition-M3/generate.go | 2 +- client/testdata/go-tuf/generator/generator.go | 2 +- keys/ecdsa.go | 12 ++-- keys/ed25519.go | 63 ++++++------------- keys/ed25519_test.go | 24 +++++++ keys/keys.go | 55 +++++----------- keys/keys_test.go | 7 +-- repo.go | 4 +- repo_test.go | 56 ++++++++--------- sign/sign.go | 2 +- verify/verify.go | 2 +- verify/verify_test.go | 10 +-- 13 files changed, 104 insertions(+), 143 deletions(-) create mode 100644 keys/ed25519_test.go diff --git a/client/client_test.go b/client/client_test.go index 9ce10f05..767c8855 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -354,7 +354,7 @@ func (s *ClientSuite) TestNewRoot(c *C) { for _, id := range ids { key, err := client.db.GetKey(id) c.Assert(err, IsNil) - c.Assert(key.IDs(), DeepEquals, ids) + c.Assert(key.MarshalKey().IDs(), DeepEquals, ids) } role := client.db.GetRole(name) c.Assert(role, NotNil) @@ -413,7 +413,7 @@ func (s *ClientSuite) TestNewTimestampKey(c *C) { for _, newID := range newIDs { key, err := client.db.GetKey(newID) c.Assert(err, IsNil) - c.Assert(key.IDs(), DeepEquals, newIDs) + c.Assert(key.MarshalKey().IDs(), DeepEquals, newIDs) } role := client.db.GetRole("timestamp") c.Assert(role, NotNil) @@ -453,7 +453,7 @@ func (s *ClientSuite) TestNewSnapshotKey(c *C) { for _, newID := range newIDs { key, err := client.db.GetKey(newID) c.Assert(err, IsNil) - c.Assert(key.IDs(), DeepEquals, newIDs) + c.Assert(key.MarshalKey().IDs(), DeepEquals, newIDs) } role := client.db.GetRole("snapshot") c.Assert(role, NotNil) @@ -496,7 +496,7 @@ func (s *ClientSuite) TestNewTargetsKey(c *C) { for _, newID := range newIDs { key, err := client.db.GetKey(newID) c.Assert(err, IsNil) - c.Assert(key.IDs(), DeepEquals, newIDs) + c.Assert(key.MarshalKey().IDs(), DeepEquals, newIDs) } role := client.db.GetRole("targets") c.Assert(role, NotNil) diff --git a/client/testdata/go-tuf-transition-M3/generate.go b/client/testdata/go-tuf-transition-M3/generate.go index 116adf6e..08417b5b 100644 --- a/client/testdata/go-tuf-transition-M3/generate.go +++ b/client/testdata/go-tuf-transition-M3/generate.go @@ -74,7 +74,7 @@ func revokeKeys(repo *tuf.Repo, role string, keyList []*data.PrivateKey) { for _, key := range keyList { signer, err := keys.GetSigner(key) assertNotNil(err) - assertNotNil(repo.RevokeKeyWithExpires(role, signer.IDs()[0], expirationDate)) + assertNotNil(repo.RevokeKeyWithExpires(role, signer.PublicData().IDs()[0], expirationDate)) } } diff --git a/client/testdata/go-tuf/generator/generator.go b/client/testdata/go-tuf/generator/generator.go index b71b7445..b1966543 100644 --- a/client/testdata/go-tuf/generator/generator.go +++ b/client/testdata/go-tuf/generator/generator.go @@ -74,7 +74,7 @@ func revokeKeys(repo *tuf.Repo, role string, keyList []*data.PrivateKey) { for _, key := range keyList { signer, err := keys.GetSigner(key) assertNotNil(err) - assertNotNil(repo.RevokeKeyWithExpires(role, signer.IDs()[0], expirationDate)) + assertNotNil(repo.RevokeKeyWithExpires(role, signer.PublicData().IDs()[0], expirationDate)) } } diff --git a/keys/ecdsa.go b/keys/ecdsa.go index de78c2d6..4489e1a0 100644 --- a/keys/ecdsa.go +++ b/keys/ecdsa.go @@ -13,15 +13,11 @@ import ( ) func init() { - KeyMap.Store(data.KeyTypeECDSA_SHA2_P256, NewEcdsa) + VerifierMap.Store(data.KeyTypeECDSA_SHA2_P256, NewEcdsaVerifier) } -func NewEcdsa() SignerVerifier { - sv := SignerVerifier{ - Signer: nil, - Verifier: &p256Verifier{}, - } - return sv +func NewEcdsaVerifier() Verifier { + return &p256Verifier{} } type ecdsaSignature struct { @@ -58,7 +54,7 @@ func (p *p256Verifier) Verify(msg, sigBytes []byte) error { return nil } -func (p *p256Verifier) Key() *data.Key { +func (p *p256Verifier) MarshalKey() *data.Key { return p.key } diff --git a/keys/ed25519.go b/keys/ed25519.go index 110bfa2b..fa7f9290 100644 --- a/keys/ed25519.go +++ b/keys/ed25519.go @@ -5,21 +5,22 @@ import ( "crypto/rand" "encoding/json" "errors" - "sync" "github.com/theupdateframework/go-tuf/data" ) func init() { - KeyMap.Store(data.KeySchemeEd25519, NewP256) + SignerMap.Store(data.KeySchemeEd25519, NewP256Signer) + VerifierMap.Store(data.KeySchemeEd25519, NewP256Verifier) + } -func NewP256() SignerVerifier { - sv := SignerVerifier{ - Signer: &ed25519Signer{}, - Verifier: &ed25519Verifier{}, - } - return sv +func NewP256Signer() Signer { + return &ed25519Signer{} +} + +func NewP256Verifier() Verifier { + return &ed25519Verifier{} } type ed25519Verifier struct { @@ -38,7 +39,7 @@ func (e *ed25519Verifier) Verify(msg, sig []byte) error { return nil } -func (e *ed25519Verifier) Key() *data.Key { +func (e *ed25519Verifier) MarshalKey() *data.Key { return e.key } @@ -62,6 +63,14 @@ type ed25519PrivateKeyValue struct { Private data.HexBytes `json:"private"` } +type ed25519Signer struct { + ed25519.PrivateKey + + keyType string + keyScheme string + keyAlgorithms []string +} + func GenerateEd25519Key() (*ed25519Signer, error) { _, private, err := ed25519.GenerateKey(rand.Reader) if err != nil { @@ -78,7 +87,7 @@ func GenerateEd25519Key() (*ed25519Signer, error) { }, nil } -func (e *ed25519Signer) MarshalPrivate() (*data.PrivateKey, error) { +func (e *ed25519Signer) MarshalSigner() (*data.PrivateKey, error) { valueBytes, err := json.Marshal(ed25519PrivateKeyValue{ Public: data.HexBytes([]byte(e.PrivateKey.Public().(ed25519.PublicKey))), Private: data.HexBytes(e.PrivateKey), @@ -117,37 +126,3 @@ func (e *ed25519Signer) PublicData() *data.Key { Value: keyValBytes, } } - -type ed25519Signer struct { - ed25519.PrivateKey - - keyType string - keyScheme string - keyAlgorithms []string - ids []string - idOnce sync.Once -} - -// var _ Signer = &ed25519Signer{} - -func (s *ed25519Signer) IDs() []string { - s.idOnce.Do(func() { s.ids = s.PublicData().IDs() }) - return s.ids -} - -func (s *ed25519Signer) ContainsID(id string) bool { - for _, keyid := range s.IDs() { - if id == keyid { - return true - } - } - return false -} - -func (s *ed25519Signer) Type() string { - return s.keyType -} - -func (s *ed25519Signer) Scheme() string { - return s.keyScheme -} diff --git a/keys/ed25519_test.go b/keys/ed25519_test.go new file mode 100644 index 00000000..4048bc3a --- /dev/null +++ b/keys/ed25519_test.go @@ -0,0 +1,24 @@ +package keys + +import ( + "crypto" + "crypto/rand" + + . "gopkg.in/check.v1" +) + +type Ed25519Suite struct{} + +var _ = Suite(&Ed25519Suite{}) + +func (Ed25519Suite) TestSignVerify(c *C) { + key, err := GenerateEd25519Key() + c.Assert(err, IsNil) + msg := []byte("foo") + sig, err := key.Sign(rand.Reader, msg, crypto.Hash(0)) + c.Assert(err, IsNil) + publicData := key.PublicData() + pubKey, err := GetVerifier(publicData) + c.Assert(err, IsNil) + c.Assert(pubKey.Verify(msg, sig), IsNil) +} diff --git a/keys/keys.go b/keys/keys.go index 112c921c..e2002cf2 100644 --- a/keys/keys.go +++ b/keys/keys.go @@ -8,13 +8,11 @@ import ( "github.com/theupdateframework/go-tuf/data" ) -// KeyMap stores mapping between key type strings and verifier constructors. -var KeyMap sync.Map +// SignerMap stores mapping between key type strings and signer constructors. +var SignerMap sync.Map -type SignerVerifier struct { - Signer Signer - Verifier Verifier -} +// Verifier stores mapping between key type strings and verifier constructors. +var VerifierMap sync.Map var ( ErrInvalid = errors.New("tuf: signature verification failed") @@ -28,24 +26,21 @@ type Verifier interface { // to verify signatures. UnmarshalKey(key *data.Key) error + // Key returns the data.Key object associated with the verifier. + MarshalKey() *data.Key + // This is the public string used as a unique identifier for the verifier instance. Public() string - // IDs returns the TUF key ids - IDs() []string - // Verify takes a message and signature, all as byte slices, // and determines whether the signature is valid for the given // key and message. Verify(msg, sig []byte) error - - // Key returns the data.Key object associated with the verifier. - Key() *data.Key } type Signer interface { // Marshal into a private key. - MarshalPrivate() (*data.PrivateKey, error) + MarshalSigner() (*data.PrivateKey, error) // UnmarshalKey takes private key data to a working Signer implementation for the key type. UnmarshalSigner(key *data.PrivateKey) error @@ -53,18 +48,6 @@ type Signer interface { // Returns the public data.Key from the private key PublicData() *data.Key - // IDs returns the TUF key ids - IDs() []string - - // ContainsID returns if the signer contains the key id - ContainsID(id string) bool - - // Type returns the TUF key type - Type() string - - // Scheme returns the TUF key scheme - Scheme() string - // Signer is used to sign messages and provides access to the public key. // The signer is expected to do its own hashing, so the full message will be // provided as the message to Sign with a zero opts.HashFunc(). @@ -72,31 +55,25 @@ type Signer interface { } func GetVerifier(key *data.Key) (Verifier, error) { - st, ok := KeyMap.Load(key.Type) + st, ok := VerifierMap.Load(key.Type) if !ok { return nil, ErrInvalidKey } - s := st.(func() SignerVerifier)() - if s.Verifier == nil { + s := st.(func() Verifier)() + if err := s.UnmarshalKey(key); err != nil { return nil, ErrInvalidKey } - if err := s.Verifier.UnmarshalKey(key); err != nil { - return nil, ErrInvalidKey - } - return s.Verifier, nil + return s, nil } func GetSigner(key *data.PrivateKey) (Signer, error) { - st, ok := KeyMap.Load(key.Type) + st, ok := SignerMap.Load(key.Type) if !ok { return nil, ErrInvalidKey } - s := st.(func() SignerVerifier)() - if s.Signer == nil { - return nil, ErrInvalidKey - } - if err := s.Signer.UnmarshalSigner(key); err != nil { + s := st.(func() Signer)() + if err := s.UnmarshalSigner(key); err != nil { return nil, ErrInvalidKey } - return s.Signer, nil + return s, nil } diff --git a/keys/keys_test.go b/keys/keys_test.go index 481fc107..93b1d3bc 100644 --- a/keys/keys_test.go +++ b/keys/keys_test.go @@ -16,26 +16,23 @@ var _ = Suite(&KeysSuite{}) func (KeysSuite) TestSignerKeyIDs(c *C) { key, err := GenerateEd25519Key() c.Assert(err, IsNil) - c.Assert(key.PublicData().IDs(), DeepEquals, key.IDs()) // If we have a TUF-0.9 key, we won't have a scheme. key, err = GenerateEd25519Key() c.Assert(err, IsNil) - privKey, err := key.MarshalPrivate() + privKey, err := key.MarshalSigner() c.Assert(err, IsNil) privKey.Scheme = "" err = key.UnmarshalSigner(privKey) c.Assert(err, IsNil) - c.Assert(key.PublicData().IDs(), DeepEquals, key.IDs()) // Make sure we preserve ids if we don't have any // keyid_hash_algorithms. key, err = GenerateEd25519Key() c.Assert(err, IsNil) - privKey, err = key.MarshalPrivate() + privKey, err = key.MarshalSigner() c.Assert(err, IsNil) privKey.Algorithms = []string{} err = key.UnmarshalSigner(privKey) c.Assert(err, IsNil) - c.Assert(key.PublicData().IDs(), DeepEquals, key.IDs()) } diff --git a/repo.go b/repo.go index fb76a3a8..5c46c6b8 100644 --- a/repo.go +++ b/repo.go @@ -344,7 +344,7 @@ func (r *Repo) AddPrivateKeyWithExpires(keyRole string, key keys.Signer, expires return ErrInvalidExpires{expires} } - privKey, err := key.MarshalPrivate() + privKey, err := key.MarshalSigner() if err != nil { return err } @@ -640,7 +640,7 @@ func (r *Repo) getSigningKeys(name string) ([]keys.Signer, error) { } keys := make([]keys.Signer, 0, len(role.KeyIDs)) for _, key := range signingKeys { - for _, id := range key.IDs() { + for _, id := range key.PublicData().IDs() { if _, ok := role.KeyIDs[id]; ok { keys = append(keys, key) } diff --git a/repo_test.go b/repo_test.go index ee97c792..f02d307c 100644 --- a/repo_test.go +++ b/repo_test.go @@ -213,7 +213,7 @@ func (rs *RepoSuite) TestGenKey(c *C) { for _, keyID := range ids { rootKey, err := db.GetKey(keyID) c.Assert(err, IsNil) - c.Assert(rootKey.IDs(), DeepEquals, ids) + c.Assert(rootKey.MarshalKey().IDs(), DeepEquals, ids) role := db.GetRole("root") c.Assert(role.KeyIDs, DeepEquals, util.StringSliceToSet(ids)) @@ -221,13 +221,13 @@ func (rs *RepoSuite) TestGenKey(c *C) { localKeys, err := local.GetSigningKeys("root") c.Assert(err, IsNil) c.Assert(localKeys, HasLen, 1) - c.Assert(localKeys[0].IDs(), DeepEquals, ids) + c.Assert(localKeys[0].PublicData().IDs(), DeepEquals, ids) // check RootKeys() is correct rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalKey().IDs()) pk, err := keys.GetVerifier(rootKeys[0]) c.Assert(err, IsNil) c.Assert(pk.Public(), DeepEquals, rootKey.Public()) @@ -262,7 +262,7 @@ func (rs *RepoSuite) TestGenKey(c *C) { } key, err := db.GetKey(id) c.Assert(err, IsNil) - c.Assert(key.Key().ContainsID(id), Equals, true) + c.Assert(key.MarshalKey().ContainsID(id), Equals, true) } role := db.GetRole("targets") c.Assert(role.KeyIDs, DeepEquals, targetKeyIDs) @@ -271,7 +271,7 @@ func (rs *RepoSuite) TestGenKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalKey().IDs()) // check the keys were saved correctly localKeys, err := local.GetSigningKeys("targets") @@ -280,7 +280,7 @@ func (rs *RepoSuite) TestGenKey(c *C) { for _, key := range localKeys { found := false for _, id := range targetsRole.KeyIDs { - if key.ContainsID(id) { + if key.PublicData().ContainsID(id) { found = true break } @@ -376,7 +376,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { for _, keyID := range ids { rootKey, err := db.GetKey(keyID) c.Assert(err, IsNil) - c.Assert(rootKey.IDs(), DeepEquals, ids) + c.Assert(rootKey.MarshalKey().IDs(), DeepEquals, ids) role := db.GetRole("root") c.Assert(role.KeyIDs, DeepEquals, util.StringSliceToSet(ids)) @@ -384,13 +384,13 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { localKeys, err := local.GetSigningKeys("root") c.Assert(err, IsNil) c.Assert(localKeys, HasLen, 1) - c.Assert(localKeys[0].IDs(), DeepEquals, ids) + c.Assert(localKeys[0].PublicData().IDs(), DeepEquals, ids) // check RootKeys() is correct rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalKey().IDs()) pk, err := keys.GetVerifier(rootKeys[0]) c.Assert(err, IsNil) c.Assert(pk.Public(), DeepEquals, rootKey.Public()) @@ -425,7 +425,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { } key, err := db.GetKey(id) c.Assert(err, IsNil) - c.Assert(key.Key().ContainsID(id), Equals, true) + c.Assert(key.MarshalKey().ContainsID(id), Equals, true) } role := db.GetRole("targets") c.Assert(role.KeyIDs, DeepEquals, targetKeyIDs) @@ -434,7 +434,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalKey().IDs()) // check the keys were saved correctly localKeys, err := local.GetSigningKeys("targets") @@ -443,7 +443,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { for _, key := range localKeys { found := false for _, id := range targetsRole.KeyIDs { - if key.ContainsID(id) { + if key.PublicData().ContainsID(id) { found = true break } @@ -586,7 +586,7 @@ func (rs *RepoSuite) TestSign(c *C) { // signing with an available key generates a signature key, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - privateKey, err := key.MarshalPrivate() + privateKey, err := key.MarshalSigner() c.Assert(err, IsNil) c.Assert(local.SavePrivateKey("root", privateKey), IsNil) c.Assert(r.Sign("root.json"), IsNil) @@ -599,7 +599,7 @@ func (rs *RepoSuite) TestSign(c *C) { // signing with a new available key generates another signature newKey, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - newPrivateKey, err := newKey.MarshalPrivate() + newPrivateKey, err := newKey.MarshalSigner() c.Assert(err, IsNil) c.Assert(local.SavePrivateKey("root", newPrivateKey), IsNil) c.Assert(r.Sign("root.json"), IsNil) @@ -1224,14 +1224,14 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) { for i, s := range signers { v, err := keys.GetSigner(expected[i]) c.Assert(err, IsNil) - c.Assert(s.IDs(), DeepEquals, v.IDs()) + c.Assert(s.PublicData().IDs(), DeepEquals, v.PublicData().IDs()) } } // save a key and check it gets encrypted key, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - privateKey, err := key.MarshalPrivate() + privateKey, err := key.MarshalSigner() c.Assert(err, IsNil) c.Assert(store.SavePrivateKey("root", privateKey), IsNil) assertKeys("root", true, []*data.PrivateKey{privateKey}) @@ -1239,7 +1239,7 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) { // save another key and check it gets added to the existing keys newKey, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - newPrivateKey, err := newKey.MarshalPrivate() + newPrivateKey, err := newKey.MarshalSigner() c.Assert(err, IsNil) c.Assert(store.SavePrivateKey("root", newPrivateKey), IsNil) assertKeys("root", true, []*data.PrivateKey{privateKey, newPrivateKey}) @@ -1248,14 +1248,14 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) { insecureStore := FileSystemStore(tmp.path, nil) key, err = keys.GenerateEd25519Key() c.Assert(err, IsNil) - privateKey, err = key.MarshalPrivate() + privateKey, err = key.MarshalSigner() c.Assert(err, IsNil) c.Assert(insecureStore.SavePrivateKey("root", privateKey), Equals, ErrPassphraseRequired{"root"}) // save a key to an insecure store and check it is not encrypted key, err = keys.GenerateEd25519Key() c.Assert(err, IsNil) - privateKey, err = key.MarshalPrivate() + privateKey, err = key.MarshalSigner() c.Assert(err, IsNil) c.Assert(insecureStore.SavePrivateKey("targets", privateKey), IsNil) assertKeys("targets", false, []*data.PrivateKey{privateKey}) @@ -1511,7 +1511,7 @@ func (rs *RepoSuite) TestAddOrUpdateSignatures(c *C) { c.Assert(err, IsNil) rootSig, err := rootKey.Sign(rand.Reader, rootMeta.Signed, crypto.Hash(0)) c.Assert(err, IsNil) - for _, id := range rootKey.IDs() { + for _, id := range rootKey.PublicData().IDs() { c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{ KeyID: id, Signature: rootSig}), IsNil) @@ -1523,7 +1523,7 @@ func (rs *RepoSuite) TestAddOrUpdateSignatures(c *C) { c.Assert(err, IsNil) targetsSig, err := targetsKey.Sign(rand.Reader, targetsMeta.Signed, crypto.Hash(0)) c.Assert(err, IsNil) - for _, id := range targetsKey.IDs() { + for _, id := range targetsKey.PublicData().IDs() { r.AddOrUpdateSignature("targets.json", data.Signature{ KeyID: id, Signature: targetsSig}) @@ -1535,7 +1535,7 @@ func (rs *RepoSuite) TestAddOrUpdateSignatures(c *C) { c.Assert(err, IsNil) snapshotSig, err := snapshotKey.Sign(rand.Reader, snapshotMeta.Signed, crypto.Hash(0)) c.Assert(err, IsNil) - for _, id := range snapshotKey.IDs() { + for _, id := range snapshotKey.PublicData().IDs() { r.AddOrUpdateSignature("snapshot.json", data.Signature{ KeyID: id, Signature: snapshotSig}) @@ -1546,7 +1546,7 @@ func (rs *RepoSuite) TestAddOrUpdateSignatures(c *C) { c.Assert(err, IsNil) timestampSig, err := timestampKey.Sign(rand.Reader, timestampMeta.Signed, crypto.Hash(0)) c.Assert(err, IsNil) - for _, id := range timestampKey.IDs() { + for _, id := range timestampKey.PublicData().IDs() { r.AddOrUpdateSignature("timestamp.json", data.Signature{ KeyID: id, Signature: timestampSig}) @@ -1584,14 +1584,14 @@ func (rs *RepoSuite) TestBadAddOrUpdateSignatures(c *C) { c.Assert(err, IsNil) rootSig, err := rootKey.Sign(rand.Reader, rootMeta.Signed, crypto.Hash(0)) c.Assert(err, IsNil) - for _, id := range rootKey.IDs() { + for _, id := range rootKey.PublicData().IDs() { c.Assert(r.AddOrUpdateSignature("invalid_root.json", data.Signature{ KeyID: id, Signature: rootSig}), Equals, ErrInvalidRole{"invalid_root"}) } // add a root signature with an key ID that is for the targets role - for _, id := range targetsKey.IDs() { + for _, id := range targetsKey.PublicData().IDs() { c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{ KeyID: id, Signature: rootSig}), Equals, verify.ErrInvalidKey) @@ -1600,14 +1600,14 @@ func (rs *RepoSuite) TestBadAddOrUpdateSignatures(c *C) { // attempt to add a bad signature to root badSig, err := rootKey.Sign(rand.Reader, []byte(""), crypto.Hash(0)) c.Assert(err, IsNil) - for _, id := range rootKey.IDs() { + for _, id := range rootKey.PublicData().IDs() { c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{ KeyID: id, Signature: badSig}), Equals, verify.ErrInvalid) } // add the correct root signature - for _, id := range rootKey.IDs() { + for _, id := range rootKey.PublicData().IDs() { c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{ KeyID: id, Signature: rootSig}), IsNil) @@ -1632,7 +1632,7 @@ func (rs *RepoSuite) TestBadAddOrUpdateSignatures(c *C) { // re-adding should not duplicate. this is checked by verifying // signature key IDs match with the map of role key IDs. - for _, id := range rootKey.IDs() { + for _, id := range rootKey.PublicData().IDs() { c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{ KeyID: id, Signature: rootSig}), IsNil) diff --git a/sign/sign.go b/sign/sign.go index 1c8410c7..3029956f 100644 --- a/sign/sign.go +++ b/sign/sign.go @@ -10,7 +10,7 @@ import ( ) func Sign(s *data.Signed, k keys.Signer) error { - ids := k.IDs() + ids := k.PublicData().IDs() signatures := make([]data.Signature, 0, len(s.Signatures)+1) for _, sig := range s.Signatures { found := false diff --git a/verify/verify.go b/verify/verify.go index 3bcb4108..5c6476b0 100644 --- a/verify/verify.go +++ b/verify/verify.go @@ -93,7 +93,7 @@ func (db *DB) VerifySignatures(s *data.Signed, role string) error { // Only consider this key valid if we haven't seen any of it's // key ids before. if _, ok := seen[sig.KeyID]; !ok { - for _, id := range key.IDs() { + for _, id := range key.MarshalKey().IDs() { seen[id] = struct{}{} } diff --git a/verify/verify_test.go b/verify/verify_test.go index 440e2afa..833fd4c5 100644 --- a/verify/verify_test.go +++ b/verify/verify_test.go @@ -59,15 +59,7 @@ func (s ecdsaSigner) ContainsID(id string) bool { return s.PublicData().ContainsID(id) } -func (ecdsaSigner) Type() string { - return data.KeyTypeECDSA_SHA2_P256 -} - -func (ecdsaSigner) Scheme() string { - return data.KeySchemeECDSA_SHA2_P256 -} - -func (ecdsaSigner) MarshalPrivate() (*data.PrivateKey, error) { +func (ecdsaSigner) MarshalSigner() (*data.PrivateKey, error) { return nil, errors.New("not implemented") } From e437fd6244a13e1303c2c12a43ca5cad9a2f3607 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Tue, 7 Sep 2021 10:53:28 -0500 Subject: [PATCH 07/17] move into pkg/ Signed-off-by: Asra Ali --- client/client_test.go | 2 +- client/python_interop/python_interop_test.go | 2 +- client/testdata/go-tuf-transition-M3/generate.go | 2 +- client/testdata/go-tuf-transition-M4/generate.go | 2 +- client/testdata/go-tuf/generator/generator.go | 2 +- local_store.go | 2 +- {keys => pkg/keys}/ecdsa.go | 0 {keys => pkg/keys}/ed25519.go | 0 {keys => pkg/keys}/ed25519_test.go | 0 {keys => pkg/keys}/keys.go | 0 {keys => pkg/keys}/keys_test.go | 0 repo.go | 2 +- repo_test.go | 2 +- sign/sign.go | 2 +- verify/db.go | 2 +- verify/verify_test.go | 2 +- 16 files changed, 11 insertions(+), 11 deletions(-) rename {keys => pkg/keys}/ecdsa.go (100%) rename {keys => pkg/keys}/ed25519.go (100%) rename {keys => pkg/keys}/ed25519_test.go (100%) rename {keys => pkg/keys}/keys.go (100%) rename {keys => pkg/keys}/keys_test.go (100%) diff --git a/client/client_test.go b/client/client_test.go index 767c8855..fb1090b1 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -14,7 +14,7 @@ import ( cjson "github.com/tent/canonical-json-go" tuf "github.com/theupdateframework/go-tuf" "github.com/theupdateframework/go-tuf/data" - "github.com/theupdateframework/go-tuf/keys" + "github.com/theupdateframework/go-tuf/pkg/keys" "github.com/theupdateframework/go-tuf/sign" "github.com/theupdateframework/go-tuf/util" "github.com/theupdateframework/go-tuf/verify" diff --git a/client/python_interop/python_interop_test.go b/client/python_interop/python_interop_test.go index b047e959..51dfca9f 100644 --- a/client/python_interop/python_interop_test.go +++ b/client/python_interop/python_interop_test.go @@ -15,7 +15,7 @@ import ( tuf "github.com/theupdateframework/go-tuf" client "github.com/theupdateframework/go-tuf/client" "github.com/theupdateframework/go-tuf/data" - "github.com/theupdateframework/go-tuf/keys" + "github.com/theupdateframework/go-tuf/pkg/keys" "github.com/theupdateframework/go-tuf/util" "golang.org/x/crypto/ed25519" . "gopkg.in/check.v1" diff --git a/client/testdata/go-tuf-transition-M3/generate.go b/client/testdata/go-tuf-transition-M3/generate.go index 08417b5b..85f2aebd 100644 --- a/client/testdata/go-tuf-transition-M3/generate.go +++ b/client/testdata/go-tuf-transition-M3/generate.go @@ -12,7 +12,7 @@ import ( tuf "github.com/theupdateframework/go-tuf" "github.com/theupdateframework/go-tuf/data" - "github.com/theupdateframework/go-tuf/keys" + "github.com/theupdateframework/go-tuf/pkg/keys" ) var expirationDate = time.Date(2100, time.January, 1, 0, 0, 0, 0, time.UTC) diff --git a/client/testdata/go-tuf-transition-M4/generate.go b/client/testdata/go-tuf-transition-M4/generate.go index 9206a03a..f0c277ac 100644 --- a/client/testdata/go-tuf-transition-M4/generate.go +++ b/client/testdata/go-tuf-transition-M4/generate.go @@ -12,7 +12,7 @@ import ( tuf "github.com/theupdateframework/go-tuf" "github.com/theupdateframework/go-tuf/data" - "github.com/theupdateframework/go-tuf/keys" + "github.com/theupdateframework/go-tuf/pkg/keys" ) var expirationDate = time.Date(2100, time.January, 1, 0, 0, 0, 0, time.UTC) diff --git a/client/testdata/go-tuf/generator/generator.go b/client/testdata/go-tuf/generator/generator.go index b1966543..938234b9 100644 --- a/client/testdata/go-tuf/generator/generator.go +++ b/client/testdata/go-tuf/generator/generator.go @@ -12,7 +12,7 @@ import ( tuf "github.com/theupdateframework/go-tuf" "github.com/theupdateframework/go-tuf/data" - "github.com/theupdateframework/go-tuf/keys" + "github.com/theupdateframework/go-tuf/pkg/keys" ) var expirationDate = time.Date(2100, time.January, 1, 0, 0, 0, 0, time.UTC) diff --git a/local_store.go b/local_store.go index 69faec70..c0daa92c 100644 --- a/local_store.go +++ b/local_store.go @@ -11,7 +11,7 @@ import ( "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/encrypted" - "github.com/theupdateframework/go-tuf/keys" + "github.com/theupdateframework/go-tuf/pkg/keys" "github.com/theupdateframework/go-tuf/util" ) diff --git a/keys/ecdsa.go b/pkg/keys/ecdsa.go similarity index 100% rename from keys/ecdsa.go rename to pkg/keys/ecdsa.go diff --git a/keys/ed25519.go b/pkg/keys/ed25519.go similarity index 100% rename from keys/ed25519.go rename to pkg/keys/ed25519.go diff --git a/keys/ed25519_test.go b/pkg/keys/ed25519_test.go similarity index 100% rename from keys/ed25519_test.go rename to pkg/keys/ed25519_test.go diff --git a/keys/keys.go b/pkg/keys/keys.go similarity index 100% rename from keys/keys.go rename to pkg/keys/keys.go diff --git a/keys/keys_test.go b/pkg/keys/keys_test.go similarity index 100% rename from keys/keys_test.go rename to pkg/keys/keys_test.go diff --git a/repo.go b/repo.go index 5c46c6b8..36ecec90 100644 --- a/repo.go +++ b/repo.go @@ -11,7 +11,7 @@ import ( cjson "github.com/tent/canonical-json-go" "github.com/theupdateframework/go-tuf/data" - "github.com/theupdateframework/go-tuf/keys" + "github.com/theupdateframework/go-tuf/pkg/keys" "github.com/theupdateframework/go-tuf/sign" "github.com/theupdateframework/go-tuf/util" "github.com/theupdateframework/go-tuf/verify" diff --git a/repo_test.go b/repo_test.go index f02d307c..7e869251 100644 --- a/repo_test.go +++ b/repo_test.go @@ -15,7 +15,7 @@ import ( "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/encrypted" - "github.com/theupdateframework/go-tuf/keys" + "github.com/theupdateframework/go-tuf/pkg/keys" "github.com/theupdateframework/go-tuf/util" "github.com/theupdateframework/go-tuf/verify" "golang.org/x/crypto/ed25519" diff --git a/sign/sign.go b/sign/sign.go index 3029956f..9ee19ce3 100644 --- a/sign/sign.go +++ b/sign/sign.go @@ -6,7 +6,7 @@ import ( cjson "github.com/tent/canonical-json-go" "github.com/theupdateframework/go-tuf/data" - "github.com/theupdateframework/go-tuf/keys" + "github.com/theupdateframework/go-tuf/pkg/keys" ) func Sign(s *data.Signed, k keys.Signer) error { diff --git a/verify/db.go b/verify/db.go index ff726587..70f0b44a 100644 --- a/verify/db.go +++ b/verify/db.go @@ -2,7 +2,7 @@ package verify import ( "github.com/theupdateframework/go-tuf/data" - "github.com/theupdateframework/go-tuf/keys" + "github.com/theupdateframework/go-tuf/pkg/keys" ) type Role struct { diff --git a/verify/verify_test.go b/verify/verify_test.go index 833fd4c5..d65c03c9 100644 --- a/verify/verify_test.go +++ b/verify/verify_test.go @@ -13,7 +13,7 @@ import ( "time" "github.com/theupdateframework/go-tuf/data" - "github.com/theupdateframework/go-tuf/keys" + "github.com/theupdateframework/go-tuf/pkg/keys" "github.com/theupdateframework/go-tuf/sign" "golang.org/x/crypto/ed25519" From f042dd5e52a1d29a4485ef996a46c5fcd3c58b9b Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Tue, 7 Sep 2021 10:57:41 -0500 Subject: [PATCH 08/17] update impls Signed-off-by: Asra Ali --- pkg/keys/ecdsa.go | 4 ---- pkg/keys/ed25519.go | 4 ---- 2 files changed, 8 deletions(-) diff --git a/pkg/keys/ecdsa.go b/pkg/keys/ecdsa.go index 4489e1a0..dd3314f9 100644 --- a/pkg/keys/ecdsa.go +++ b/pkg/keys/ecdsa.go @@ -69,7 +69,3 @@ func (p *p256Verifier) UnmarshalKey(key *data.Key) error { p.key = key return nil } - -func (p *p256Verifier) IDs() []string { - return p.key.IDs() -} diff --git a/pkg/keys/ed25519.go b/pkg/keys/ed25519.go index fa7f9290..73aa760b 100644 --- a/pkg/keys/ed25519.go +++ b/pkg/keys/ed25519.go @@ -54,10 +54,6 @@ func (e *ed25519Verifier) UnmarshalKey(key *data.Key) error { return nil } -func (e *ed25519Verifier) IDs() []string { - return e.key.IDs() -} - type ed25519PrivateKeyValue struct { Public data.HexBytes `json:"public"` Private data.HexBytes `json:"private"` From 1b5ff03be2b595e46900d30d34c29cbd1b964c81 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Fri, 10 Sep 2021 09:03:17 -0500 Subject: [PATCH 09/17] remove empty block Signed-off-by: Asra Ali --- repo.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/repo.go b/repo.go index 36ecec90..19c6d945 100644 --- a/repo.go +++ b/repo.go @@ -401,10 +401,6 @@ func validExpires(expires time.Time) bool { return expires.Sub(time.Now()) > 0 } -/* - - */ - func (r *Repo) RootKeys() ([]*data.Key, error) { root, err := r.root() if err != nil { From d092aa0a5454b937346e97eb14362f48b5bdb5c4 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Fri, 10 Sep 2021 11:24:46 -0500 Subject: [PATCH 10/17] joshua suggestions Signed-off-by: Asra Ali --- pkg/keys/keys.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/keys/keys.go b/pkg/keys/keys.go index e2002cf2..42ee9ec1 100644 --- a/pkg/keys/keys.go +++ b/pkg/keys/keys.go @@ -26,7 +26,7 @@ type Verifier interface { // to verify signatures. UnmarshalKey(key *data.Key) error - // Key returns the data.Key object associated with the verifier. + // MarshalKey returns the data.Key object associated with the verifier. MarshalKey() *data.Key // This is the public string used as a unique identifier for the verifier instance. @@ -39,10 +39,10 @@ type Verifier interface { } type Signer interface { - // Marshal into a private key. + // MarshalSigner returns the private key data. MarshalSigner() (*data.PrivateKey, error) - // UnmarshalKey takes private key data to a working Signer implementation for the key type. + // UnmarshalSigner takes private key data to a working Signer implementation for the key type. UnmarshalSigner(key *data.PrivateKey) error // Returns the public data.Key from the private key From f6cc92a9c686d3a81cb07b1fee002da9bda87cef Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Wed, 22 Sep 2021 10:02:44 -0500 Subject: [PATCH 11/17] add rsa key Signed-off-by: Asra Ali --- data/types.go | 12 +++--- pkg/keys/ecdsa.go | 4 +- pkg/keys/ed25519.go | 4 +- pkg/keys/keys_test.go | 4 +- pkg/keys/rsa.go | 83 +++++++++++++++++++++++++++++++++++++ pkg/keys/rsa_test.go | 96 +++++++++++++++++++++++++++++++++++++++++++ verify/verify_test.go | 4 +- 7 files changed, 194 insertions(+), 13 deletions(-) create mode 100644 pkg/keys/rsa.go create mode 100644 pkg/keys/rsa_test.go diff --git a/data/types.go b/data/types.go index ed1b45cc..2e90da5d 100644 --- a/data/types.go +++ b/data/types.go @@ -14,11 +14,13 @@ import ( ) const ( - KeyIDLength = sha256.Size * 2 - KeyTypeEd25519 = "ed25519" - KeyTypeECDSA_SHA2_P256 = "ecdsa-sha2-nistp256" - KeySchemeEd25519 = "ed25519" - KeySchemeECDSA_SHA2_P256 = "ecdsa-sha2-nistp256" + KeyIDLength = sha256.Size * 2 + KeyTypeEd25519 = "ed25519" + KeyTypeECDSA_SHA2_P256 = "ecdsa-sha2-nistp256" + KeySchemeEd25519 = "ed25519" + KeySchemeECDSA_SHA2_P256 = "ecdsa-sha2-nistp256" + KeyTypeRSASSA_PSS_SHA256 = "rsa" + KeySchemeRSASSA_PSS_SHA256 = "rsassa-pss-sha256" ) var ( diff --git a/pkg/keys/ecdsa.go b/pkg/keys/ecdsa.go index dd3314f9..420c66e1 100644 --- a/pkg/keys/ecdsa.go +++ b/pkg/keys/ecdsa.go @@ -60,11 +60,11 @@ func (p *p256Verifier) MarshalKey() *data.Key { func (p *p256Verifier) UnmarshalKey(key *data.Key) error { if err := json.Unmarshal(key.Value, p); err != nil { - return errors.New("unmarshalling key") + return errors.New("unmarshalling ecdsa key") } x, _ := elliptic.Unmarshal(elliptic.P256(), p.PublicKey) if x == nil { - return errors.New("unmarshalling key") + return errors.New("invalid public key point for ecdsa key") } p.key = key return nil diff --git a/pkg/keys/ed25519.go b/pkg/keys/ed25519.go index 73aa760b..904f6ebb 100644 --- a/pkg/keys/ed25519.go +++ b/pkg/keys/ed25519.go @@ -46,10 +46,10 @@ func (e *ed25519Verifier) MarshalKey() *data.Key { func (e *ed25519Verifier) UnmarshalKey(key *data.Key) error { e.key = key if err := json.Unmarshal(key.Value, e); err != nil { - return errors.New("unmarshalling key") + return errors.New("unmarshalling ed25519 key") } if len(e.PublicKey) != ed25519.PublicKeySize { - return errors.New("unmarshalling key") + return errors.New("unexpected public key length for ed25519 key") } return nil } diff --git a/pkg/keys/keys_test.go b/pkg/keys/keys_test.go index 93b1d3bc..fe42e076 100644 --- a/pkg/keys/keys_test.go +++ b/pkg/keys/keys_test.go @@ -14,11 +14,11 @@ type KeysSuite struct{} var _ = Suite(&KeysSuite{}) func (KeysSuite) TestSignerKeyIDs(c *C) { - key, err := GenerateEd25519Key() + _, err := GenerateEd25519Key() c.Assert(err, IsNil) // If we have a TUF-0.9 key, we won't have a scheme. - key, err = GenerateEd25519Key() + key, err := GenerateEd25519Key() c.Assert(err, IsNil) privKey, err := key.MarshalSigner() c.Assert(err, IsNil) diff --git a/pkg/keys/rsa.go b/pkg/keys/rsa.go new file mode 100644 index 00000000..5d496e19 --- /dev/null +++ b/pkg/keys/rsa.go @@ -0,0 +1,83 @@ +package keys + +import ( + "crypto" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/json" + "encoding/pem" + + "github.com/pkg/errors" + + "github.com/theupdateframework/go-tuf/data" +) + +func init() { + VerifierMap.Store(data.KeyTypeRSASSA_PSS_SHA256, NewRsaVerifier) +} + +func NewRsaVerifier() Verifier { + return &rsaVerifier{} +} + +type rsaVerifier struct { + PublicKey string `json:"public"` + rsaKey *rsa.PublicKey + key *data.Key +} + +func (p *rsaVerifier) Public() string { + // Unique public key identifier, use a uniform encodng + r, err := x509.MarshalPKIXPublicKey(p.rsaKey) + if err != nil { + // This shouldn't happen with a valid rsa key, but fallback on the + // JSON public key string + return string(p.PublicKey) + } + return string(r) +} + +func (p *rsaVerifier) Verify(msg, sigBytes []byte) error { + hash := sha256.Sum256(msg) + + return rsa.VerifyPSS(p.rsaKey, crypto.SHA256, hash[:], sigBytes, &rsa.PSSOptions{}) +} + +func (p *rsaVerifier) MarshalKey() *data.Key { + return p.key +} + +func (p *rsaVerifier) UnmarshalKey(key *data.Key) error { + if err := json.Unmarshal(key.Value, p); err != nil { + return errors.Wrap(err, "unmarshalling rsa key") + } + var err error + p.rsaKey, err = parseKey(p.PublicKey) + if err != nil { + return err + } + p.key = key + return nil +} + +// parseKey tries to parse a PEM []byte slice by attempting PKCS1 and PKIX in order. +func parseKey(data string) (*rsa.PublicKey, error) { + block, _ := pem.Decode([]byte(data)) + if block == nil { + return nil, errors.New("invalid pem public key") + } + rsaPub, err := x509.ParsePKCS1PublicKey(block.Bytes) + if err == nil { + return rsaPub, nil + } + key, err := x509.ParsePKIXPublicKey(block.Bytes) + if err == nil { + rsaPub, ok := key.(*rsa.PublicKey) + if !ok { + return nil, errors.New("parsing invalid rsa key") + } + return rsaPub, nil + } + return nil, errors.New("unmarshalling rsa key") +} diff --git a/pkg/keys/rsa_test.go b/pkg/keys/rsa_test.go new file mode 100644 index 00000000..7a365db4 --- /dev/null +++ b/pkg/keys/rsa_test.go @@ -0,0 +1,96 @@ +package keys + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/json" + "encoding/pem" + "errors" + "io" + + . "gopkg.in/check.v1" + + "github.com/theupdateframework/go-tuf/data" +) + +type rsaSigner struct { + *rsa.PrivateKey +} + +type rsaPublic struct { + // PEM encoded public key. + PublicKey string `json:"public"` +} + +func (s rsaSigner) PublicData() *data.Key { + pub, _ := x509.MarshalPKIXPublicKey(s.Public().(*rsa.PublicKey)) + pubBytes := pem.EncodeToMemory(&pem.Block{ + Type: "RSA PUBLIC KEY", + Bytes: pub, + }) + + keyValBytes, _ := json.Marshal(rsaPublic{PublicKey: string(pubBytes)}) + return &data.Key{ + Type: data.KeyTypeRSASSA_PSS_SHA256, + Scheme: data.KeySchemeRSASSA_PSS_SHA256, + Algorithms: data.KeyAlgorithms, + Value: keyValBytes, + } +} + +func (s rsaSigner) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { + hash := sha256.Sum256(msg) + return rsa.SignPSS(rand, s.PrivateKey, crypto.SHA256, hash[:], &rsa.PSSOptions{}) +} + +func (s rsaSigner) IDs() []string { + return s.PublicData().IDs() +} + +func (s rsaSigner) ContainsID(id string) bool { + return s.PublicData().ContainsID(id) +} + +func (rsaSigner) MarshalSigner() (*data.PrivateKey, error) { + return nil, errors.New("not implemented for test") +} + +func (rsaSigner) UnmarshalSigner(key *data.PrivateKey) error { + return errors.New("not implemented for test") +} + +func GenerateRsaKey() (*rsaSigner, error) { + privkey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, err + } + return &rsaSigner{privkey}, nil +} + +type RsaSuite struct{} + +var _ = Suite(&RsaSuite{}) + +func (RsaSuite) TestSignVerify(c *C) { + key, err := GenerateRsaKey() + c.Assert(err, IsNil) + msg := []byte("foo") + sig, err := key.Sign(rand.Reader, msg, crypto.Hash(0)) + c.Assert(err, IsNil) + publicData := key.PublicData() + pubKey, err := GetVerifier(publicData) + c.Assert(err, IsNil) + c.Assert(pubKey.Verify(msg, sig), IsNil) +} + +func (RsaSuite) TestMarshalUnmarshal(c *C) { + key, err := GenerateRsaKey() + c.Assert(err, IsNil) + publicData := key.PublicData() + pubKey, err := GetVerifier(publicData) + c.Assert(err, IsNil) + c.Assert(pubKey.MarshalKey(), DeepEquals, publicData) +} diff --git a/verify/verify_test.go b/verify/verify_test.go index d65c03c9..a0ed3c90 100644 --- a/verify/verify_test.go +++ b/verify/verify_test.go @@ -60,11 +60,11 @@ func (s ecdsaSigner) ContainsID(id string) bool { } func (ecdsaSigner) MarshalSigner() (*data.PrivateKey, error) { - return nil, errors.New("not implemented") + return nil, errors.New("not implemented for test") } func (ecdsaSigner) UnmarshalSigner(key *data.PrivateKey) error { - return errors.New("not implemented") + return errors.New("not implemented for test") } func (VerifySuite) Test(c *C) { From fadd6cb5109f1bebfa6c8dab3f5d7f4bd32ba2b0 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Thu, 23 Sep 2021 10:53:40 -0500 Subject: [PATCH 12/17] address comments Signed-off-by: Asra Ali --- local_store.go | 18 +++++++++--------- pkg/keys/ed25519.go | 1 - 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/local_store.go b/local_store.go index c0daa92c..529b2707 100644 --- a/local_store.go +++ b/local_store.go @@ -15,7 +15,7 @@ import ( "github.com/theupdateframework/go-tuf/util" ) -func privateKeySigners(privateKeys []*data.PrivateKey) []keys.Signer { +func signers(privateKeys []*data.PrivateKey) []keys.Signer { res := make([]keys.Signer, len(privateKeys)) for i, k := range privateKeys { signer, err := keys.GetSigner(k) @@ -99,7 +99,7 @@ func (m *memoryStore) GetSigningKeys(role string) ([]keys.Signer, error) { } func (m *memoryStore) SavePrivateKey(role string, key *data.PrivateKey) error { - signers := privateKeySigners([]*data.PrivateKey{key}) + signers := signers([]*data.PrivateKey{key}) m.signers[role] = append(m.signers[role], signers...) return nil } @@ -321,14 +321,14 @@ func (f *fileSystemStore) GetSigningKeys(role string) ([]keys.Signer, error) { if keys, ok := f.signers[role]; ok { return keys, nil } - keys, _, err := f.loadKeys(role) + keys, _, err := f.loadPrivateKeys(role) if err != nil { if os.IsNotExist(err) { return nil, nil } return nil, err } - f.signers[role] = privateKeySigners(keys) + f.signers[role] = signers(keys) return f.signers[role], nil } @@ -338,13 +338,13 @@ func (f *fileSystemStore) SavePrivateKey(role string, key *data.PrivateKey) erro } // add the key to the existing keys (if any) - keys, pass, err := f.loadKeys(role) + keys, pass, err := f.loadPrivateKeys(role) if err != nil && !os.IsNotExist(err) { return err } keys = append(keys, key) - // if loadKeys didn't return a passphrase (because no keys yet exist) + // if loadPrivateKeys didn't return a passphrase (because no keys yet exist) // and passphraseFunc is set, get the passphrase so the keys file can // be encrypted later (passphraseFunc being nil indicates the keys file // should not be encrypted) @@ -375,13 +375,13 @@ func (f *fileSystemStore) SavePrivateKey(role string, key *data.PrivateKey) erro if err := util.AtomicallyWriteFile(f.keysPath(role), append(data, '\n'), 0600); err != nil { return err } - f.signers[role] = privateKeySigners(keys) + f.signers[role] = signers(keys) return nil } -// loadKeys loads keys for the given role and returns them along with the +// loadPrivateKeys loads keys for the given role and returns them along with the // passphrase (if read) so that callers don't need to re-read it. -func (f *fileSystemStore) loadKeys(role string) ([]*data.PrivateKey, []byte, error) { +func (f *fileSystemStore) loadPrivateKeys(role string) ([]*data.PrivateKey, []byte, error) { file, err := os.Open(f.keysPath(role)) if err != nil { return nil, nil, err diff --git a/pkg/keys/ed25519.go b/pkg/keys/ed25519.go index 904f6ebb..30cc2668 100644 --- a/pkg/keys/ed25519.go +++ b/pkg/keys/ed25519.go @@ -12,7 +12,6 @@ import ( func init() { SignerMap.Store(data.KeySchemeEd25519, NewP256Signer) VerifierMap.Store(data.KeySchemeEd25519, NewP256Verifier) - } func NewP256Signer() Signer { From 9545f820e4ee7995841c80d28cbac8c859b233f0 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Thu, 23 Sep 2021 12:14:03 -0500 Subject: [PATCH 13/17] update method name Signed-off-by: Asra Ali --- client/client_test.go | 2 +- local_store.go | 4 ++-- repo.go | 6 +++--- repo_test.go | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/client/client_test.go b/client/client_test.go index 7a85aa19..e0420683 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -1120,7 +1120,7 @@ func (s *ClientSuite) TestUnknownKeyIDs(c *C) { root.Signed.Keys["unknown-key-id"] = key.PublicData() // re-sign the root metadata, then commit it back into the store. - signingKeys, err := s.store.GetSigningKeys("root") + signingKeys, err := s.store.GetSigners("root") c.Assert(err, IsNil) signedRoot, err := sign.Marshal(root.Signed, signingKeys...) diff --git a/local_store.go b/local_store.go index 529b2707..610845ea 100644 --- a/local_store.go +++ b/local_store.go @@ -94,7 +94,7 @@ func (m *memoryStore) Commit(consistentSnapshot bool, versions map[string]int, h return nil } -func (m *memoryStore) GetSigningKeys(role string) ([]keys.Signer, error) { +func (m *memoryStore) GetSigners(role string) ([]keys.Signer, error) { return m.signers[role], nil } @@ -317,7 +317,7 @@ func (f *fileSystemStore) Commit(consistentSnapshot bool, versions map[string]in return f.Clean() } -func (f *fileSystemStore) GetSigningKeys(role string) ([]keys.Signer, error) { +func (f *fileSystemStore) GetSigners(role string) ([]keys.Signer, error) { if keys, ok := f.signers[role]; ok { return keys, nil } diff --git a/repo.go b/repo.go index 12b49ee6..2f26119b 100644 --- a/repo.go +++ b/repo.go @@ -50,8 +50,8 @@ type LocalStore interface { // Commit is used to publish staged files to the repository Commit(bool, map[string]int, map[string]data.Hashes) error - // GetSigningKeys return a list of signing keys for a role. - GetSigningKeys(string) ([]keys.Signer, error) + // GetSigners return a list of signing keys for a role. + GetSigners(string) ([]keys.Signer, error) // SavePrivateKey adds a signing key to a role. SavePrivateKey(string, *data.PrivateKey) error @@ -609,7 +609,7 @@ func (r *Repo) AddOrUpdateSignature(roleFilename string, signature data.Signatur // keys are returned (revoked root keys still need to sign new root metadata so // clients can verify the new root.json and update their keys db accordingly). func (r *Repo) getSigningKeys(name string) ([]keys.Signer, error) { - signingKeys, err := r.local.GetSigningKeys(name) + signingKeys, err := r.local.GetSigners(name) if err != nil { return nil, err } diff --git a/repo_test.go b/repo_test.go index 79f109bc..e2a67dac 100644 --- a/repo_test.go +++ b/repo_test.go @@ -218,7 +218,7 @@ func (rs *RepoSuite) TestGenKey(c *C) { c.Assert(role.KeyIDs, DeepEquals, util.StringSliceToSet(ids)) // check the key was saved correctly - localKeys, err := local.GetSigningKeys("root") + localKeys, err := local.GetSigners("root") c.Assert(err, IsNil) c.Assert(localKeys, HasLen, 1) c.Assert(localKeys[0].PublicData().IDs(), DeepEquals, ids) @@ -274,7 +274,7 @@ func (rs *RepoSuite) TestGenKey(c *C) { c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalKey().IDs()) // check the keys were saved correctly - localKeys, err := local.GetSigningKeys("targets") + localKeys, err := local.GetSigners("targets") c.Assert(err, IsNil) c.Assert(localKeys, HasLen, 2) for _, key := range localKeys { @@ -381,7 +381,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { c.Assert(role.KeyIDs, DeepEquals, util.StringSliceToSet(ids)) // check the key was saved correctly - localKeys, err := local.GetSigningKeys("root") + localKeys, err := local.GetSigners("root") c.Assert(err, IsNil) c.Assert(localKeys, HasLen, 1) c.Assert(localKeys[0].PublicData().IDs(), DeepEquals, ids) @@ -437,7 +437,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalKey().IDs()) // check the keys were saved correctly - localKeys, err := local.GetSigningKeys("targets") + localKeys, err := local.GetSigners("targets") c.Assert(err, IsNil) c.Assert(localKeys, HasLen, 2) for _, key := range localKeys { @@ -1215,7 +1215,7 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) { } // check GetKeys is correct - signers, err := store.GetSigningKeys(role) + signers, err := store.GetSigners(role) c.Assert(err, IsNil) c.Assert(signers, HasLen, len(expected)) for i, s := range signers { From ef1ad4870b879bd551863e69634186c608208686 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Mon, 27 Sep 2021 10:27:53 -0500 Subject: [PATCH 14/17] address preliminary comments Signed-off-by: Asra Ali --- local_store.go | 13 ++++++++----- pkg/keys/ecdsa.go | 6 +++--- pkg/keys/ed25519.go | 8 ++++---- pkg/keys/ed25519_test.go | 14 ++++++++++++++ pkg/keys/keys.go | 6 +++--- pkg/keys/rsa.go | 8 ++++---- pkg/keys/rsa_test.go | 4 ---- repo.go | 27 +++++++++++---------------- repo_test.go | 26 +++++++++++--------------- verify/verify_test.go | 4 ---- 10 files changed, 58 insertions(+), 58 deletions(-) diff --git a/local_store.go b/local_store.go index 610845ea..554b5199 100644 --- a/local_store.go +++ b/local_store.go @@ -98,9 +98,8 @@ func (m *memoryStore) GetSigners(role string) ([]keys.Signer, error) { return m.signers[role], nil } -func (m *memoryStore) SavePrivateKey(role string, key *data.PrivateKey) error { - signers := signers([]*data.PrivateKey{key}) - m.signers[role] = append(m.signers[role], signers...) +func (m *memoryStore) SaveSigner(role string, signer keys.Signer) error { + m.signers[role] = append(m.signers[role], signer) return nil } @@ -332,7 +331,7 @@ func (f *fileSystemStore) GetSigners(role string) ([]keys.Signer, error) { return f.signers[role], nil } -func (f *fileSystemStore) SavePrivateKey(role string, key *data.PrivateKey) error { +func (f *fileSystemStore) SaveSigner(role string, signer keys.Signer) error { if err := f.createDirs(); err != nil { return err } @@ -342,6 +341,10 @@ func (f *fileSystemStore) SavePrivateKey(role string, key *data.PrivateKey) erro if err != nil && !os.IsNotExist(err) { return err } + key, err := signer.MarshalSigner() + if err != nil { + return err + } keys = append(keys, key) // if loadPrivateKeys didn't return a passphrase (because no keys yet exist) @@ -375,7 +378,7 @@ func (f *fileSystemStore) SavePrivateKey(role string, key *data.PrivateKey) erro if err := util.AtomicallyWriteFile(f.keysPath(role), append(data, '\n'), 0600); err != nil { return err } - f.signers[role] = signers(keys) + f.signers[role] = append(f.signers[role], signer) return nil } diff --git a/pkg/keys/ecdsa.go b/pkg/keys/ecdsa.go index 420c66e1..914496c6 100644 --- a/pkg/keys/ecdsa.go +++ b/pkg/keys/ecdsa.go @@ -49,7 +49,7 @@ func (p *p256Verifier) Verify(msg, sigBytes []byte) error { hash := sha256.Sum256(msg) if !ecdsa.Verify(k, hash[:], sig.R, sig.S) { - return errors.New("verifying ecdsa signature") + return errors.New("tuf: ecdsa signature verification failed") } return nil } @@ -60,11 +60,11 @@ func (p *p256Verifier) MarshalKey() *data.Key { func (p *p256Verifier) UnmarshalKey(key *data.Key) error { if err := json.Unmarshal(key.Value, p); err != nil { - return errors.New("unmarshalling ecdsa key") + return err } x, _ := elliptic.Unmarshal(elliptic.P256(), p.PublicKey) if x == nil { - return errors.New("invalid public key point for ecdsa key") + return errors.New("tuf: invalid ecdsa public key point") } p.key = key return nil diff --git a/pkg/keys/ed25519.go b/pkg/keys/ed25519.go index 30cc2668..1b7fdc14 100644 --- a/pkg/keys/ed25519.go +++ b/pkg/keys/ed25519.go @@ -4,8 +4,8 @@ import ( "crypto/ed25519" "crypto/rand" "encoding/json" - "errors" + "github.com/pkg/errors" "github.com/theupdateframework/go-tuf/data" ) @@ -33,7 +33,7 @@ func (e *ed25519Verifier) Public() string { func (e *ed25519Verifier) Verify(msg, sig []byte) error { if !ed25519.Verify([]byte(e.PublicKey), msg, sig) { - return ErrInvalid + return errors.New("tuf: ed25519 signature verification failed") } return nil } @@ -45,10 +45,10 @@ func (e *ed25519Verifier) MarshalKey() *data.Key { func (e *ed25519Verifier) UnmarshalKey(key *data.Key) error { e.key = key if err := json.Unmarshal(key.Value, e); err != nil { - return errors.New("unmarshalling ed25519 key") + return err } if len(e.PublicKey) != ed25519.PublicKeySize { - return errors.New("unexpected public key length for ed25519 key") + return errors.New("tuf: unexpected public key length for ed25519 key") } return nil } diff --git a/pkg/keys/ed25519_test.go b/pkg/keys/ed25519_test.go index 4048bc3a..9b12cdfc 100644 --- a/pkg/keys/ed25519_test.go +++ b/pkg/keys/ed25519_test.go @@ -3,7 +3,9 @@ package keys import ( "crypto" "crypto/rand" + "encoding/json" + "github.com/theupdateframework/go-tuf/data" . "gopkg.in/check.v1" ) @@ -11,6 +13,18 @@ type Ed25519Suite struct{} var _ = Suite(&Ed25519Suite{}) +func (Ed25519Suite) TestUnmarshalEd25519(c *C) { + badKeyValue, _ := json.Marshal(true) + badKey := &data.Key{ + Type: data.KeyTypeRSASSA_PSS_SHA256, + Scheme: data.KeySchemeRSASSA_PSS_SHA256, + Algorithms: data.KeyAlgorithms, + Value: badKeyValue, + } + verifier := NewP256Verifier() + c.Assert(verifier.UnmarshalKey(badKey), ErrorMatches, "json: cannot unmarshal.*") +} + func (Ed25519Suite) TestSignVerify(c *C) { key, err := GenerateEd25519Key() c.Assert(err, IsNil) diff --git a/pkg/keys/keys.go b/pkg/keys/keys.go index 42ee9ec1..347e7ffe 100644 --- a/pkg/keys/keys.go +++ b/pkg/keys/keys.go @@ -2,9 +2,9 @@ package keys import ( "crypto" - "errors" "sync" + "github.com/pkg/errors" "github.com/theupdateframework/go-tuf/data" ) @@ -61,7 +61,7 @@ func GetVerifier(key *data.Key) (Verifier, error) { } s := st.(func() Verifier)() if err := s.UnmarshalKey(key); err != nil { - return nil, ErrInvalidKey + return nil, errors.Wrap(err, "tuf: error unmarshalling key") } return s, nil } @@ -73,7 +73,7 @@ func GetSigner(key *data.PrivateKey) (Signer, error) { } s := st.(func() Signer)() if err := s.UnmarshalSigner(key); err != nil { - return nil, ErrInvalidKey + return nil, errors.Wrap(err, "tuf: error unmarshalling key") } return s, nil } diff --git a/pkg/keys/rsa.go b/pkg/keys/rsa.go index 5d496e19..846ed71a 100644 --- a/pkg/keys/rsa.go +++ b/pkg/keys/rsa.go @@ -50,7 +50,7 @@ func (p *rsaVerifier) MarshalKey() *data.Key { func (p *rsaVerifier) UnmarshalKey(key *data.Key) error { if err := json.Unmarshal(key.Value, p); err != nil { - return errors.Wrap(err, "unmarshalling rsa key") + return err } var err error p.rsaKey, err = parseKey(p.PublicKey) @@ -65,7 +65,7 @@ func (p *rsaVerifier) UnmarshalKey(key *data.Key) error { func parseKey(data string) (*rsa.PublicKey, error) { block, _ := pem.Decode([]byte(data)) if block == nil { - return nil, errors.New("invalid pem public key") + return nil, errors.New("tuf: pem decoding public key failed") } rsaPub, err := x509.ParsePKCS1PublicKey(block.Bytes) if err == nil { @@ -75,9 +75,9 @@ func parseKey(data string) (*rsa.PublicKey, error) { if err == nil { rsaPub, ok := key.(*rsa.PublicKey) if !ok { - return nil, errors.New("parsing invalid rsa key") + return nil, errors.New("tuf: invalid rsa key") } return rsaPub, nil } - return nil, errors.New("unmarshalling rsa key") + return nil, errors.New("tuf: error unmarshalling rsa key") } diff --git a/pkg/keys/rsa_test.go b/pkg/keys/rsa_test.go index 7a365db4..41037e5f 100644 --- a/pkg/keys/rsa_test.go +++ b/pkg/keys/rsa_test.go @@ -46,10 +46,6 @@ func (s rsaSigner) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]b return rsa.SignPSS(rand, s.PrivateKey, crypto.SHA256, hash[:], &rsa.PSSOptions{}) } -func (s rsaSigner) IDs() []string { - return s.PublicData().IDs() -} - func (s rsaSigner) ContainsID(id string) bool { return s.PublicData().ContainsID(id) } diff --git a/repo.go b/repo.go index 2f26119b..c3cc4544 100644 --- a/repo.go +++ b/repo.go @@ -50,11 +50,11 @@ type LocalStore interface { // Commit is used to publish staged files to the repository Commit(bool, map[string]int, map[string]data.Hashes) error - // GetSigners return a list of signing keys for a role. + // GetSigners return a list of signers for a role. GetSigners(string) ([]keys.Signer, error) - // SavePrivateKey adds a signing key to a role. - SavePrivateKey(string, *data.PrivateKey) error + // SavePrivateKey adds a signer to a role. + SaveSigner(string, keys.Signer) error // Clean is used to remove all staged manifests. Clean() error @@ -312,23 +312,23 @@ func (r *Repo) GenKey(role string) ([]string, error) { } func (r *Repo) GenKeyWithExpires(keyRole string, expires time.Time) ([]string, error) { - key, err := keys.GenerateEd25519Key() + signer, err := keys.GenerateEd25519Key() if err != nil { return []string{}, err } - if err = r.AddPrivateKeyWithExpires(keyRole, key, expires); err != nil { + if err = r.AddPrivateKeyWithExpires(keyRole, signer, expires); err != nil { return []string{}, err } - return key.PublicData().IDs(), nil + return signer.PublicData().IDs(), nil } -func (r *Repo) AddPrivateKey(role string, key keys.Signer) error { - return r.AddPrivateKeyWithExpires(role, key, data.DefaultExpires(role)) +func (r *Repo) AddPrivateKey(role string, signer keys.Signer) error { + return r.AddPrivateKeyWithExpires(role, signer, data.DefaultExpires(role)) } -func (r *Repo) AddPrivateKeyWithExpires(keyRole string, key keys.Signer, expires time.Time) error { +func (r *Repo) AddPrivateKeyWithExpires(keyRole string, signer keys.Signer, expires time.Time) error { if !verify.ValidRole(keyRole) { return ErrInvalidRole{keyRole} } @@ -337,16 +337,11 @@ func (r *Repo) AddPrivateKeyWithExpires(keyRole string, key keys.Signer, expires return ErrInvalidExpires{expires} } - privKey, err := key.MarshalSigner() - if err != nil { - return err - } - - if err := r.local.SavePrivateKey(keyRole, privKey); err != nil { + if err := r.local.SaveSigner(keyRole, signer); err != nil { return err } - if err = r.AddVerificationKeyWithExpiration(keyRole, key.PublicData(), expires); err != nil { + if err := r.AddVerificationKeyWithExpiration(keyRole, signer.PublicData(), expires); err != nil { return err } diff --git a/repo_test.go b/repo_test.go index e2a67dac..70f0abac 100644 --- a/repo_test.go +++ b/repo_test.go @@ -326,7 +326,7 @@ func addPrivateKey(c *C, r *Repo, role string, key keys.Signer) []string { return keyids } -func addGeneratedPrivateKey(c *C, r *Repo, role string) []string { +func generateAndAddPrivateKey(c *C, r *Repo, role string) []string { key, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) return addPrivateKey(c, r, role, key) @@ -400,8 +400,8 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { c.Assert(err, IsNil) // generate two targets keys - addGeneratedPrivateKey(c, r, "targets") - addGeneratedPrivateKey(c, r, "targets") + generateAndAddPrivateKey(c, r, "targets") + generateAndAddPrivateKey(c, r, "targets") // check root metadata is correct root, err = r.root() @@ -481,8 +481,8 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { c.Assert(stagedRoot.Roles, DeepEquals, root.Roles) // commit to make sure we don't modify metadata after committing metadata. - addGeneratedPrivateKey(c, r, "snapshot") - addGeneratedPrivateKey(c, r, "timestamp") + generateAndAddPrivateKey(c, r, "snapshot") + generateAndAddPrivateKey(c, r, "timestamp") c.Assert(r.AddTargets([]string{}, nil), IsNil) c.Assert(r.Snapshot(), IsNil) c.Assert(r.Timestamp(), IsNil) @@ -586,9 +586,7 @@ func (rs *RepoSuite) TestSign(c *C) { // signing with an available key generates a signature key, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - privateKey, err := key.MarshalSigner() - c.Assert(err, IsNil) - c.Assert(local.SavePrivateKey("root", privateKey), IsNil) + c.Assert(local.SaveSigner("root", key), IsNil) c.Assert(r.Sign("root.json"), IsNil) checkSigIDs(key.PublicData().IDs()...) @@ -599,9 +597,7 @@ func (rs *RepoSuite) TestSign(c *C) { // signing with a new available key generates another signature newKey, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - newPrivateKey, err := newKey.MarshalSigner() - c.Assert(err, IsNil) - c.Assert(local.SavePrivateKey("root", newPrivateKey), IsNil) + c.Assert(local.SaveSigner("root", newKey), IsNil) c.Assert(r.Sign("root.json"), IsNil) checkSigIDs(append(key.PublicData().IDs(), newKey.PublicData().IDs()...)...) } @@ -1230,7 +1226,7 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) { c.Assert(err, IsNil) privateKey, err := key.MarshalSigner() c.Assert(err, IsNil) - c.Assert(store.SavePrivateKey("root", privateKey), IsNil) + c.Assert(store.SaveSigner("root", key), IsNil) assertKeys("root", true, []*data.PrivateKey{privateKey}) // save another key and check it gets added to the existing keys @@ -1238,7 +1234,7 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) { c.Assert(err, IsNil) newPrivateKey, err := newKey.MarshalSigner() c.Assert(err, IsNil) - c.Assert(store.SavePrivateKey("root", newPrivateKey), IsNil) + c.Assert(store.SaveSigner("root", newKey), IsNil) assertKeys("root", true, []*data.PrivateKey{privateKey, newPrivateKey}) // check saving a key to an encrypted file without a passphrase fails @@ -1247,14 +1243,14 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) { c.Assert(err, IsNil) privateKey, err = key.MarshalSigner() c.Assert(err, IsNil) - c.Assert(insecureStore.SavePrivateKey("root", privateKey), Equals, ErrPassphraseRequired{"root"}) + c.Assert(insecureStore.SaveSigner("root", key), Equals, ErrPassphraseRequired{"root"}) // save a key to an insecure store and check it is not encrypted key, err = keys.GenerateEd25519Key() c.Assert(err, IsNil) privateKey, err = key.MarshalSigner() c.Assert(err, IsNil) - c.Assert(insecureStore.SavePrivateKey("targets", privateKey), IsNil) + c.Assert(insecureStore.SaveSigner("targets", key), IsNil) assertKeys("targets", false, []*data.PrivateKey{privateKey}) } diff --git a/verify/verify_test.go b/verify/verify_test.go index f136ed54..74eab780 100644 --- a/verify/verify_test.go +++ b/verify/verify_test.go @@ -51,10 +51,6 @@ func (s ecdsaSigner) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([ return s.PrivateKey.Sign(rand, hash[:], crypto.SHA256) } -func (s ecdsaSigner) IDs() []string { - return s.PublicData().IDs() -} - func (s ecdsaSigner) ContainsID(id string) bool { return s.PublicData().ContainsID(id) } From 736fcc61962c9cece79df91d0e8393e351d0fd8f Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Mon, 27 Sep 2021 16:28:19 -0500 Subject: [PATCH 15/17] address comments Signed-off-by: Asra Ali --- client/client.go | 2 +- client/client_test.go | 30 +++---- client/delegations_test.go | 2 +- client/interop_test.go | 4 +- client/python_interop/python_interop_test.go | 4 +- client/testdata/tools/gen-keys.go | 4 +- cmd/tuf-client/init.go | 2 +- data/types.go | 26 +++--- data/types_test.go | 10 +-- local_store.go | 2 +- pkg/keys/ecdsa.go | 6 +- pkg/keys/ed25519.go | 19 ++-- pkg/keys/ed25519_test.go | 12 ++- pkg/keys/keys.go | 33 ++++--- pkg/keys/keys_test.go | 12 +-- pkg/keys/rsa.go | 62 ++++++++++++- pkg/keys/rsa_test.go | 74 ++-------------- repo.go | 8 +- repo_test.go | 92 ++++++++++---------- sign/sign.go | 5 +- verify/db.go | 20 ++--- verify/db_test.go | 4 +- verify/verify.go | 6 +- verify/verify_test.go | 23 +++-- 24 files changed, 226 insertions(+), 236 deletions(-) diff --git a/client/client.go b/client/client.go index e918bdc2..182c0173 100644 --- a/client/client.go +++ b/client/client.go @@ -110,7 +110,7 @@ func NewClient(local LocalStore, remote RemoteStore) *Client { // The latest root.json is fetched from remote storage, verified using rootKeys // and threshold, and then saved in local storage. It is expected that rootKeys // were securely distributed with the software being updated. -func (c *Client) Init(rootKeys []*data.Key, threshold int) error { +func (c *Client) Init(rootKeys []*data.PublicKey, threshold int) error { if len(rootKeys) < threshold { return ErrInsufficientKeys } diff --git a/client/client_test.go b/client/client_test.go index e0420683..cf0013ae 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -173,7 +173,7 @@ func (s *ClientSuite) addRemoteTarget(c *C, name string) { s.syncRemote(c) } -func (s *ClientSuite) rootKeys(c *C) []*data.Key { +func (s *ClientSuite) rootKeys(c *C) []*data.PublicKey { rootKeys, err := s.repo.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) @@ -347,7 +347,7 @@ func (s *ClientSuite) TestNewRoot(c *C) { for _, ids := range s.keyIDs { c.Assert(len(ids) > 0, Equals, true) for _, id := range ids { - _, err := client.db.GetKey(id) + _, err := client.db.GetVerifier(id) c.Assert(err, NotNil) } } @@ -356,9 +356,9 @@ func (s *ClientSuite) TestNewRoot(c *C) { for name, ids := range newKeyIDs { c.Assert(len(ids) > 0, Equals, true) for _, id := range ids { - key, err := client.db.GetKey(id) + verifier, err := client.db.GetVerifier(id) c.Assert(err, IsNil) - c.Assert(key.MarshalKey().IDs(), DeepEquals, ids) + c.Assert(verifier.MarshalPublicKey().IDs(), DeepEquals, ids) } role := client.db.GetRole(name) c.Assert(role, NotNil) @@ -592,13 +592,13 @@ func (s *ClientSuite) TestNewTimestampKey(c *C) { // check key has been replaced in db for _, oldID := range oldIDs { - _, err := client.db.GetKey(oldID) + _, err := client.db.GetVerifier(oldID) c.Assert(err, NotNil) } for _, newID := range newIDs { - key, err := client.db.GetKey(newID) + verifier, err := client.db.GetVerifier(newID) c.Assert(err, IsNil) - c.Assert(key.MarshalKey().IDs(), DeepEquals, newIDs) + c.Assert(verifier.MarshalPublicKey().IDs(), DeepEquals, newIDs) } role := client.db.GetRole("timestamp") c.Assert(role, NotNil) @@ -632,13 +632,13 @@ func (s *ClientSuite) TestNewSnapshotKey(c *C) { // check key has been replaced in db for _, oldID := range oldIDs { - _, err := client.db.GetKey(oldID) + _, err := client.db.GetVerifier(oldID) c.Assert(err, NotNil) } for _, newID := range newIDs { - key, err := client.db.GetKey(newID) + verifier, err := client.db.GetVerifier(newID) c.Assert(err, IsNil) - c.Assert(key.MarshalKey().IDs(), DeepEquals, newIDs) + c.Assert(verifier.MarshalPublicKey().IDs(), DeepEquals, newIDs) } role := client.db.GetRole("snapshot") c.Assert(role, NotNil) @@ -675,13 +675,13 @@ func (s *ClientSuite) TestNewTargetsKey(c *C) { // check key has been replaced in db for _, oldID := range oldIDs { - _, err := client.db.GetKey(oldID) + _, err := client.db.GetVerifier(oldID) c.Assert(err, NotNil) } for _, newID := range newIDs { - key, err := client.db.GetKey(newID) + verifier, err := client.db.GetVerifier(newID) c.Assert(err, IsNil) - c.Assert(key.MarshalKey().IDs(), DeepEquals, newIDs) + c.Assert(verifier.MarshalPublicKey().IDs(), DeepEquals, newIDs) } role := client.db.GetRole("targets") c.Assert(role, NotNil) @@ -1114,10 +1114,10 @@ func (s *ClientSuite) TestUnknownKeyIDs(c *C) { c.Assert(json.Unmarshal(rootJSON, &root), IsNil) // update remote root.json to add a new key with an unknown id - key, err := keys.GenerateEd25519Key() + signer, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - root.Signed.Keys["unknown-key-id"] = key.PublicData() + root.Signed.Keys["unknown-key-id"] = signer.PublicData() // re-sign the root metadata, then commit it back into the store. signingKeys, err := s.store.GetSigners("root") diff --git a/client/delegations_test.go b/client/delegations_test.go index a2f405ce..2397d40a 100644 --- a/client/delegations_test.go +++ b/client/delegations_test.go @@ -271,7 +271,7 @@ func initTestDelegationClient(t *testing.T, dirPrefix string) (*Client, func() e root := &data.Root{} assert.Nil(t, json.Unmarshal(rawFile, s)) assert.Nil(t, json.Unmarshal(s.Signed, root)) - var keys []*data.Key + var keys []*data.PublicKey for _, sig := range s.Signatures { k, ok := root.Keys[sig.KeyID] if ok { diff --git a/client/interop_test.go b/client/interop_test.go index 04c4e5fd..09858ecf 100644 --- a/client/interop_test.go +++ b/client/interop_test.go @@ -188,7 +188,7 @@ func startFileServer(c *C, dir string) (string, func() error) { return addr, l.Close } -func getKeys(c *C, remote RemoteStore) []*data.Key { +func getKeys(c *C, remote RemoteStore) []*data.PublicKey { r, _, err := remote.GetMeta("root.json") c.Assert(err, IsNil) @@ -202,7 +202,7 @@ func getKeys(c *C, remote RemoteStore) []*data.Key { rootRole, exists := root.Signed.Roles["root"] c.Assert(exists, Equals, true) - rootKeys := []*data.Key{} + rootKeys := []*data.PublicKey{} for _, keyID := range rootRole.KeyIDs { key, exists := root.Signed.Keys[keyID] diff --git a/client/python_interop/python_interop_test.go b/client/python_interop/python_interop_test.go index 203e7dce..590f4560 100644 --- a/client/python_interop/python_interop_test.go +++ b/client/python_interop/python_interop_test.go @@ -62,14 +62,14 @@ func (InteropSuite) TestGoClientPythonGenerated(c *C) { // initiate a client with the root keys f, err := os.Open(filepath.Join(testDataDir, dir, "keystore", "root_key.pub")) c.Assert(err, IsNil) - key := &data.Key{} + key := &data.PublicKey{} c.Assert(json.NewDecoder(f).Decode(key), IsNil) c.Assert(key.Type, Equals, "ed25519") pk, err := keys.GetVerifier(key) c.Assert(err, IsNil) c.Assert(pk.Public(), HasLen, ed25519.PublicKeySize) client := client.NewClient(client.MemoryLocalStore(), remote) - c.Assert(client.Init([]*data.Key{key}, 1), IsNil) + c.Assert(client.Init([]*data.PublicKey{key}, 1), IsNil) // check update returns the correct updated targets files, err := client.Update() diff --git a/client/testdata/tools/gen-keys.go b/client/testdata/tools/gen-keys.go index 64838265..896fc01f 100644 --- a/client/testdata/tools/gen-keys.go +++ b/client/testdata/tools/gen-keys.go @@ -29,9 +29,9 @@ func main() { keys := [][]*data.PrivateKey{} for i := 0; i < 2; i++ { - key, err := keys.GenerateEd25519Key() + signer, err := keys.GenerateEd25519Key() assertNotNil(err) - keys = append(keys, []*data.PrivateKey{key}) + keys = append(keys, []*data.PrivateKey{signer}) } roles[name] = keys diff --git a/cmd/tuf-client/init.go b/cmd/tuf-client/init.go index 2ff70f90..6b1296ac 100644 --- a/cmd/tuf-client/init.go +++ b/cmd/tuf-client/init.go @@ -33,7 +33,7 @@ func cmdInit(args *docopt.Args, client *tuf.Client) error { return err } } - var rootKeys []*data.Key + var rootKeys []*data.PublicKey if err := json.NewDecoder(in).Decode(&rootKeys); err != nil { return err } diff --git a/data/types.go b/data/types.go index 2e90da5d..ee9a2878 100644 --- a/data/types.go +++ b/data/types.go @@ -38,7 +38,7 @@ type Signature struct { Signature HexBytes `json:"sig"` } -type Key struct { +type PublicKey struct { Type string `json:"keytype"` Scheme string `json:"scheme"` Algorithms []string `json:"keyid_hash_algorithms,omitempty"` @@ -55,7 +55,7 @@ type PrivateKey struct { Value json.RawMessage `json:"keyval"` } -func (k *Key) IDs() []string { +func (k *PublicKey) IDs() []string { k.idOnce.Do(func() { data, _ := cjson.Marshal(k) digest := sha256.Sum256(data) @@ -64,7 +64,7 @@ func (k *Key) IDs() []string { return k.ids } -func (k *Key) ContainsID(id string) bool { +func (k *PublicKey) ContainsID(id string) bool { for _, keyid := range k.IDs() { if id == keyid { return true @@ -89,12 +89,12 @@ func DefaultExpires(role string) time.Time { } type Root struct { - Type string `json:"_type"` - SpecVersion string `json:"spec_version"` - Version int `json:"version"` - Expires time.Time `json:"expires"` - Keys map[string]*Key `json:"keys"` - Roles map[string]*Role `json:"roles"` + Type string `json:"_type"` + SpecVersion string `json:"spec_version"` + Version int `json:"version"` + Expires time.Time `json:"expires"` + Keys map[string]*PublicKey `json:"keys"` + Roles map[string]*Role `json:"roles"` ConsistentSnapshot bool `json:"consistent_snapshot"` } @@ -104,13 +104,13 @@ func NewRoot() *Root { Type: "root", SpecVersion: "1.0", Expires: DefaultExpires("root"), - Keys: make(map[string]*Key), + Keys: make(map[string]*PublicKey), Roles: make(map[string]*Role), ConsistentSnapshot: true, } } -func (r *Root) AddKey(key *Key) bool { +func (r *Root) AddKey(key *PublicKey) bool { changed := false for _, id := range key.IDs() { if _, ok := r.Keys[id]; !ok { @@ -205,8 +205,8 @@ type Targets struct { // Delegations represents the edges from a parent Targets role to one or more // delegated target roles. See spec v1.0.19 section 4.5. type Delegations struct { - Keys map[string]*Key `json:"keys"` - Roles []DelegatedRole `json:"roles"` + Keys map[string]*PublicKey `json:"keys"` + Roles []DelegatedRole `json:"roles"` } // DelegatedRole describes a delegated role, including what paths it is diff --git a/data/types_test.go b/data/types_test.go index c3f305e0..0c689eb6 100644 --- a/data/types_test.go +++ b/data/types_test.go @@ -34,14 +34,14 @@ func (TypesSuite) TestKeyIDs(c *C) { keyValBytes, err := json.Marshal(ed25519Public{PublicKey: hexbytes}) c.Assert(err, IsNil) - key := Key{ + key := PublicKey{ Type: KeyTypeEd25519, Scheme: KeySchemeEd25519, Value: keyValBytes, } c.Assert(key.IDs(), DeepEquals, []string{keyid10}) - key = Key{ + key = PublicKey{ Type: KeyTypeEd25519, Scheme: KeySchemeEd25519, Algorithms: KeyAlgorithms, @@ -57,7 +57,7 @@ func (TypesSuite) TestRootAddKey(c *C) { keyValBytes, err := json.Marshal(ed25519Public{PublicKey: hexbytes}) c.Assert(err, IsNil) - key := &Key{ + key := &PublicKey{ Type: KeyTypeEd25519, Scheme: KeySchemeEd25519, Value: keyValBytes, @@ -76,7 +76,7 @@ func (TypesSuite) TestRoleAddKeyIDs(c *C) { keyValBytes, err := json.Marshal(ed25519Public{PublicKey: hexbytes}) c.Assert(err, IsNil) - key := &Key{ + key := &PublicKey{ Type: KeyTypeEd25519, Scheme: KeySchemeEd25519, Value: keyValBytes, @@ -93,7 +93,7 @@ func (TypesSuite) TestRoleAddKeyIDs(c *C) { c.Assert(role.KeyIDs, DeepEquals, []string{keyid10}) // Add another key. - key = &Key{ + key = &PublicKey{ Type: KeyTypeEd25519, Scheme: KeySchemeEd25519, Algorithms: KeyAlgorithms, diff --git a/local_store.go b/local_store.go index 554b5199..d2010024 100644 --- a/local_store.go +++ b/local_store.go @@ -341,7 +341,7 @@ func (f *fileSystemStore) SaveSigner(role string, signer keys.Signer) error { if err != nil && !os.IsNotExist(err) { return err } - key, err := signer.MarshalSigner() + key, err := signer.MarshalPrivateKey() if err != nil { return err } diff --git a/pkg/keys/ecdsa.go b/pkg/keys/ecdsa.go index 914496c6..1471235b 100644 --- a/pkg/keys/ecdsa.go +++ b/pkg/keys/ecdsa.go @@ -26,7 +26,7 @@ type ecdsaSignature struct { type p256Verifier struct { PublicKey data.HexBytes `json:"public"` - key *data.Key + key *data.PublicKey } func (p *p256Verifier) Public() string { @@ -54,11 +54,11 @@ func (p *p256Verifier) Verify(msg, sigBytes []byte) error { return nil } -func (p *p256Verifier) MarshalKey() *data.Key { +func (p *p256Verifier) MarshalPublicKey() *data.PublicKey { return p.key } -func (p *p256Verifier) UnmarshalKey(key *data.Key) error { +func (p *p256Verifier) UnmarshalPublicKey(key *data.PublicKey) error { if err := json.Unmarshal(key.Value, p); err != nil { return err } diff --git a/pkg/keys/ed25519.go b/pkg/keys/ed25519.go index 1b7fdc14..65be3409 100644 --- a/pkg/keys/ed25519.go +++ b/pkg/keys/ed25519.go @@ -1,6 +1,7 @@ package keys import ( + "crypto" "crypto/ed25519" "crypto/rand" "encoding/json" @@ -24,7 +25,7 @@ func NewP256Verifier() Verifier { type ed25519Verifier struct { PublicKey data.HexBytes `json:"public"` - key *data.Key + key *data.PublicKey } func (e *ed25519Verifier) Public() string { @@ -38,11 +39,11 @@ func (e *ed25519Verifier) Verify(msg, sig []byte) error { return nil } -func (e *ed25519Verifier) MarshalKey() *data.Key { +func (e *ed25519Verifier) MarshalPublicKey() *data.PublicKey { return e.key } -func (e *ed25519Verifier) UnmarshalKey(key *data.Key) error { +func (e *ed25519Verifier) UnmarshalPublicKey(key *data.PublicKey) error { e.key = key if err := json.Unmarshal(key.Value, e); err != nil { return err @@ -82,7 +83,11 @@ func GenerateEd25519Key() (*ed25519Signer, error) { }, nil } -func (e *ed25519Signer) MarshalSigner() (*data.PrivateKey, error) { +func (e *ed25519Signer) SignMessage(message []byte) ([]byte, error) { + return e.Sign(rand.Reader, message, crypto.Hash(0)) +} + +func (e *ed25519Signer) MarshalPrivateKey() (*data.PrivateKey, error) { valueBytes, err := json.Marshal(ed25519PrivateKeyValue{ Public: data.HexBytes([]byte(e.PrivateKey.Public().(ed25519.PublicKey))), Private: data.HexBytes(e.PrivateKey), @@ -98,7 +103,7 @@ func (e *ed25519Signer) MarshalSigner() (*data.PrivateKey, error) { }, nil } -func (e *ed25519Signer) UnmarshalSigner(key *data.PrivateKey) error { +func (e *ed25519Signer) UnmarshalPrivateKey(key *data.PrivateKey) error { keyValue := &ed25519PrivateKeyValue{} if err := json.Unmarshal(key.Value, keyValue); err != nil { return err @@ -112,9 +117,9 @@ func (e *ed25519Signer) UnmarshalSigner(key *data.PrivateKey) error { return nil } -func (e *ed25519Signer) PublicData() *data.Key { +func (e *ed25519Signer) PublicData() *data.PublicKey { keyValBytes, _ := json.Marshal(ed25519Verifier{PublicKey: []byte(e.PrivateKey.Public().(ed25519.PublicKey))}) - return &data.Key{ + return &data.PublicKey{ Type: e.keyType, Scheme: e.keyScheme, Algorithms: e.keyAlgorithms, diff --git a/pkg/keys/ed25519_test.go b/pkg/keys/ed25519_test.go index 9b12cdfc..3aeb77f2 100644 --- a/pkg/keys/ed25519_test.go +++ b/pkg/keys/ed25519_test.go @@ -1,8 +1,6 @@ package keys import ( - "crypto" - "crypto/rand" "encoding/json" "github.com/theupdateframework/go-tuf/data" @@ -15,23 +13,23 @@ var _ = Suite(&Ed25519Suite{}) func (Ed25519Suite) TestUnmarshalEd25519(c *C) { badKeyValue, _ := json.Marshal(true) - badKey := &data.Key{ + badKey := &data.PublicKey{ Type: data.KeyTypeRSASSA_PSS_SHA256, Scheme: data.KeySchemeRSASSA_PSS_SHA256, Algorithms: data.KeyAlgorithms, Value: badKeyValue, } verifier := NewP256Verifier() - c.Assert(verifier.UnmarshalKey(badKey), ErrorMatches, "json: cannot unmarshal.*") + c.Assert(verifier.UnmarshalPublicKey(badKey), ErrorMatches, "json: cannot unmarshal.*") } func (Ed25519Suite) TestSignVerify(c *C) { - key, err := GenerateEd25519Key() + signer, err := GenerateEd25519Key() c.Assert(err, IsNil) msg := []byte("foo") - sig, err := key.Sign(rand.Reader, msg, crypto.Hash(0)) + sig, err := signer.SignMessage(msg) c.Assert(err, IsNil) - publicData := key.PublicData() + publicData := signer.PublicData() pubKey, err := GetVerifier(publicData) c.Assert(err, IsNil) c.Assert(pubKey.Verify(msg, sig), IsNil) diff --git a/pkg/keys/keys.go b/pkg/keys/keys.go index 347e7ffe..7fa9f416 100644 --- a/pkg/keys/keys.go +++ b/pkg/keys/keys.go @@ -1,7 +1,6 @@ package keys import ( - "crypto" "sync" "github.com/pkg/errors" @@ -21,13 +20,13 @@ var ( // A Verifier verifies public key signatures. type Verifier interface { - // UnmarshalKey takes key data to a working verifier implementation for the key type. - // This performs any validation over the data.Key to ensure that the verifier is usable + // UnmarshalPublicKey takes key data to a working verifier implementation for the key type. + // This performs any validation over the data.PublicKey to ensure that the verifier is usable // to verify signatures. - UnmarshalKey(key *data.Key) error + UnmarshalPublicKey(key *data.PublicKey) error - // MarshalKey returns the data.Key object associated with the verifier. - MarshalKey() *data.Key + // MarshalPublicKey returns the data.PublicKey object associated with the verifier. + MarshalPublicKey() *data.PublicKey // This is the public string used as a unique identifier for the verifier instance. Public() string @@ -39,28 +38,28 @@ type Verifier interface { } type Signer interface { - // MarshalSigner returns the private key data. - MarshalSigner() (*data.PrivateKey, error) + // MarshalPrivateKey returns the private key data. + MarshalPrivateKey() (*data.PrivateKey, error) - // UnmarshalSigner takes private key data to a working Signer implementation for the key type. - UnmarshalSigner(key *data.PrivateKey) error + // UnmarshalPrivateKey takes private key data to a working Signer implementation for the key type. + UnmarshalPrivateKey(key *data.PrivateKey) error - // Returns the public data.Key from the private key - PublicData() *data.Key + // Returns the public data.PublicKey from the private key + PublicData() *data.PublicKey - // Signer is used to sign messages and provides access to the public key. + // Sign returns the signature of the message. // The signer is expected to do its own hashing, so the full message will be // provided as the message to Sign with a zero opts.HashFunc(). - crypto.Signer + SignMessage(message []byte) ([]byte, error) } -func GetVerifier(key *data.Key) (Verifier, error) { +func GetVerifier(key *data.PublicKey) (Verifier, error) { st, ok := VerifierMap.Load(key.Type) if !ok { return nil, ErrInvalidKey } s := st.(func() Verifier)() - if err := s.UnmarshalKey(key); err != nil { + if err := s.UnmarshalPublicKey(key); err != nil { return nil, errors.Wrap(err, "tuf: error unmarshalling key") } return s, nil @@ -72,7 +71,7 @@ func GetSigner(key *data.PrivateKey) (Signer, error) { return nil, ErrInvalidKey } s := st.(func() Signer)() - if err := s.UnmarshalSigner(key); err != nil { + if err := s.UnmarshalPrivateKey(key); err != nil { return nil, errors.Wrap(err, "tuf: error unmarshalling key") } return s, nil diff --git a/pkg/keys/keys_test.go b/pkg/keys/keys_test.go index fe42e076..956a318e 100644 --- a/pkg/keys/keys_test.go +++ b/pkg/keys/keys_test.go @@ -18,21 +18,21 @@ func (KeysSuite) TestSignerKeyIDs(c *C) { c.Assert(err, IsNil) // If we have a TUF-0.9 key, we won't have a scheme. - key, err := GenerateEd25519Key() + signer, err := GenerateEd25519Key() c.Assert(err, IsNil) - privKey, err := key.MarshalSigner() + privKey, err := signer.MarshalPrivateKey() c.Assert(err, IsNil) privKey.Scheme = "" - err = key.UnmarshalSigner(privKey) + err = signer.UnmarshalPrivateKey(privKey) c.Assert(err, IsNil) // Make sure we preserve ids if we don't have any // keyid_hash_algorithms. - key, err = GenerateEd25519Key() + signer, err = GenerateEd25519Key() c.Assert(err, IsNil) - privKey, err = key.MarshalSigner() + privKey, err = signer.MarshalPrivateKey() c.Assert(err, IsNil) privKey.Algorithms = []string{} - err = key.UnmarshalSigner(privKey) + err = signer.UnmarshalPrivateKey(privKey) c.Assert(err, IsNil) } diff --git a/pkg/keys/rsa.go b/pkg/keys/rsa.go index 846ed71a..f47a36df 100644 --- a/pkg/keys/rsa.go +++ b/pkg/keys/rsa.go @@ -2,6 +2,7 @@ package keys import ( "crypto" + "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" @@ -15,16 +16,21 @@ import ( func init() { VerifierMap.Store(data.KeyTypeRSASSA_PSS_SHA256, NewRsaVerifier) + SignerMap.Store(data.KeyTypeRSASSA_PSS_SHA256, NewRsaSigner) } func NewRsaVerifier() Verifier { return &rsaVerifier{} } +func NewRsaSigner() Signer { + return &rsaSigner{} +} + type rsaVerifier struct { PublicKey string `json:"public"` rsaKey *rsa.PublicKey - key *data.Key + key *data.PublicKey } func (p *rsaVerifier) Public() string { @@ -44,11 +50,11 @@ func (p *rsaVerifier) Verify(msg, sigBytes []byte) error { return rsa.VerifyPSS(p.rsaKey, crypto.SHA256, hash[:], sigBytes, &rsa.PSSOptions{}) } -func (p *rsaVerifier) MarshalKey() *data.Key { +func (p *rsaVerifier) MarshalPublicKey() *data.PublicKey { return p.key } -func (p *rsaVerifier) UnmarshalKey(key *data.Key) error { +func (p *rsaVerifier) UnmarshalPublicKey(key *data.PublicKey) error { if err := json.Unmarshal(key.Value, p); err != nil { return err } @@ -81,3 +87,53 @@ func parseKey(data string) (*rsa.PublicKey, error) { } return nil, errors.New("tuf: error unmarshalling rsa key") } + +type rsaSigner struct { + *rsa.PrivateKey +} + +type rsaPublic struct { + // PEM encoded public key. + PublicKey string `json:"public"` +} + +func (s *rsaSigner) PublicData() *data.PublicKey { + pub, _ := x509.MarshalPKIXPublicKey(s.Public().(*rsa.PublicKey)) + pubBytes := pem.EncodeToMemory(&pem.Block{ + Type: "RSA PUBLIC KEY", + Bytes: pub, + }) + + keyValBytes, _ := json.Marshal(rsaPublic{PublicKey: string(pubBytes)}) + return &data.PublicKey{ + Type: data.KeyTypeRSASSA_PSS_SHA256, + Scheme: data.KeySchemeRSASSA_PSS_SHA256, + Algorithms: data.KeyAlgorithms, + Value: keyValBytes, + } +} + +func (s *rsaSigner) SignMessage(message []byte) ([]byte, error) { + hash := sha256.Sum256(message) + return rsa.SignPSS(rand.Reader, s.PrivateKey, crypto.SHA256, hash[:], &rsa.PSSOptions{}) +} + +func (s *rsaSigner) ContainsID(id string) bool { + return s.PublicData().ContainsID(id) +} + +func (s *rsaSigner) MarshalPrivateKey() (*data.PrivateKey, error) { + return nil, errors.New("not implemented for test") +} + +func (s *rsaSigner) UnmarshalPrivateKey(key *data.PrivateKey) error { + return errors.New("not implemented for test") +} + +func GenerateRsaKey() (*rsaSigner, error) { + privkey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, err + } + return &rsaSigner{privkey}, nil +} diff --git a/pkg/keys/rsa_test.go b/pkg/keys/rsa_test.go index 41037e5f..d0e3e862 100644 --- a/pkg/keys/rsa_test.go +++ b/pkg/keys/rsa_test.go @@ -1,92 +1,30 @@ package keys import ( - "crypto" - "crypto/rand" - "crypto/rsa" - "crypto/sha256" - "crypto/x509" - "encoding/json" - "encoding/pem" - "errors" - "io" - . "gopkg.in/check.v1" - - "github.com/theupdateframework/go-tuf/data" ) -type rsaSigner struct { - *rsa.PrivateKey -} - -type rsaPublic struct { - // PEM encoded public key. - PublicKey string `json:"public"` -} - -func (s rsaSigner) PublicData() *data.Key { - pub, _ := x509.MarshalPKIXPublicKey(s.Public().(*rsa.PublicKey)) - pubBytes := pem.EncodeToMemory(&pem.Block{ - Type: "RSA PUBLIC KEY", - Bytes: pub, - }) - - keyValBytes, _ := json.Marshal(rsaPublic{PublicKey: string(pubBytes)}) - return &data.Key{ - Type: data.KeyTypeRSASSA_PSS_SHA256, - Scheme: data.KeySchemeRSASSA_PSS_SHA256, - Algorithms: data.KeyAlgorithms, - Value: keyValBytes, - } -} - -func (s rsaSigner) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { - hash := sha256.Sum256(msg) - return rsa.SignPSS(rand, s.PrivateKey, crypto.SHA256, hash[:], &rsa.PSSOptions{}) -} - -func (s rsaSigner) ContainsID(id string) bool { - return s.PublicData().ContainsID(id) -} - -func (rsaSigner) MarshalSigner() (*data.PrivateKey, error) { - return nil, errors.New("not implemented for test") -} - -func (rsaSigner) UnmarshalSigner(key *data.PrivateKey) error { - return errors.New("not implemented for test") -} - -func GenerateRsaKey() (*rsaSigner, error) { - privkey, err := rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - return nil, err - } - return &rsaSigner{privkey}, nil -} - type RsaSuite struct{} var _ = Suite(&RsaSuite{}) func (RsaSuite) TestSignVerify(c *C) { - key, err := GenerateRsaKey() + signer, err := GenerateRsaKey() c.Assert(err, IsNil) msg := []byte("foo") - sig, err := key.Sign(rand.Reader, msg, crypto.Hash(0)) + sig, err := signer.SignMessage(msg) c.Assert(err, IsNil) - publicData := key.PublicData() + publicData := signer.PublicData() pubKey, err := GetVerifier(publicData) c.Assert(err, IsNil) c.Assert(pubKey.Verify(msg, sig), IsNil) } func (RsaSuite) TestMarshalUnmarshal(c *C) { - key, err := GenerateRsaKey() + signer, err := GenerateRsaKey() c.Assert(err, IsNil) - publicData := key.PublicData() + publicData := signer.PublicData() pubKey, err := GetVerifier(publicData) c.Assert(err, IsNil) - c.Assert(pubKey.MarshalKey(), DeepEquals, publicData) + c.Assert(pubKey.MarshalPublicKey(), DeepEquals, publicData) } diff --git a/repo.go b/repo.go index c3cc4544..f5541244 100644 --- a/repo.go +++ b/repo.go @@ -348,11 +348,11 @@ func (r *Repo) AddPrivateKeyWithExpires(keyRole string, signer keys.Signer, expi return nil } -func (r *Repo) AddVerificationKey(keyRole string, pk *data.Key) error { +func (r *Repo) AddVerificationKey(keyRole string, pk *data.PublicKey) error { return r.AddVerificationKeyWithExpiration(keyRole, pk, data.DefaultExpires(keyRole)) } -func (r *Repo) AddVerificationKeyWithExpiration(keyRole string, pk *data.Key, expires time.Time) error { +func (r *Repo) AddVerificationKeyWithExpiration(keyRole string, pk *data.PublicKey, expires time.Time) error { root, err := r.root() if err != nil { return err @@ -389,7 +389,7 @@ func validExpires(expires time.Time) bool { return expires.Sub(time.Now()) > 0 } -func (r *Repo) RootKeys() ([]*data.Key, error) { +func (r *Repo) RootKeys() ([]*data.PublicKey, error) { root, err := r.root() if err != nil { return nil, err @@ -402,7 +402,7 @@ func (r *Repo) RootKeys() ([]*data.Key, error) { // We might have multiple key ids that correspond to the same key, so // make sure we only return unique keys. seen := make(map[string]struct{}) - rootKeys := []*data.Key{} + rootKeys := []*data.PublicKey{} for _, id := range role.KeyIDs { key, ok := root.Keys[id] if !ok { diff --git a/repo_test.go b/repo_test.go index 70f0abac..a48f59fb 100644 --- a/repo_test.go +++ b/repo_test.go @@ -41,11 +41,11 @@ func (RepoSuite) TestNewRepoIndent(c *C) { // UniqueKeys returns the unique keys for each associated role. // We might have multiple key IDs that correspond to the same key. -func UniqueKeys(r *data.Root) map[string][]*data.Key { - keysByRole := make(map[string][]*data.Key) +func UniqueKeys(r *data.Root) map[string][]*data.PublicKey { + keysByRole := make(map[string][]*data.PublicKey) for name, role := range r.Roles { seen := make(map[string]struct{}) - roleKeys := []*data.Key{} + roleKeys := []*data.PublicKey{} for _, id := range role.KeyIDs { // Double-check that there is actually a key with that ID. if key, ok := r.Keys[id]; ok { @@ -211,9 +211,9 @@ func (rs *RepoSuite) TestGenKey(c *C) { db, err := r.db() c.Assert(err, IsNil) for _, keyID := range ids { - rootKey, err := db.GetKey(keyID) + rootKey, err := db.GetVerifier(keyID) c.Assert(err, IsNil) - c.Assert(rootKey.MarshalKey().IDs(), DeepEquals, ids) + c.Assert(rootKey.MarshalPublicKey().IDs(), DeepEquals, ids) role := db.GetRole("root") c.Assert(role.KeyIDs, DeepEquals, util.StringSliceToSet(ids)) @@ -227,13 +227,13 @@ func (rs *RepoSuite) TestGenKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalKey().IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalPublicKey().IDs()) pk, err := keys.GetVerifier(rootKeys[0]) c.Assert(err, IsNil) c.Assert(pk.Public(), DeepEquals, rootKey.Public()) } - rootKey, err := db.GetKey(ids[0]) + rootKey, err := db.GetVerifier(ids[0]) c.Assert(err, IsNil) // generate two targets keys @@ -260,9 +260,9 @@ func (rs *RepoSuite) TestGenKey(c *C) { if !ok { c.Fatal("missing key") } - key, err := db.GetKey(id) + verifier, err := db.GetVerifier(id) c.Assert(err, IsNil) - c.Assert(key.MarshalKey().ContainsID(id), Equals, true) + c.Assert(verifier.MarshalPublicKey().ContainsID(id), Equals, true) } role := db.GetRole("targets") c.Assert(role.KeyIDs, DeepEquals, targetKeyIDs) @@ -271,7 +271,7 @@ func (rs *RepoSuite) TestGenKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalKey().IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalPublicKey().IDs()) // check the keys were saved correctly localKeys, err := local.GetSigners("targets") @@ -327,9 +327,9 @@ func addPrivateKey(c *C, r *Repo, role string, key keys.Signer) []string { } func generateAndAddPrivateKey(c *C, r *Repo, role string) []string { - key, err := keys.GenerateEd25519Key() + signer, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - return addPrivateKey(c, r, role, key) + return addPrivateKey(c, r, role, signer) } func (rs *RepoSuite) TestAddPrivateKey(c *C) { @@ -338,13 +338,13 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { c.Assert(err, IsNil) // generate a key for an unknown role - key, err := keys.GenerateEd25519Key() + signer, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - err = r.AddPrivateKey("foo", key) + err = r.AddPrivateKey("foo", signer) c.Assert(err, Equals, ErrInvalidRole{"foo"}) // add a root key - ids := addPrivateKey(c, r, "root", key) + ids := addPrivateKey(c, r, "root", signer) // check root metadata is correct root, err := r.root() @@ -374,9 +374,9 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { db, err := r.db() c.Assert(err, IsNil) for _, keyID := range ids { - rootKey, err := db.GetKey(keyID) + rootKey, err := db.GetVerifier(keyID) c.Assert(err, IsNil) - c.Assert(rootKey.MarshalKey().IDs(), DeepEquals, ids) + c.Assert(rootKey.MarshalPublicKey().IDs(), DeepEquals, ids) role := db.GetRole("root") c.Assert(role.KeyIDs, DeepEquals, util.StringSliceToSet(ids)) @@ -390,13 +390,13 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalKey().IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalPublicKey().IDs()) pk, err := keys.GetVerifier(rootKeys[0]) c.Assert(err, IsNil) c.Assert(pk.Public(), DeepEquals, rootKey.Public()) } - rootKey, err := db.GetKey(ids[0]) + rootKey, err := db.GetVerifier(ids[0]) c.Assert(err, IsNil) // generate two targets keys @@ -423,9 +423,9 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { if !ok { c.Fatal("missing key") } - key, err := db.GetKey(id) + verifier, err := db.GetVerifier(id) c.Assert(err, IsNil) - c.Assert(key.MarshalKey().ContainsID(id), Equals, true) + c.Assert(verifier.MarshalPublicKey().ContainsID(id), Equals, true) } role := db.GetRole("targets") c.Assert(role.KeyIDs, DeepEquals, targetKeyIDs) @@ -434,7 +434,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { rootKeys, err := r.RootKeys() c.Assert(err, IsNil) c.Assert(rootKeys, HasLen, 1) - c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalKey().IDs()) + c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalPublicKey().IDs()) // check the keys were saved correctly localKeys, err := local.GetSigners("targets") @@ -491,7 +491,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) { // add the same root key to make sure the metadata is unmodified. oldRoot, err := r.root() c.Assert(err, IsNil) - addPrivateKey(c, r, "root", key) + addPrivateKey(c, r, "root", signer) newRoot, err := r.root() c.Assert(err, IsNil) c.Assert(oldRoot, DeepEquals, newRoot) @@ -584,22 +584,22 @@ func (rs *RepoSuite) TestSign(c *C) { } // signing with an available key generates a signature - key, err := keys.GenerateEd25519Key() + signer, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - c.Assert(local.SaveSigner("root", key), IsNil) + c.Assert(local.SaveSigner("root", signer), IsNil) c.Assert(r.Sign("root.json"), IsNil) - checkSigIDs(key.PublicData().IDs()...) + checkSigIDs(signer.PublicData().IDs()...) // signing again does not generate a duplicate signature c.Assert(r.Sign("root.json"), IsNil) - checkSigIDs(key.PublicData().IDs()...) + checkSigIDs(signer.PublicData().IDs()...) // signing with a new available key generates another signature newKey, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) c.Assert(local.SaveSigner("root", newKey), IsNil) c.Assert(r.Sign("root.json"), IsNil) - checkSigIDs(append(key.PublicData().IDs(), newKey.PublicData().IDs()...)...) + checkSigIDs(append(signer.PublicData().IDs(), newKey.PublicData().IDs()...)...) } func (rs *RepoSuite) TestCommit(c *C) { @@ -1222,35 +1222,33 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) { } // save a key and check it gets encrypted - key, err := keys.GenerateEd25519Key() + signer, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - privateKey, err := key.MarshalSigner() + privateKey, err := signer.MarshalPrivateKey() c.Assert(err, IsNil) - c.Assert(store.SaveSigner("root", key), IsNil) + c.Assert(store.SaveSigner("root", signer), IsNil) assertKeys("root", true, []*data.PrivateKey{privateKey}) // save another key and check it gets added to the existing keys newKey, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) - newPrivateKey, err := newKey.MarshalSigner() + newPrivateKey, err := newKey.MarshalPrivateKey() c.Assert(err, IsNil) c.Assert(store.SaveSigner("root", newKey), IsNil) assertKeys("root", true, []*data.PrivateKey{privateKey, newPrivateKey}) // check saving a key to an encrypted file without a passphrase fails insecureStore := FileSystemStore(tmp.path, nil) - key, err = keys.GenerateEd25519Key() + signer, err = keys.GenerateEd25519Key() c.Assert(err, IsNil) - privateKey, err = key.MarshalSigner() - c.Assert(err, IsNil) - c.Assert(insecureStore.SaveSigner("root", key), Equals, ErrPassphraseRequired{"root"}) + c.Assert(insecureStore.SaveSigner("root", signer), Equals, ErrPassphraseRequired{"root"}) // save a key to an insecure store and check it is not encrypted - key, err = keys.GenerateEd25519Key() + signer, err = keys.GenerateEd25519Key() c.Assert(err, IsNil) - privateKey, err = key.MarshalSigner() + privateKey, err = signer.MarshalPrivateKey() c.Assert(err, IsNil) - c.Assert(insecureStore.SaveSigner("targets", key), IsNil) + c.Assert(insecureStore.SaveSigner("targets", signer), IsNil) assertKeys("targets", false, []*data.PrivateKey{privateKey}) } @@ -1367,14 +1365,14 @@ func (rs *RepoSuite) TestUnknownKeyIDs(c *C) { genKey(c, r, "timestamp") // add a new key to the root metadata with an unknown key id. - key, err := keys.GenerateEd25519Key() + signer, err := keys.GenerateEd25519Key() c.Assert(err, IsNil) root, err := r.root() c.Assert(err, IsNil) c.Assert(root.Version, Equals, 1) - root.Keys["unknown-key-id"] = key.PublicData() + root.Keys["unknown-key-id"] = signer.PublicData() r.setMeta("root.json", root) // commit the metadata to the store. @@ -1400,7 +1398,7 @@ func (rs *RepoSuite) TestUnknownKeyIDs(c *C) { unknownKey, ok := signedRoot.Signed.Keys["unknown-key-id"] c.Assert(ok, Equals, true) - c.Assert(unknownKey, DeepEquals, key.PublicData()) + c.Assert(unknownKey, DeepEquals, signer.PublicData()) // a new root should preserve the unknown key id. root, err = r.root() @@ -1421,7 +1419,7 @@ func (rs *RepoSuite) TestUnknownKeyIDs(c *C) { unknownKey, ok = signedRoot.Signed.Keys["unknown-key-id"] c.Assert(ok, Equals, true) - c.Assert(unknownKey, DeepEquals, key.PublicData()) + c.Assert(unknownKey, DeepEquals, signer.PublicData()) } func (rs *RepoSuite) TestThreshold(c *C) { @@ -1502,7 +1500,7 @@ func (rs *RepoSuite) TestAddOrUpdateSignatures(c *C) { // generate signatures externally and append rootMeta, err := r.SignedMeta("root.json") c.Assert(err, IsNil) - rootSig, err := rootKey.Sign(rand.Reader, rootMeta.Signed, crypto.Hash(0)) + rootSig, err := rootKey.SignMessage(rootMeta.Signed) c.Assert(err, IsNil) for _, id := range rootKey.PublicData().IDs() { c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{ @@ -1514,7 +1512,7 @@ func (rs *RepoSuite) TestAddOrUpdateSignatures(c *C) { c.Assert(r.AddTarget("foo.txt", nil), IsNil) targetsMeta, err := r.SignedMeta("targets.json") c.Assert(err, IsNil) - targetsSig, err := targetsKey.Sign(rand.Reader, targetsMeta.Signed, crypto.Hash(0)) + targetsSig, err := targetsKey.SignMessage(targetsMeta.Signed) c.Assert(err, IsNil) for _, id := range targetsKey.PublicData().IDs() { r.AddOrUpdateSignature("targets.json", data.Signature{ @@ -1526,7 +1524,7 @@ func (rs *RepoSuite) TestAddOrUpdateSignatures(c *C) { c.Assert(r.Snapshot(), IsNil) snapshotMeta, err := r.SignedMeta("snapshot.json") c.Assert(err, IsNil) - snapshotSig, err := snapshotKey.Sign(rand.Reader, snapshotMeta.Signed, crypto.Hash(0)) + snapshotSig, err := snapshotKey.SignMessage(snapshotMeta.Signed) c.Assert(err, IsNil) for _, id := range snapshotKey.PublicData().IDs() { r.AddOrUpdateSignature("snapshot.json", data.Signature{ @@ -1537,7 +1535,7 @@ func (rs *RepoSuite) TestAddOrUpdateSignatures(c *C) { c.Assert(r.Timestamp(), IsNil) timestampMeta, err := r.SignedMeta("timestamp.json") c.Assert(err, IsNil) - timestampSig, err := timestampKey.Sign(rand.Reader, timestampMeta.Signed, crypto.Hash(0)) + timestampSig, err := timestampKey.SignMessage(timestampMeta.Signed) c.Assert(err, IsNil) for _, id := range timestampKey.PublicData().IDs() { r.AddOrUpdateSignature("timestamp.json", data.Signature{ diff --git a/sign/sign.go b/sign/sign.go index 9ee19ce3..3dd81267 100644 --- a/sign/sign.go +++ b/sign/sign.go @@ -1,9 +1,6 @@ package sign import ( - "crypto" - "crypto/rand" - cjson "github.com/tent/canonical-json-go" "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/pkg/keys" @@ -25,7 +22,7 @@ func Sign(s *data.Signed, k keys.Signer) error { } } - sig, err := k.Sign(rand.Reader, s.Signed, crypto.Hash(0)) + sig, err := k.SignMessage(s.Signed) if err != nil { return err } diff --git a/verify/db.go b/verify/db.go index 70f0b44a..0684e6a8 100644 --- a/verify/db.go +++ b/verify/db.go @@ -16,14 +16,14 @@ func (r *Role) ValidKey(id string) bool { } type DB struct { - roles map[string]*Role - keys map[string]keys.Verifier + roles map[string]*Role + verifiers map[string]keys.Verifier } func NewDB() *DB { return &DB{ - roles: make(map[string]*Role), - keys: make(map[string]keys.Verifier), + roles: make(map[string]*Role), + verifiers: make(map[string]keys.Verifier), } } @@ -40,8 +40,8 @@ func (d *DelegationsVerifier) Unmarshal(b []byte, v interface{}, role string, mi // unmarshals. func NewDelegationsVerifier(d *data.Delegations) (DelegationsVerifier, error) { db := &DB{ - roles: make(map[string]*Role, len(d.Roles)), - keys: make(map[string]keys.Verifier, len(d.Keys)), + roles: make(map[string]*Role, len(d.Roles)), + verifiers: make(map[string]keys.Verifier, len(d.Keys)), } for _, r := range d.Roles { if _, ok := topLevelRoles[r.Name]; ok { @@ -60,7 +60,7 @@ func NewDelegationsVerifier(d *data.Delegations) (DelegationsVerifier, error) { return DelegationsVerifier{db}, nil } -func (db *DB) AddKey(id string, k *data.Key) error { +func (db *DB) AddKey(id string, k *data.PublicKey) error { if !k.ContainsID(id) { return ErrWrongID{} } @@ -68,7 +68,7 @@ func (db *DB) AddKey(id string, k *data.Key) error { if err != nil { return ErrInvalidKey } - db.keys[id] = verifier + db.verifiers[id] = verifier return nil } @@ -116,8 +116,8 @@ func (db *DB) addRole(name string, r *data.Role) error { return nil } -func (db *DB) GetKey(id string) (keys.Verifier, error) { - k, ok := db.keys[id] +func (db *DB) GetVerifier(id string) (keys.Verifier, error) { + k, ok := db.verifiers[id] if !ok { return nil, ErrMissingKey } diff --git a/verify/db_test.go b/verify/db_test.go index 8921993d..cb328981 100644 --- a/verify/db_test.go +++ b/verify/db_test.go @@ -35,8 +35,8 @@ func TestDelegationsVerifier(t *testing.T) { }, { testName: "invalid keys", - delegations: &data.Delegations{Keys: map[string]*data.Key{ - "a": &data.Key{Type: data.KeySchemeEd25519}, + delegations: &data.Delegations{Keys: map[string]*data.PublicKey{ + "a": &data.PublicKey{Type: data.KeySchemeEd25519}, }}, initErr: ErrWrongID{}, }, diff --git a/verify/verify.go b/verify/verify.go index ca9ebae3..c0b6a037 100644 --- a/verify/verify.go +++ b/verify/verify.go @@ -97,19 +97,19 @@ func (db *DB) VerifySignatures(s *data.Signed, role string) error { if !roleData.ValidKey(sig.KeyID) { continue } - key, err := db.GetKey(sig.KeyID) + verifier, err := db.GetVerifier(sig.KeyID) if err != nil { continue } - if err := key.Verify(msg, sig.Signature); err != nil { + if err := verifier.Verify(msg, sig.Signature); err != nil { return ErrInvalid } // Only consider this key valid if we haven't seen any of it's // key ids before. if _, ok := seen[sig.KeyID]; !ok { - for _, id := range key.MarshalKey().IDs() { + for _, id := range verifier.MarshalPublicKey().IDs() { seen[id] = struct{}{} } diff --git a/verify/verify_test.go b/verify/verify_test.go index 74eab780..34e146fe 100644 --- a/verify/verify_test.go +++ b/verify/verify_test.go @@ -8,7 +8,6 @@ import ( "crypto/sha256" "encoding/json" "errors" - "io" "testing" "time" @@ -35,10 +34,10 @@ type ecdsaPublic struct { PublicKey data.HexBytes `json:"public"` } -func (s ecdsaSigner) PublicData() *data.Key { +func (s ecdsaSigner) PublicData() *data.PublicKey { pub := s.Public().(*ecdsa.PublicKey) keyValBytes, _ := json.Marshal(ecdsaPublic{PublicKey: elliptic.Marshal(pub.Curve, pub.X, pub.Y)}) - return &data.Key{ + return &data.PublicKey{ Type: data.KeyTypeECDSA_SHA2_P256, Scheme: data.KeySchemeECDSA_SHA2_P256, Algorithms: data.KeyAlgorithms, @@ -46,27 +45,27 @@ func (s ecdsaSigner) PublicData() *data.Key { } } -func (s ecdsaSigner) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { - hash := sha256.Sum256(msg) - return s.PrivateKey.Sign(rand, hash[:], crypto.SHA256) +func (s ecdsaSigner) SignMessage(message []byte) ([]byte, error) { + hash := sha256.Sum256(message) + return s.PrivateKey.Sign(rand.Reader, hash[:], crypto.SHA256) } func (s ecdsaSigner) ContainsID(id string) bool { return s.PublicData().ContainsID(id) } -func (ecdsaSigner) MarshalSigner() (*data.PrivateKey, error) { +func (ecdsaSigner) MarshalPrivateKey() (*data.PrivateKey, error) { return nil, errors.New("not implemented for test") } -func (ecdsaSigner) UnmarshalSigner(key *data.PrivateKey) error { +func (ecdsaSigner) UnmarshalPrivateKey(key *data.PrivateKey) error { return errors.New("not implemented for test") } func (VerifySuite) Test(c *C) { type test struct { name string - keys []*data.Key + keys []*data.PublicKey roles map[string]*data.Role s *data.Signed ver int @@ -186,7 +185,7 @@ func (VerifySuite) Test(c *C) { s := ecdsaSigner{k} sign.Sign(t.s, s) t.s.Signatures = t.s.Signatures[1:] - t.keys = []*data.Key{s.PublicData()} + t.keys = []*data.PublicKey{s.PublicData()} t.roles["root"].KeyIDs = s.PublicData().IDs() }, }, @@ -220,7 +219,7 @@ func (VerifySuite) Test(c *C) { if t.keys == nil && t.s == nil { k, _ := keys.GenerateEd25519Key() t.s, _ = sign.Marshal(&signedMeta{Type: t.typ, Version: t.ver, Expires: *t.exp}, k) - t.keys = []*data.Key{k.PublicData()} + t.keys = []*data.PublicKey{k.PublicData()} } if t.roles == nil { t.roles = map[string]*data.Role{ @@ -260,7 +259,7 @@ func (VerifySuite) TestVerifyIgnoreExpired(c *C) { role := "root" k, _ := keys.GenerateEd25519Key() s, _ := sign.Marshal(&signedMeta{Type: role, Version: minVer, Expires: time.Now().Add(-time.Hour)}, k) - keys := []*data.Key{k.PublicData()} + keys := []*data.PublicKey{k.PublicData()} roles := map[string]*data.Role{ "root": { KeyIDs: keys[0].IDs(), From 8e037e9e0788300a8ab44c8a9ac7da7af07515e0 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Tue, 28 Sep 2021 10:26:11 -0500 Subject: [PATCH 16/17] address comments Signed-off-by: Asra Ali --- data/types.go | 2 +- data/types_test.go | 4 ++-- local_store.go | 6 +++--- pkg/keys/ed25519.go | 2 +- pkg/keys/ed25519_test.go | 2 +- pkg/keys/rsa.go | 2 +- repo.go | 6 +++--- verify/verify_test.go | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/data/types.go b/data/types.go index ee9a2878..9c6945fd 100644 --- a/data/types.go +++ b/data/types.go @@ -24,7 +24,7 @@ const ( ) var ( - KeyAlgorithms = []string{"sha256", "sha512"} + HashAlgorithms = []string{"sha256", "sha512"} ErrPathsAndPathHashesSet = errors.New("tuf: failed validation of delegated target: paths and path_hash_prefixes are both set") ) diff --git a/data/types_test.go b/data/types_test.go index 0c689eb6..7bf45957 100644 --- a/data/types_test.go +++ b/data/types_test.go @@ -44,7 +44,7 @@ func (TypesSuite) TestKeyIDs(c *C) { key = PublicKey{ Type: KeyTypeEd25519, Scheme: KeySchemeEd25519, - Algorithms: KeyAlgorithms, + Algorithms: HashAlgorithms, Value: keyValBytes, } c.Assert(key.IDs(), DeepEquals, []string{keyid10algos}) @@ -96,7 +96,7 @@ func (TypesSuite) TestRoleAddKeyIDs(c *C) { key = &PublicKey{ Type: KeyTypeEd25519, Scheme: KeySchemeEd25519, - Algorithms: KeyAlgorithms, + Algorithms: HashAlgorithms, Value: keyValBytes, } diff --git a/local_store.go b/local_store.go index d2010024..4eb5c398 100644 --- a/local_store.go +++ b/local_store.go @@ -16,13 +16,13 @@ import ( ) func signers(privateKeys []*data.PrivateKey) []keys.Signer { - res := make([]keys.Signer, len(privateKeys)) - for i, k := range privateKeys { + res := make([]keys.Signer, 0, len(privateKeys)) + for _, k := range privateKeys { signer, err := keys.GetSigner(k) if err != nil { continue } - res[i] = signer + res = append(res, signer) } return res } diff --git a/pkg/keys/ed25519.go b/pkg/keys/ed25519.go index 65be3409..cd161dbd 100644 --- a/pkg/keys/ed25519.go +++ b/pkg/keys/ed25519.go @@ -79,7 +79,7 @@ func GenerateEd25519Key() (*ed25519Signer, error) { PrivateKey: ed25519.PrivateKey(data.HexBytes(private)), keyType: data.KeyTypeEd25519, keyScheme: data.KeySchemeEd25519, - keyAlgorithms: data.KeyAlgorithms, + keyAlgorithms: data.HashAlgorithms, }, nil } diff --git a/pkg/keys/ed25519_test.go b/pkg/keys/ed25519_test.go index 3aeb77f2..657b16ce 100644 --- a/pkg/keys/ed25519_test.go +++ b/pkg/keys/ed25519_test.go @@ -16,7 +16,7 @@ func (Ed25519Suite) TestUnmarshalEd25519(c *C) { badKey := &data.PublicKey{ Type: data.KeyTypeRSASSA_PSS_SHA256, Scheme: data.KeySchemeRSASSA_PSS_SHA256, - Algorithms: data.KeyAlgorithms, + Algorithms: data.HashAlgorithms, Value: badKeyValue, } verifier := NewP256Verifier() diff --git a/pkg/keys/rsa.go b/pkg/keys/rsa.go index f47a36df..72c715bb 100644 --- a/pkg/keys/rsa.go +++ b/pkg/keys/rsa.go @@ -108,7 +108,7 @@ func (s *rsaSigner) PublicData() *data.PublicKey { return &data.PublicKey{ Type: data.KeyTypeRSASSA_PSS_SHA256, Scheme: data.KeySchemeRSASSA_PSS_SHA256, - Algorithms: data.KeyAlgorithms, + Algorithms: data.HashAlgorithms, Value: keyValBytes, } } diff --git a/repo.go b/repo.go index f5541244..94d17129 100644 --- a/repo.go +++ b/repo.go @@ -311,7 +311,7 @@ func (r *Repo) GenKey(role string) ([]string, error) { return r.GenKeyWithExpires(role, data.DefaultExpires("root")) } -func (r *Repo) GenKeyWithExpires(keyRole string, expires time.Time) ([]string, error) { +func (r *Repo) GenKeyWithExpires(keyRole string, expires time.Time) (keyids []string, err error) { signer, err := keys.GenerateEd25519Key() if err != nil { return []string{}, err @@ -320,8 +320,8 @@ func (r *Repo) GenKeyWithExpires(keyRole string, expires time.Time) ([]string, e if err = r.AddPrivateKeyWithExpires(keyRole, signer, expires); err != nil { return []string{}, err } - - return signer.PublicData().IDs(), nil + keyids = signer.PublicData().IDs() + return } func (r *Repo) AddPrivateKey(role string, signer keys.Signer) error { diff --git a/verify/verify_test.go b/verify/verify_test.go index 34e146fe..648db325 100644 --- a/verify/verify_test.go +++ b/verify/verify_test.go @@ -40,7 +40,7 @@ func (s ecdsaSigner) PublicData() *data.PublicKey { return &data.PublicKey{ Type: data.KeyTypeECDSA_SHA2_P256, Scheme: data.KeySchemeECDSA_SHA2_P256, - Algorithms: data.KeyAlgorithms, + Algorithms: data.HashAlgorithms, Value: keyValBytes, } } From 621662eab4737a62bfa0e8cb0467448a2c4fbac5 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Tue, 28 Sep 2021 13:46:53 -0500 Subject: [PATCH 17/17] add panic Signed-off-by: Asra Ali --- data/types.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/data/types.go b/data/types.go index 9c6945fd..01a811f4 100644 --- a/data/types.go +++ b/data/types.go @@ -4,12 +4,12 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" - "errors" "path/filepath" "strings" "sync" "time" + "github.com/pkg/errors" cjson "github.com/tent/canonical-json-go" ) @@ -57,7 +57,10 @@ type PrivateKey struct { func (k *PublicKey) IDs() []string { k.idOnce.Do(func() { - data, _ := cjson.Marshal(k) + data, err := cjson.Marshal(k) + if err != nil { + panic(errors.Wrap(err, "tuf: error creating key ID")) + } digest := sha256.Sum256(data) k.ids = []string{hex.EncodeToString(digest[:])} })