From 4f8c1a8ef405004e2c72ff944143ef2ffd96a42d Mon Sep 17 00:00:00 2001 From: Ying Li Date: Wed, 18 Nov 2015 00:29:18 -0800 Subject: [PATCH 1/4] Server check that the root.json's timestamp key ID is valid. If the client sends a root.json with an invalid timestamp key ID, possibly because they are pushing an existing repo to a new server, then the server should reject the update. Signed-off-by: Ying Li --- server/handlers/validation.go | 46 ++++++-- server/handlers/validation_test.go | 176 ++++++++++++++++++++++++----- 2 files changed, 188 insertions(+), 34 deletions(-) diff --git a/server/handlers/validation.go b/server/handlers/validation.go index 86d0524895..1356a87d32 100644 --- a/server/handlers/validation.go +++ b/server/handlers/validation.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "strings" "github.com/docker/notary/tuf" "github.com/docker/notary/tuf/data" @@ -94,10 +95,11 @@ func validateUpdate(gun string, updates []storage.MetaUpdate, store storage.Meta if rootUpdate, ok := roles[rootRole]; ok { // if root is present, validate its integrity, possibly // against a previous root - if root, err = validateRoot(gun, oldRootJSON, rootUpdate.Data); err != nil { + if root, err = validateRoot(gun, oldRootJSON, rootUpdate.Data, store); err != nil { logrus.Error("ErrBadRoot: ", err.Error()) return ErrBadRoot{msg: err.Error()} } + // setting root will update keys db if err = repo.SetRoot(root); err != nil { logrus.Error("ErrValidation: ", err.Error()) @@ -252,7 +254,9 @@ func hierarchyOK(roles map[string]storage.MetaUpdate) error { return nil } -func validateRoot(gun string, oldRoot, newRoot []byte) (*data.SignedRoot, error) { +func validateRoot(gun string, oldRoot, newRoot []byte, store storage.MetaStore) ( + *data.SignedRoot, error) { + var parsedOldRoot *data.SignedRoot parsedNewRoot := &data.SignedRoot{} @@ -271,23 +275,32 @@ func validateRoot(gun string, oldRoot, newRoot []byte) (*data.SignedRoot, error) if err != nil { return nil, err } - if err := checkRoot(parsedOldRoot, parsedNewRoot); err != nil { + + // Don't update if a timestamp key doesn't exist. + algo, keyBytes, err := store.GetTimestampKey(gun) + if err != nil || algo == "" || keyBytes == nil { + return nil, fmt.Errorf("no timestamp key for %s", gun) + } + timestampKey := data.NewPublicKey(algo, keyBytes) + + if err := checkRoot(parsedOldRoot, parsedNewRoot, timestampKey); err != nil { // TODO(david): how strict do we want to be here about old signatures // for rotations? Should the user have to provide a flag // which gets transmitted to force a root update without // correct old key signatures. return nil, err } + if !data.ValidTUFType(parsedNewRoot.Signed.Type, data.CanonicalRootRole) { return nil, fmt.Errorf("root has wrong type") } return parsedNewRoot, nil } -// checkRoot returns true if no rotation, or a valid -// rotation has taken place, and the threshold number of signatures -// are valid. -func checkRoot(oldRoot, newRoot *data.SignedRoot) error { +// checkRoot errors if an invalid valid rotation has taken place, if the +// threshold number of signatures is invalid valid, if there are an invalid +// number of roles and keys, or if the timestamp keys are invalid +func checkRoot(oldRoot, newRoot *data.SignedRoot, timestampKey data.PublicKey) error { rootRole := data.RoleName(data.CanonicalRootRole) targetsRole := data.RoleName(data.CanonicalTargetsRole) snapshotRole := data.RoleName(data.CanonicalSnapshotRole) @@ -360,6 +373,9 @@ func checkRoot(oldRoot, newRoot *data.SignedRoot) error { if err != nil { return err } + + var timestampKeyIDs []string + // at a minimum, check the 4 required roles are present for _, r := range []string{rootRole, targetsRole, snapshotRole, timestampRole} { role, ok := root.Signed.Roles[r] @@ -372,6 +388,20 @@ func checkRoot(oldRoot, newRoot *data.SignedRoot) error { if len(role.KeyIDs) < role.Threshold { return fmt.Errorf("%s role has insufficient number of keys", r) } + + if r == timestampRole { + timestampKeyIDs = role.KeyIDs + } } - return nil + + // ensure that at least one of the timestamp keys specified in the role + // actually exists + + for _, keyID := range timestampKeyIDs { + if timestampKey.ID() == keyID { + return nil + } + } + return fmt.Errorf("none of the following timestamp keys exist: %s", + strings.Join(timestampKeyIDs, ", ")) } diff --git a/server/handlers/validation_test.go b/server/handlers/validation_test.go index aa7312b392..d3dcfd232f 100644 --- a/server/handlers/validation_test.go +++ b/server/handlers/validation_test.go @@ -1,9 +1,13 @@ package handlers import ( + "crypto/rand" + "fmt" "testing" + "github.com/docker/notary/trustmanager" "github.com/docker/notary/tuf/data" + "github.com/docker/notary/tuf/keys" "github.com/docker/notary/tuf/signed" "github.com/docker/notary/tuf/testutils" "github.com/stretchr/testify/assert" @@ -11,8 +15,25 @@ import ( "github.com/docker/notary/server/storage" ) +func copyTimestampKey(t *testing.T, fromKeyDB *keys.KeyDB, + toStore storage.MetaStore, gun string) { + + role := fromKeyDB.GetRole(data.CanonicalTimestampRole) + assert.NotNil(t, role, "No timestamp role in the KeyDB") + assert.Len(t, role.KeyIDs, 1, fmt.Sprintf( + "Expected 1 timestamp key in timestamp role, got %d", len(role.KeyIDs))) + + pubTimestampKey := fromKeyDB.GetKey(role.KeyIDs[0]) + assert.NotNil(t, pubTimestampKey, + "Timestamp key specified by KeyDB role not in KeysDB") + + err := toStore.SetTimestampKey(gun, pubTimestampKey.Algorithm(), + pubTimestampKey.Public()) + assert.NoError(t, err) +} + func TestValidateEmptyNew(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -42,13 +63,13 @@ func TestValidateEmptyNew(t *testing.T) { Data: timestamp, }, } - + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.NoError(t, err) } func TestValidateNoNewRoot(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -82,13 +103,13 @@ func TestValidateNoNewRoot(t *testing.T) { Data: timestamp, }, } - + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.NoError(t, err) } func TestValidateNoNewTargets(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -122,13 +143,13 @@ func TestValidateNoNewTargets(t *testing.T) { Data: timestamp, }, } - + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.NoError(t, err) } func TestValidateOnlySnapshot(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -160,13 +181,13 @@ func TestValidateOnlySnapshot(t *testing.T) { Data: snapshot, }, } - + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.NoError(t, err) } func TestValidateOldRoot(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -205,13 +226,13 @@ func TestValidateOldRoot(t *testing.T) { Data: timestamp, }, } - + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.NoError(t, err) } func TestValidateRootRotation(t *testing.T) { - _, repo, crypto := testutils.EmptyRepo() + kdb, repo, crypto := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -278,12 +299,13 @@ func TestValidateRootRotation(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.NoError(t, err) } func TestValidateNoRoot(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -309,13 +331,14 @@ func TestValidateNoRoot(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrValidation{}, err) } func TestValidateSnapshotMissing(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -336,16 +359,104 @@ func TestValidateSnapshotMissing(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadHierarchy{}, err) } +// If there is no timestamp key in the store, validation fails. This could +// happen if pushing an existing repository from one server to another that +// does not have the repo. +func TestValidateRootNoTimestampKey(t *testing.T) { + _, oldRepo, _ := testutils.EmptyRepo() + + r, tg, sn, ts, err := testutils.Sign(oldRepo) + assert.NoError(t, err) + root, targets, snapshot, _, err := testutils.Serialize(r, tg, sn, ts) + assert.NoError(t, err) + + store := storage.NewMemStorage() + updates := []storage.MetaUpdate{ + { + Role: "root", + Version: 1, + Data: root, + }, + { + Role: "targets", + Version: 1, + Data: targets, + }, + { + Role: "snapshot", + Version: 1, + Data: snapshot, + }, + } + + // sanity check - no timestamp keys for the GUN + _, _, err = store.GetTimestampKey("testGUN") + assert.Error(t, err) + assert.IsType(t, &storage.ErrNoKey{}, err) + + // do not copy the targets key to the storage, and try to update the root + err = validateUpdate("testGUN", updates, store) + assert.Error(t, err) + assert.IsType(t, ErrBadRoot{}, err) + + // there should still be no timestamp keys - one should not have been + // created + _, _, err = store.GetTimestampKey("testGUN") + assert.Error(t, err) +} + +// If the timestamp key in the store does not match the timestamp key in +// the root.json, validation fails. This could happen if pushing an existing +// repository from one server to another that had already initialized the same +// repo. +func TestValidateRootInvalidTimestampKey(t *testing.T) { + _, oldRepo, _ := testutils.EmptyRepo() + + r, tg, sn, ts, err := testutils.Sign(oldRepo) + assert.NoError(t, err) + root, targets, snapshot, _, err := testutils.Serialize(r, tg, sn, ts) + assert.NoError(t, err) + + store := storage.NewMemStorage() + updates := []storage.MetaUpdate{ + { + Role: "root", + Version: 1, + Data: root, + }, + { + Role: "targets", + Version: 1, + Data: targets, + }, + { + Role: "snapshot", + Version: 1, + Data: snapshot, + }, + } + + key, err := trustmanager.GenerateECDSAKey(rand.Reader) + assert.NoError(t, err) + err = store.SetTimestampKey("testGUN", key.Algorithm(), key.Public()) + assert.NoError(t, err) + + err = validateUpdate("testGUN", updates, store) + assert.Error(t, err) + assert.IsType(t, ErrBadRoot{}, err) +} + // ### Role missing negative tests ### // These tests remove a role from the Root file and // check for a ErrBadRoot func TestValidateRootRoleMissing(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() delete(repo.Root.Signed.Roles, "root") @@ -378,13 +489,14 @@ func TestValidateRootRoleMissing(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadRoot{}, err) } func TestValidateTargetsRoleMissing(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() delete(repo.Root.Signed.Roles, "targets") @@ -417,13 +529,14 @@ func TestValidateTargetsRoleMissing(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadRoot{}, err) } func TestValidateSnapshotRoleMissing(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() delete(repo.Root.Signed.Roles, "snapshot") @@ -456,6 +569,7 @@ func TestValidateSnapshotRoleMissing(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadRoot{}, err) @@ -465,7 +579,7 @@ func TestValidateSnapshotRoleMissing(t *testing.T) { // ### Signature missing negative tests ### func TestValidateRootSigMissing(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() delete(repo.Root.Signed.Roles, "snapshot") @@ -501,13 +615,14 @@ func TestValidateRootSigMissing(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadRoot{}, err) } func TestValidateTargetsSigMissing(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -541,13 +656,14 @@ func TestValidateTargetsSigMissing(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadTargets{}, err) } func TestValidateSnapshotSigMissing(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -581,6 +697,7 @@ func TestValidateSnapshotSigMissing(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadSnapshot{}, err) @@ -590,7 +707,7 @@ func TestValidateSnapshotSigMissing(t *testing.T) { // ### Corrupted metadata negative tests ### func TestValidateRootCorrupt(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -624,13 +741,14 @@ func TestValidateRootCorrupt(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadRoot{}, err) } func TestValidateTargetsCorrupt(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -664,13 +782,14 @@ func TestValidateTargetsCorrupt(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadTargets{}, err) } func TestValidateSnapshotCorrupt(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -704,6 +823,7 @@ func TestValidateSnapshotCorrupt(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadSnapshot{}, err) @@ -713,7 +833,7 @@ func TestValidateSnapshotCorrupt(t *testing.T) { // ### Snapshot size mismatch negative tests ### func TestValidateRootModifiedSize(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -751,13 +871,14 @@ func TestValidateRootModifiedSize(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadRoot{}, err) } func TestValidateTargetsModifiedSize(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -792,6 +913,7 @@ func TestValidateTargetsModifiedSize(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadSnapshot{}, err) @@ -801,7 +923,7 @@ func TestValidateTargetsModifiedSize(t *testing.T) { // ### Snapshot hash mismatch negative tests ### func TestValidateRootModifiedHash(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -840,13 +962,14 @@ func TestValidateRootModifiedHash(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadSnapshot{}, err) } func TestValidateTargetsModifiedHash(t *testing.T) { - _, repo, _ := testutils.EmptyRepo() + kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) @@ -885,6 +1008,7 @@ func TestValidateTargetsModifiedHash(t *testing.T) { }, } + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.Error(t, err) assert.IsType(t, ErrBadSnapshot{}, err) From b4fb4ac173c28125b2f62a6aa6f0a4c2791159d8 Mon Sep 17 00:00:00 2001 From: Ying Li Date: Wed, 18 Nov 2015 14:53:28 -0800 Subject: [PATCH 2/4] Change the error message on the client, if the server returns 400. Previously it was "fatal: Unable to reach trust server at this time: 400." and now it is "fatal: Trust server rejected operation." Signed-off-by: Ying Li --- tuf/store/httpstore.go | 56 +++++++++++++++++++++---------------- tuf/store/httpstore_test.go | 8 ++++-- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/tuf/store/httpstore.go b/tuf/store/httpstore.go index 5e667432b7..f4dbcdb350 100644 --- a/tuf/store/httpstore.go +++ b/tuf/store/httpstore.go @@ -33,6 +33,19 @@ func (err ErrMaliciousServer) Error() string { return "Trust server returned a bad response." } +// ErrInvalidOperation indicates that the server returned a 400 response and +// propogate any body we received. +type ErrInvalidOperation struct { + msg string +} + +func (err ErrInvalidOperation) Error() string { + if err.msg != "" { + return fmt.Sprintf("Trust server rejected operation: %s", err.msg) + } + return "Trust server rejected operation." +} + // HTTPStore manages pulling and pushing metadata from and to a remote // service over HTTP. It assumes the URL structure of the remote service // maps identically to the structure of the TUF repo: @@ -70,6 +83,17 @@ func NewHTTPStore(baseURL, metaPrefix, metaExtension, targetsPrefix, keyExtensio }, nil } +func translateStatusToError(resp *http.Response) error { + if resp.StatusCode == http.StatusNotFound { + return ErrMetaNotFound{} + } else if resp.StatusCode == http.StatusBadRequest { + return ErrInvalidOperation{} + } else if resp.StatusCode != http.StatusOK { + return ErrServerUnavailable{code: resp.StatusCode} + } + return nil +} + // GetMeta downloads the named meta file with the given size. A short body // is acceptable because in the case of timestamp.json, the size is a cap, // not an exact length. @@ -87,11 +111,9 @@ func (s HTTPStore) GetMeta(name string, size int64) ([]byte, error) { return nil, err } defer resp.Body.Close() - if resp.StatusCode == http.StatusNotFound { - return nil, ErrMetaNotFound{} - } else if resp.StatusCode != http.StatusOK { + if err := translateStatusToError(resp); err != nil { logrus.Debugf("received HTTP status %d when requesting %s.", resp.StatusCode, name) - return nil, ErrServerUnavailable{code: resp.StatusCode} + return nil, err } if resp.ContentLength > size { return nil, ErrMaliciousServer{} @@ -120,12 +142,7 @@ func (s HTTPStore) SetMeta(name string, blob []byte) error { return err } defer resp.Body.Close() - if resp.StatusCode == http.StatusNotFound { - return ErrMetaNotFound{} - } else if resp.StatusCode != http.StatusOK { - return ErrServerUnavailable{code: resp.StatusCode} - } - return nil + return translateStatusToError(resp) } // SetMultiMeta does a single batch upload of multiple pieces of TUF metadata. @@ -159,12 +176,7 @@ func (s HTTPStore) SetMultiMeta(metas map[string][]byte) error { return err } defer resp.Body.Close() - if resp.StatusCode == http.StatusNotFound { - return ErrMetaNotFound{} - } else if resp.StatusCode != http.StatusOK { - return ErrServerUnavailable{code: resp.StatusCode} - } - return nil + return translateStatusToError(resp) } func (s HTTPStore) buildMetaURL(name string) (*url.URL, error) { @@ -212,10 +224,8 @@ func (s HTTPStore) GetTarget(path string) (io.ReadCloser, error) { return nil, err } defer resp.Body.Close() - if resp.StatusCode == http.StatusNotFound { - return nil, ErrMetaNotFound{} - } else if resp.StatusCode != http.StatusOK { - return nil, ErrServerUnavailable{code: resp.StatusCode} + if err := translateStatusToError(resp); err != nil { + return nil, err } return resp.Body, nil } @@ -235,10 +245,8 @@ func (s HTTPStore) GetKey(role string) ([]byte, error) { return nil, err } defer resp.Body.Close() - if resp.StatusCode == http.StatusNotFound { - return nil, ErrMetaNotFound{} - } else if resp.StatusCode != http.StatusOK { - return nil, ErrServerUnavailable{code: resp.StatusCode} + if err := translateStatusToError(resp); err != nil { + return nil, err } body, err := ioutil.ReadAll(resp.Body) if err != nil { diff --git a/tuf/store/httpstore_test.go b/tuf/store/httpstore_test.go index 6d1c689acc..9f5c3c1cf7 100644 --- a/tuf/store/httpstore_test.go +++ b/tuf/store/httpstore_test.go @@ -178,11 +178,11 @@ func testErrorCode(t *testing.T, errorCode int, errType error) { fmt.Sprintf("%d should translate to %v", errorCode, errType)) } -func TestErrMetadataNotFound(t *testing.T) { +func Test404Error(t *testing.T) { testErrorCode(t, http.StatusNotFound, ErrMetaNotFound{}) } -func Test500Errors(t *testing.T) { +func Test50XErrors(t *testing.T) { fiveHundreds := []int{ http.StatusInternalServerError, http.StatusNotImplemented, @@ -195,3 +195,7 @@ func Test500Errors(t *testing.T) { testErrorCode(t, code, ErrServerUnavailable{}) } } + +func Test400Error(t *testing.T) { + testErrorCode(t, http.StatusBadRequest, ErrInvalidOperation{}) +} From bd84f3cce1a13af2c609f3bb3c7b7f65f6fddb0c Mon Sep 17 00:00:00 2001 From: Ying Li Date: Tue, 24 Nov 2015 13:45:02 -0500 Subject: [PATCH 3/4] Address review comments. Thanks @mtrmac! Signed-off-by: Ying Li --- server/handlers/validation.go | 4 ++-- tuf/store/httpstore.go | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/server/handlers/validation.go b/server/handlers/validation.go index 1356a87d32..9f18a0fcd0 100644 --- a/server/handlers/validation.go +++ b/server/handlers/validation.go @@ -297,8 +297,8 @@ func validateRoot(gun string, oldRoot, newRoot []byte, store storage.MetaStore) return parsedNewRoot, nil } -// checkRoot errors if an invalid valid rotation has taken place, if the -// threshold number of signatures is invalid valid, if there are an invalid +// checkRoot errors if an invalid rotation has taken place, if the +// threshold number of signatures is invalid, if there are an invalid // number of roles and keys, or if the timestamp keys are invalid func checkRoot(oldRoot, newRoot *data.SignedRoot, timestampKey data.PublicKey) error { rootRole := data.RoleName(data.CanonicalRootRole) diff --git a/tuf/store/httpstore.go b/tuf/store/httpstore.go index f4dbcdb350..460c782695 100644 --- a/tuf/store/httpstore.go +++ b/tuf/store/httpstore.go @@ -84,14 +84,16 @@ func NewHTTPStore(baseURL, metaPrefix, metaExtension, targetsPrefix, keyExtensio } func translateStatusToError(resp *http.Response) error { - if resp.StatusCode == http.StatusNotFound { + switch resp.StatusCode { + case http.StatusOK: + return nil + case http.StatusNotFound: return ErrMetaNotFound{} - } else if resp.StatusCode == http.StatusBadRequest { + case http.StatusBadRequest: return ErrInvalidOperation{} - } else if resp.StatusCode != http.StatusOK { + default: return ErrServerUnavailable{code: resp.StatusCode} } - return nil } // GetMeta downloads the named meta file with the given size. A short body From 9c3d87d5eb7460cba5c9e2d0f0bbab48fdccd69a Mon Sep 17 00:00:00 2001 From: Ying Li Date: Tue, 24 Nov 2015 17:47:00 -0500 Subject: [PATCH 4/4] When validating root.json on the server, timestamp threshold must be 1. This is because the server handles the timestamp key and timestamp signing. So there can only ever be 1 key. Thanks @mtrmac for pointing this out. This change also refactors some of the test code somewhat. Signed-off-by: Ying Li --- server/handlers/validation.go | 6 +- server/handlers/validation_test.go | 667 ++++++----------------------- 2 files changed, 140 insertions(+), 533 deletions(-) diff --git a/server/handlers/validation.go b/server/handlers/validation.go index 9f18a0fcd0..e17246b2b9 100644 --- a/server/handlers/validation.go +++ b/server/handlers/validation.go @@ -382,7 +382,11 @@ func checkRoot(oldRoot, newRoot *data.SignedRoot, timestampKey data.PublicKey) e if !ok { return fmt.Errorf("missing required %s role from root", r) } - if role.Threshold < 1 { + // According to the TUF spec, any role may have more than one signing + // key and require a threshold signature. However, notary-server + // creates the timestamp, and there is only ever one, so a threshold + // greater than one would just always fail validation + if (r == timestampRole && role.Threshold != 1) || role.Threshold < 1 { return fmt.Errorf("%s role has invalid threshold", r) } if len(role.KeyIDs) < role.Threshold { diff --git a/server/handlers/validation_test.go b/server/handlers/validation_test.go index d3dcfd232f..5f6e7e59cc 100644 --- a/server/handlers/validation_test.go +++ b/server/handlers/validation_test.go @@ -32,37 +32,49 @@ func copyTimestampKey(t *testing.T, fromKeyDB *keys.KeyDB, assert.NoError(t, err) } +// Returns a mapping of role name to `MetaUpdate` objects +func getUpdates(r, tg, sn, ts *data.Signed) ( + root, targets, snapshot, timestamp storage.MetaUpdate, err error) { + + rs, tgs, sns, tss, err := testutils.Serialize(r, tg, sn, ts) + if err != nil { + return + } + + root = storage.MetaUpdate{ + Role: data.CanonicalRootRole, + Version: 1, + Data: rs, + } + targets = storage.MetaUpdate{ + Role: data.CanonicalTargetsRole, + Version: 1, + Data: tgs, + } + snapshot = storage.MetaUpdate{ + Role: data.CanonicalSnapshotRole, + Version: 1, + Data: sns, + } + timestamp = storage.MetaUpdate{ + Role: data.CanonicalTimestampRole, + Version: 1, + Data: tss, + } + return +} + func TestValidateEmptyNew(t *testing.T) { kdb, repo, _ := testutils.EmptyRepo() store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} + copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.NoError(t, err) @@ -74,35 +86,12 @@ func TestValidateNoNewRoot(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - store.UpdateCurrent( - "testGUN", - storage.MetaUpdate{ - Role: "root", - Version: 1, - Data: root, - }, - ) + store.UpdateCurrent("testGUN", root) + updates := []storage.MetaUpdate{targets, snapshot, timestamp} - updates := []storage.MetaUpdate{ - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.NoError(t, err) @@ -114,35 +103,12 @@ func TestValidateNoNewTargets(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - store.UpdateCurrent( - "testGUN", - storage.MetaUpdate{ - Role: "targets", - Version: 1, - Data: targets, - }, - ) + store.UpdateCurrent("testGUN", targets) + updates := []storage.MetaUpdate{root, snapshot, timestamp} - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.NoError(t, err) @@ -154,33 +120,14 @@ func TestValidateOnlySnapshot(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - root, targets, snapshot, _, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, _, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - store.UpdateCurrent( - "testGUN", - storage.MetaUpdate{ - Role: "root", - Version: 1, - Data: root, - }, - ) - store.UpdateCurrent( - "testGUN", - storage.MetaUpdate{ - Role: "targets", - Version: 1, - Data: targets, - }, - ) + store.UpdateCurrent("testGUN", root) + store.UpdateCurrent("testGUN", targets) + + updates := []storage.MetaUpdate{snapshot} - updates := []storage.MetaUpdate{ - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - } copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.NoError(t, err) @@ -192,40 +139,12 @@ func TestValidateOldRoot(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - store.UpdateCurrent( - "testGUN", - storage.MetaUpdate{ - Role: "root", - Version: 1, - Data: root, - }, - ) + store.UpdateCurrent("testGUN", root) + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) assert.NoError(t, err) @@ -237,17 +156,10 @@ func TestValidateRootRotation(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - store.UpdateCurrent( - "testGUN", - storage.MetaUpdate{ - Role: "root", - Version: 1, - Data: root, - }, - ) + store.UpdateCurrent("testGUN", root) oldRootRole := repo.Root.Signed.Roles["root"] oldRootKey := repo.Root.Signed.Keys[oldRootRole.KeyIDs[0]] @@ -273,31 +185,10 @@ func TestValidateRootRotation(t *testing.T) { sn, err = repo.SignSnapshot(data.DefaultExpires(data.CanonicalSnapshotRole)) assert.NoError(t, err) - root, targets, snapshot, timestamp, err = testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err = getUpdates(r, tg, sn, ts) assert.NoError(t, err) - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -310,26 +201,10 @@ func TestValidateNoRoot(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - _, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + _, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - updates := []storage.MetaUpdate{ - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -343,21 +218,10 @@ func TestValidateSnapshotMissing(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - root, targets, _, _, err := testutils.Serialize(r, tg, sn, ts) + root, targets, _, _, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - } + updates := []storage.MetaUpdate{root, targets} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -373,27 +237,11 @@ func TestValidateRootNoTimestampKey(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(oldRepo) assert.NoError(t, err) - root, targets, snapshot, _, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, _, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) store := storage.NewMemStorage() - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot} // sanity check - no timestamp keys for the GUN _, _, err = store.GetTimestampKey("testGUN") @@ -420,27 +268,11 @@ func TestValidateRootInvalidTimestampKey(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(oldRepo) assert.NoError(t, err) - root, targets, snapshot, _, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, _, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) store := storage.NewMemStorage() - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot} key, err := trustmanager.GenerateECDSAKey(rand.Reader) assert.NoError(t, err) @@ -452,6 +284,50 @@ func TestValidateRootInvalidTimestampKey(t *testing.T) { assert.IsType(t, ErrBadRoot{}, err) } +// If the timestamp role has a threshold > 1, validation fails. +func TestValidateRootInvalidTimestampThreshold(t *testing.T) { + kdb, oldRepo, _ := testutils.EmptyRepo() + tsRole, ok := oldRepo.Root.Signed.Roles[data.CanonicalTimestampRole] + assert.True(t, ok) + tsRole.Threshold = 2 + + r, tg, sn, ts, err := testutils.Sign(oldRepo) + assert.NoError(t, err) + root, targets, snapshot, _, err := getUpdates(r, tg, sn, ts) + assert.NoError(t, err) + + store := storage.NewMemStorage() + updates := []storage.MetaUpdate{root, targets, snapshot} + + copyTimestampKey(t, kdb, store, "testGUN") + err = validateUpdate("testGUN", updates, store) + assert.Error(t, err) + assert.Contains(t, err.Error(), "timestamp role has invalid threshold") +} + +// If any role has a threshold < 1, validation fails +func TestValidateRootInvalidZeroThreshold(t *testing.T) { + for role := range data.ValidRoles { + kdb, oldRepo, _ := testutils.EmptyRepo() + tsRole, ok := oldRepo.Root.Signed.Roles[role] + assert.True(t, ok) + tsRole.Threshold = 0 + + r, tg, sn, ts, err := testutils.Sign(oldRepo) + assert.NoError(t, err) + root, targets, snapshot, _, err := getUpdates(r, tg, sn, ts) + assert.NoError(t, err) + + store := storage.NewMemStorage() + updates := []storage.MetaUpdate{root, targets, snapshot} + + copyTimestampKey(t, kdb, store, "testGUN") + err = validateUpdate("testGUN", updates, store) + assert.Error(t, err) + assert.Contains(t, err.Error(), "role has invalid threshold") + } +} + // ### Role missing negative tests ### // These tests remove a role from the Root file and // check for a ErrBadRoot @@ -463,31 +339,10 @@ func TestValidateRootRoleMissing(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -503,31 +358,10 @@ func TestValidateTargetsRoleMissing(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -543,31 +377,10 @@ func TestValidateSnapshotRoleMissing(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -589,31 +402,10 @@ func TestValidateRootSigMissing(t *testing.T) { r.Signatures = nil - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -630,31 +422,10 @@ func TestValidateTargetsSigMissing(t *testing.T) { tg.Signatures = nil - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -671,31 +442,10 @@ func TestValidateSnapshotSigMissing(t *testing.T) { sn.Signatures = nil - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -712,34 +462,13 @@ func TestValidateRootCorrupt(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) // flip all the bits in the first byte - root[0] = root[0] ^ 0xff + root.Data[0] = root.Data[0] ^ 0xff - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -753,34 +482,13 @@ func TestValidateTargetsCorrupt(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) // flip all the bits in the first byte - targets[0] = targets[0] ^ 0xff + targets.Data[0] = targets.Data[0] ^ 0xff - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -794,34 +502,13 @@ func TestValidateSnapshotCorrupt(t *testing.T) { r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) // flip all the bits in the first byte - snapshot[0] = snapshot[0] ^ 0xff + snapshot.Data[0] = snapshot.Data[0] ^ 0xff - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -842,34 +529,13 @@ func TestValidateRootModifiedSize(t *testing.T) { // add another copy of the signature so the hash is different r.Signatures = append(r.Signatures, r.Signatures[0]) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) // flip all the bits in the first byte - root[0] = root[0] ^ 0xff + root.Data[0] = root.Data[0] ^ 0xff - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -887,31 +553,10 @@ func TestValidateTargetsModifiedSize(t *testing.T) { // add another copy of the signature so the hash is different tg.Signatures = append(tg.Signatures, tg.Signatures[0]) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -936,31 +581,10 @@ func TestValidateRootModifiedHash(t *testing.T) { sn, err = snap.ToSigned() assert.NoError(t, err) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store) @@ -982,31 +606,10 @@ func TestValidateTargetsModifiedHash(t *testing.T) { sn, err = snap.ToSigned() assert.NoError(t, err) - root, targets, snapshot, timestamp, err := testutils.Serialize(r, tg, sn, ts) + root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) - updates := []storage.MetaUpdate{ - { - Role: "root", - Version: 1, - Data: root, - }, - { - Role: "targets", - Version: 1, - Data: targets, - }, - { - Role: "snapshot", - Version: 1, - Data: snapshot, - }, - { - Role: "timestamp", - Version: 1, - Data: timestamp, - }, - } + updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, kdb, store, "testGUN") err = validateUpdate("testGUN", updates, store)