From 20b60d9cc2d1d8394e1965fbf49b067a1bc375cb Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Sat, 18 Jul 2015 22:50:44 -0700 Subject: [PATCH] cleaning up cache vs filestore Signed-off-by: David Lawrence (github: endophage) --- .../endophage/gotuf/client/client_test.go | 190 ++++++++++++++++++ client/client.go | 59 ++---- server/storage/memory.go | 4 +- 3 files changed, 213 insertions(+), 40 deletions(-) create mode 100644 Godeps/_workspace/src/github.com/endophage/gotuf/client/client_test.go diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/client/client_test.go b/Godeps/_workspace/src/github.com/endophage/gotuf/client/client_test.go new file mode 100644 index 0000000000..50faf0fa46 --- /dev/null +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/client/client_test.go @@ -0,0 +1,190 @@ +package client + +import ( + "testing" + + "github.com/Sirupsen/logrus" + tuf "github.com/endophage/gotuf" + "github.com/stretchr/testify/assert" + + "github.com/endophage/gotuf/data" + "github.com/endophage/gotuf/keys" + "github.com/endophage/gotuf/signed" + "github.com/endophage/gotuf/store" +) + +func TestRotation(t *testing.T) { + kdb := keys.NewDB() + signer := signed.NewEd25519() + repo := tuf.NewTufRepo(kdb, signer) + remote := store.NewMemoryStore(nil, nil) + cache := store.NewMemoryStore(nil, nil) + + // Generate initial root key and role and add to key DB + rootKey, err := signer.Create("root", data.ED25519Key) + assert.NoError(t, err, "Error creating root key") + rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil) + assert.NoError(t, err, "Error creating root role") + + kdb.AddKey(rootKey) + err = kdb.AddRole(rootRole) + assert.NoError(t, err, "Error adding root role to db") + + // Generate new key and role. These will appear in the root.json + // but will not be added to the keyDB. + replacementKey, err := signer.Create("root", data.ED25519Key) + assert.NoError(t, err, "Error creating replacement root key") + replacementRole, err := data.NewRole("root", 1, []string{replacementKey.ID()}, nil, nil) + assert.NoError(t, err, "Error creating replacement root role") + + // Generate a new root with the replacement key and role + testRoot, err := data.NewRoot( + map[string]data.PublicKey{replacementKey.ID(): replacementKey}, + map[string]*data.RootRole{"root": &replacementRole.RootRole}, + false, + ) + assert.NoError(t, err, "Failed to create new root") + + // Sign testRoot with both old and new keys + signedRoot, err := testRoot.ToSigned() + err = signed.Sign(signer, signedRoot, rootKey, replacementKey) + assert.NoError(t, err, "Failed to sign root") + var origKeySig bool + var replKeySig bool + for _, sig := range signedRoot.Signatures { + if sig.KeyID == rootKey.ID() { + origKeySig = true + } else if sig.KeyID == replacementKey.ID() { + replKeySig = true + } + } + assert.True(t, origKeySig, "Original root key signature not present") + assert.True(t, replKeySig, "Replacement root key signature not present") + + client := NewClient(repo, remote, kdb, cache) + + err = client.verifyRoot("root", signedRoot, 0) + assert.NoError(t, err, "Failed to verify key rotated root") +} + +func TestRotationNewSigMissing(t *testing.T) { + logrus.SetLevel(logrus.DebugLevel) + kdb := keys.NewDB() + signer := signed.NewEd25519() + repo := tuf.NewTufRepo(kdb, signer) + remote := store.NewMemoryStore(nil, nil) + cache := store.NewMemoryStore(nil, nil) + + // Generate initial root key and role and add to key DB + rootKey, err := signer.Create("root", data.ED25519Key) + assert.NoError(t, err, "Error creating root key") + rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil) + assert.NoError(t, err, "Error creating root role") + + kdb.AddKey(rootKey) + err = kdb.AddRole(rootRole) + assert.NoError(t, err, "Error adding root role to db") + + // Generate new key and role. These will appear in the root.json + // but will not be added to the keyDB. + replacementKey, err := signer.Create("root", data.ED25519Key) + assert.NoError(t, err, "Error creating replacement root key") + replacementRole, err := data.NewRole("root", 1, []string{replacementKey.ID()}, nil, nil) + assert.NoError(t, err, "Error creating replacement root role") + + assert.NotEqual(t, rootKey.ID(), replacementKey.ID(), "Key IDs are the same") + + // Generate a new root with the replacement key and role + testRoot, err := data.NewRoot( + map[string]data.PublicKey{replacementKey.ID(): replacementKey}, + map[string]*data.RootRole{"root": &replacementRole.RootRole}, + false, + ) + assert.NoError(t, err, "Failed to create new root") + + _, ok := testRoot.Signed.Keys[rootKey.ID()] + assert.False(t, ok, "Old root key appeared in test root") + + // Sign testRoot with both old and new keys + signedRoot, err := testRoot.ToSigned() + err = signed.Sign(signer, signedRoot, rootKey) + assert.NoError(t, err, "Failed to sign root") + var origKeySig bool + var replKeySig bool + for _, sig := range signedRoot.Signatures { + if sig.KeyID == rootKey.ID() { + origKeySig = true + } else if sig.KeyID == replacementKey.ID() { + replKeySig = true + } + } + assert.True(t, origKeySig, "Original root key signature not present") + assert.False(t, replKeySig, "Replacement root key signature was present and shouldn't be") + + client := NewClient(repo, remote, kdb, cache) + + err = client.verifyRoot("root", signedRoot, 0) + assert.Error(t, err, "Should have errored on verify as replacement signature was missing.") + +} + +func TestRotationOldSigMissing(t *testing.T) { + logrus.SetLevel(logrus.DebugLevel) + kdb := keys.NewDB() + signer := signed.NewEd25519() + repo := tuf.NewTufRepo(kdb, signer) + remote := store.NewMemoryStore(nil, nil) + cache := store.NewMemoryStore(nil, nil) + + // Generate initial root key and role and add to key DB + rootKey, err := signer.Create("root", data.ED25519Key) + assert.NoError(t, err, "Error creating root key") + rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil) + assert.NoError(t, err, "Error creating root role") + + kdb.AddKey(rootKey) + err = kdb.AddRole(rootRole) + assert.NoError(t, err, "Error adding root role to db") + + // Generate new key and role. These will appear in the root.json + // but will not be added to the keyDB. + replacementKey, err := signer.Create("root", data.ED25519Key) + assert.NoError(t, err, "Error creating replacement root key") + replacementRole, err := data.NewRole("root", 1, []string{replacementKey.ID()}, nil, nil) + assert.NoError(t, err, "Error creating replacement root role") + + assert.NotEqual(t, rootKey.ID(), replacementKey.ID(), "Key IDs are the same") + + // Generate a new root with the replacement key and role + testRoot, err := data.NewRoot( + map[string]data.PublicKey{replacementKey.ID(): replacementKey}, + map[string]*data.RootRole{"root": &replacementRole.RootRole}, + false, + ) + assert.NoError(t, err, "Failed to create new root") + + _, ok := testRoot.Signed.Keys[rootKey.ID()] + assert.False(t, ok, "Old root key appeared in test root") + + // Sign testRoot with both old and new keys + signedRoot, err := testRoot.ToSigned() + err = signed.Sign(signer, signedRoot, replacementKey) + assert.NoError(t, err, "Failed to sign root") + var origKeySig bool + var replKeySig bool + for _, sig := range signedRoot.Signatures { + if sig.KeyID == rootKey.ID() { + origKeySig = true + } else if sig.KeyID == replacementKey.ID() { + replKeySig = true + } + } + assert.False(t, origKeySig, "Original root key signature was present and shouldn't be") + assert.True(t, replKeySig, "Replacement root key signature was not present") + + client := NewClient(repo, remote, kdb, cache) + + err = client.verifyRoot("root", signedRoot, 0) + assert.Error(t, err, "Should have errored on verify as replacement signature was missing.") + +} diff --git a/client/client.go b/client/client.go index 045d3b9474..80b2865401 100644 --- a/client/client.go +++ b/client/client.go @@ -103,6 +103,17 @@ func NewNotaryRepository(baseDir, gun, baseURL string, rt http.RoundTripper) (*N KeyStoreManager: keyStoreManager, } + fileStore, err := store.NewFilesystemStore( + nRepo.tufRepoPath, + "metadata", + "json", + "", + ) + if err != nil { + return nil, err + } + nRepo.fileStore = fileStore + return nRepo, nil } @@ -210,16 +221,6 @@ func (r *NotaryRepository) Initialize(uCryptoService *cryptoservice.UnlockedCryp r.tufRepo = tuf.NewTufRepo(kdb, r.cryptoService) - r.fileStore, err = store.NewFilesystemStore( - r.tufRepoPath, - "metadata", - "json", - "", - ) - if err != nil { - return err - } - if err := r.tufRepo.InitRepo(false); err != nil { return err } @@ -421,21 +422,11 @@ func (r *NotaryRepository) Publish(getPass passwordRetriever) error { } func (r *NotaryRepository) bootstrapRepo() error { - fileStore, err := store.NewFilesystemStore( - r.tufRepoPath, - "metadata", - "json", - "", - ) - if err != nil { - return err - } - kdb := keys.NewDB() tufRepo := tuf.NewTufRepo(kdb, r.cryptoService) logrus.Debugf("Loading trusted collection.") - rootJSON, err := fileStore.GetMeta("root", 0) + rootJSON, err := r.fileStore.GetMeta("root", 0) if err != nil { return err } @@ -445,7 +436,7 @@ func (r *NotaryRepository) bootstrapRepo() error { return err } tufRepo.SetRoot(root) - targetsJSON, err := fileStore.GetMeta("targets", 0) + targetsJSON, err := r.fileStore.GetMeta("targets", 0) if err != nil { return err } @@ -455,7 +446,7 @@ func (r *NotaryRepository) bootstrapRepo() error { return err } tufRepo.SetTargets("targets", targets) - snapshotJSON, err := fileStore.GetMeta("snapshot", 0) + snapshotJSON, err := r.fileStore.GetMeta("snapshot", 0) if err != nil { return err } @@ -467,7 +458,6 @@ func (r *NotaryRepository) bootstrapRepo() error { tufRepo.SetSnapshot(snapshot) r.tufRepo = tufRepo - r.fileStore = fileStore return nil } @@ -506,19 +496,7 @@ func (r *NotaryRepository) snapshot() error { } func (r *NotaryRepository) bootstrapClient() (*tufclient.Client, error) { - var cache store.MetadataStore - cache, err := store.NewFilesystemStore( - filepath.Join(r.tufRepoPath, "cache"), - "metadata", - "json", - "", - ) - if err != nil { - cache = store.NewMemoryStore(nil, nil) - } - var rootJSON []byte - err = nil remote, err := getRemoteStore(r.baseURL, r.gun, r.roundTrip) if err == nil { // if remote store successfully set up, try and get root from remote @@ -528,7 +506,12 @@ func (r *NotaryRepository) bootstrapClient() (*tufclient.Client, error) { // if remote store couldn't be setup, or we failed to get a root from it // load the root from cache (offline operation) if err != nil { - rootJSON, err = cache.GetMeta("root", maxSize) + if err, ok := err.(*store.ErrMetaNotFound); ok { + // if the error was MetaNotFound then we successfully contacted + // the store and it doesn't know about the repo. + return nil, err + } + rootJSON, err = r.fileStore.GetMeta("root", maxSize) if err != nil { // if cache didn't return a root, we cannot proceed return nil, &store.ErrMetaNotFound{} @@ -557,6 +540,6 @@ func (r *NotaryRepository) bootstrapClient() (*tufclient.Client, error) { r.tufRepo, remote, kdb, - cache, + r.fileStore, ), nil } diff --git a/server/storage/memory.go b/server/storage/memory.go index 9cf58a424a..6d436697f0 100644 --- a/server/storage/memory.go +++ b/server/storage/memory.go @@ -64,10 +64,10 @@ func (st *MemStorage) GetCurrent(gun, role string) (data []byte, err error) { st.lock.Lock() defer st.lock.Unlock() space, ok := st.tufMeta[id] - if !ok { + if !ok || len(space) == 0 { return nil, &ErrNotFound{} } - return space[len(st.tufMeta[id])-1].data, nil + return space[len(space)-1].data, nil } // Delete delets all the metadata for a given GUN