Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor keys to allow more key types and add RSA key verifier #148

Merged
merged 18 commits into from
Oct 6, 2021
2 changes: 1 addition & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
45 changes: 25 additions & 20 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,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/pkg/keys"
"github.com/theupdateframework/go-tuf/sign"
"github.com/theupdateframework/go-tuf/util"
"github.com/theupdateframework/go-tuf/verify"
Expand Down Expand Up @@ -172,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)
Expand Down Expand Up @@ -346,17 +347,18 @@ 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.GetVerifier(id)
c.Assert(err, NotNil)
}
}

// check new keys are in db
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)
verifier, err := client.db.GetVerifier(id)
c.Assert(err, IsNil)
c.Assert(verifier.MarshalPublicKey().IDs(), DeepEquals, ids)
}
role := client.db.GetRole(name)
c.Assert(role, NotNil)
Expand Down Expand Up @@ -590,12 +592,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.GetVerifier(oldID)
c.Assert(err, NotNil)
}
for _, newID := range newIDs {
key := client.db.GetKey(newID)
c.Assert(key, NotNil)
c.Assert(key.IDs(), DeepEquals, newIDs)
verifier, err := client.db.GetVerifier(newID)
c.Assert(err, IsNil)
c.Assert(verifier.MarshalPublicKey().IDs(), DeepEquals, newIDs)
}
role := client.db.GetRole("timestamp")
c.Assert(role, NotNil)
Expand Down Expand Up @@ -629,12 +632,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.GetVerifier(oldID)
c.Assert(err, NotNil)
}
for _, newID := range newIDs {
key := client.db.GetKey(newID)
c.Assert(key, NotNil)
c.Assert(key.IDs(), DeepEquals, newIDs)
verifier, err := client.db.GetVerifier(newID)
c.Assert(err, IsNil)
c.Assert(verifier.MarshalPublicKey().IDs(), DeepEquals, newIDs)
}
role := client.db.GetRole("snapshot")
c.Assert(role, NotNil)
Expand Down Expand Up @@ -671,12 +675,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.GetVerifier(oldID)
c.Assert(err, NotNil)
}
for _, newID := range newIDs {
key := client.db.GetKey(newID)
c.Assert(key, NotNil)
c.Assert(key.IDs(), DeepEquals, newIDs)
verifier, err := client.db.GetVerifier(newID)
c.Assert(err, IsNil)
c.Assert(verifier.MarshalPublicKey().IDs(), DeepEquals, newIDs)
}
role := client.db.GetRole("targets")
c.Assert(role, NotNil)
Expand Down Expand Up @@ -1109,13 +1114,13 @@ 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()
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.GetSigningKeys("root")
signingKeys, err := s.store.GetSigners("root")
c.Assert(err, IsNil)

signedRoot, err := sign.Marshal(root.Signed, signingKeys...)
Expand Down
2 changes: 1 addition & 1 deletion client/delegations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions client/interop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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]
Expand Down
9 changes: 6 additions & 3 deletions client/python_interop/python_interop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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/pkg/keys"
"github.com/theupdateframework/go-tuf/util"
"golang.org/x/crypto/ed25519"
. "gopkg.in/check.v1"
Expand Down Expand Up @@ -61,12 +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")
c.Assert(key.Value.Public, HasLen, ed25519.PublicKeySize)
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()
Expand Down
29 changes: 17 additions & 12 deletions client/testdata/go-tuf-transition-M3/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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/pkg/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) {
Expand Down Expand Up @@ -48,10 +49,12 @@ 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 {
signer, err := keys.GetSigner(key)
assertNotNil(err)
assertNotNil(repo.AddPrivateKeyWithExpires(role, signer, expirationDate))
}
}
}
Expand All @@ -67,22 +70,24 @@ 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 {
signer, err := keys.GetSigner(key)
assertNotNil(err)
assertNotNil(repo.RevokeKeyWithExpires(role, signer.PublicData().IDs()[0], expirationDate))
}
}

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],
Expand Down Expand Up @@ -110,7 +115,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]
Expand Down
21 changes: 12 additions & 9 deletions client/testdata/go-tuf-transition-M4/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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/pkg/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) {
Expand Down Expand Up @@ -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))
Expand All @@ -67,22 +68,24 @@ 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 {
signer, err := keys.GetSigner(key)
assertNotNil(err)
assertNotNil(repo.RevokeKeyWithExpires(role, signer.PublicData().IDs()[0], expirationDate))
}
}

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],
Expand Down Expand Up @@ -110,7 +113,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]
Expand Down
31 changes: 18 additions & 13 deletions client/testdata/go-tuf/generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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/pkg/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) {
Expand Down Expand Up @@ -48,10 +49,12 @@ 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 {
signer, err := keys.GetSigner(key)
assertNotNil(err)
assertNotNil(repo.AddPrivateKeyWithExpires(role, signer, expirationDate))
}
}
}
Expand All @@ -67,16 +70,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 {
signer, err := keys.GetSigner(key)
assertNotNil(err)
assertNotNil(repo.RevokeKeyWithExpires(role, signer.PublicData().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],
Expand Down Expand Up @@ -104,7 +109,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]
Expand All @@ -131,7 +136,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)
Expand Down
Loading