func TestGetAllRoles(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) // After we init, we get the base roles roles := repo.GetAllLoadedRoles() assert.Len(t, roles, len(data.BaseRoles)) // Clear the keysDB, check that we get an empty list repo.keysDB = keys.NewDB() roles = repo.GetAllLoadedRoles() assert.Len(t, roles, 0) }
func TestDeleteDelegationsRoleNotExistBecauseNoParentMeta(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) testKey, err := ed25519.Create("targets/test", data.ED25519Key) assert.NoError(t, err) role, err := data.NewRole("targets/test", 1, []string{testKey.ID()}, []string{"test"}, []string{}) assert.NoError(t, err) err = repo.UpdateDelegations(role, data.KeyList{testKey}) assert.NoError(t, err) // no empty delegation metadata created for new delegation _, ok := repo.Targets["targets/test"] assert.False(t, ok, "no targets file should be created for empty delegation") delRole, err := data.NewRole( "targets/test/a", 1, []string{testKey.ID()}, []string{"test"}, []string{}) err = repo.DeleteDelegation(*delRole) assert.NoError(t, err) // still no metadata _, ok = repo.Targets["targets/test"] assert.False(t, ok) }
func TestRotationNewSigMissing(t *testing.T) { logrus.SetLevel(logrus.DebugLevel) kdb := keys.NewDB() signer := signed.NewEd25519() repo := tuf.NewRepo(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.") }
// A delegation can be created with a role that is missing a signing key, so // long as UpdateDelegations is called with the key func TestUpdateDelegationsRoleThatIsMissingDelegationKey(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) roleKey, err := ed25519.Create("Invalid Role", data.ED25519Key) assert.NoError(t, err) role, err := data.NewRole("targets/role", 1, []string{}, []string{""}, []string{}) assert.NoError(t, err) // key should get added to role as part of updating the delegation err = repo.UpdateDelegations(role, data.KeyList{roleKey}) assert.NoError(t, err) r, ok := repo.Targets[data.CanonicalTargetsRole] assert.True(t, ok) assert.Len(t, r.Signed.Delegations.Roles, 1) assert.Len(t, r.Signed.Delegations.Keys, 1) keyIDs := r.Signed.Delegations.Roles[0].KeyIDs assert.Len(t, keyIDs, 1) assert.Equal(t, roleKey.ID(), keyIDs[0]) assert.True(t, r.Dirty) // no empty delegation metadata created for new delegation _, ok = repo.Targets["targets/role"] assert.False(t, ok, "no targets file should be created for empty delegation") }
func TestDeleteDelegationsMidSliceRole(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) testKey, err := ed25519.Create("targets/test", data.ED25519Key) assert.NoError(t, err) role, err := data.NewRole("targets/test", 1, []string{}, []string{""}, []string{}) assert.NoError(t, err) err = repo.UpdateDelegations(role, data.KeyList{testKey}) assert.NoError(t, err) role2, err := data.NewRole("targets/test2", 1, []string{}, []string{""}, []string{}) assert.NoError(t, err) err = repo.UpdateDelegations(role2, data.KeyList{testKey}) assert.NoError(t, err) role3, err := data.NewRole("targets/test3", 1, []string{}, []string{""}, []string{}) assert.NoError(t, err) err = repo.UpdateDelegations(role3, data.KeyList{testKey}) assert.NoError(t, err) err = repo.DeleteDelegation(*role2) assert.NoError(t, err) r, ok := repo.Targets[data.CanonicalTargetsRole] assert.True(t, ok) assert.Len(t, r.Signed.Delegations.Roles, 2) assert.Len(t, r.Signed.Delegations.Keys, 1) assert.True(t, r.Dirty) }
func TestUpdateDelegationsInvalidRole(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) roleKey, err := ed25519.Create("Invalid Role", data.ED25519Key) assert.NoError(t, err) // data.NewRole errors if the role isn't a valid TUF role so use one of the non-delegation // valid roles invalidRole, err := data.NewRole("root", 1, []string{roleKey.ID()}, []string{}, []string{}) assert.NoError(t, err) err = repo.UpdateDelegations(invalidRole, data.KeyList{roleKey}) assert.Error(t, err) assert.IsType(t, data.ErrInvalidRole{}, err) r, ok := repo.Targets[data.CanonicalTargetsRole] assert.True(t, ok) assert.Len(t, r.Signed.Delegations.Roles, 0) // no delegation metadata created for invalid delgation _, ok = repo.Targets["root"] assert.False(t, ok, "no targets file should be created since delegation failed") }
// Adding targets to a role that we don't have signing keys for fails func TestAddTargetsNoSigningKeys(t *testing.T) { hash := sha256.Sum256([]byte{}) f := data.FileMeta{ Length: 1, Hashes: map[string][]byte{ "sha256": hash[:], }, } ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) testKey, err := ed25519.Create("targets/test", data.ED25519Key) assert.NoError(t, err) role, err := data.NewRole( "targets/test", 1, []string{testKey.ID()}, []string{"test"}, []string{}) assert.NoError(t, err) err = repo.UpdateDelegations(role, data.KeyList{testKey}) assert.NoError(t, err) // now delete the signing key (all keys) repo.cryptoService = signed.NewEd25519() // adding the targets to the role should create the metadata though _, err = repo.AddTargets("targets/test", data.Files{"f": f}) assert.Error(t, err) assert.IsType(t, signed.ErrNoKeys{}, err) }
// we require that at least the base targets role is available when creating // initializing a snapshot func TestInitSnapshotNoTargets(t *testing.T) { cryptoService := signed.NewEd25519() keyDB := keys.NewDB() rootKey, err := cryptoService.Create("root", data.ED25519Key) assert.NoError(t, err) snapshotKey, err := cryptoService.Create("snapshot", data.ED25519Key) assert.NoError(t, err) keyDB.AddKey(rootKey) keyDB.AddKey(snapshotKey) rootRole := &data.Role{ Name: "root", RootRole: data.RootRole{ KeyIDs: []string{rootKey.ID()}, Threshold: 1, }, } snapshotRole := &data.Role{ Name: "snapshot", RootRole: data.RootRole{ KeyIDs: []string{snapshotKey.ID()}, Threshold: 1, }, } keyDB.AddRole(rootRole) keyDB.AddRole(snapshotRole) repo := NewRepo(keyDB, cryptoService) err = repo.InitSnapshot() assert.Error(t, err) assert.IsType(t, ErrNotLoaded{}, err) }
// Removing targets from a role that exists, has targets, and is signable // should succeed, even if we also want to remove targets that don't exist. func TestRemoveExistingAndNonexistingTargets(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) testKey, err := ed25519.Create("targets/test", data.ED25519Key) assert.NoError(t, err) role, err := data.NewRole( "targets/test", 1, []string{testKey.ID()}, []string{"test"}, []string{}) assert.NoError(t, err) err = repo.UpdateDelegations(role, data.KeyList{testKey}) assert.NoError(t, err) // no empty metadata is created for this role _, ok := repo.Targets["targets/test"] assert.False(t, ok, "no empty targets file should be created") // now remove a target assert.NoError(t, repo.RemoveTargets("targets/test", "f")) // still no metadata _, ok = repo.Targets["targets/test"] assert.False(t, ok) }
// adding a key to a role marks root as dirty as well as the role func TestAddBaseKeysToRoot(t *testing.T) { for _, role := range data.BaseRoles { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) key, err := ed25519.Create(role, data.ED25519Key) assert.NoError(t, err) assert.Len(t, repo.Root.Signed.Roles[role].KeyIDs, 1) assert.NoError(t, repo.AddBaseKeys(role, key)) _, ok := repo.Root.Signed.Keys[key.ID()] assert.True(t, ok) assert.Len(t, repo.Root.Signed.Roles[role].KeyIDs, 2) assert.True(t, repo.Root.Dirty) switch role { case data.CanonicalSnapshotRole: assert.True(t, repo.Snapshot.Dirty) case data.CanonicalTargetsRole: assert.True(t, repo.Targets[data.CanonicalTargetsRole].Dirty) case data.CanonicalTimestampRole: assert.True(t, repo.Timestamp.Dirty) } } }
func TestDuplicateSigs(t *testing.T) { cs := NewEd25519() k, err := cs.Create("root", data.ED25519Key) assert.NoError(t, err) r, err := data.NewRole( "root", 2, []string{k.ID()}, nil, nil, ) assert.NoError(t, err) db := keys.NewDB() assert.NoError(t, err) db.AddKey(k) err = db.AddRole(r) assert.NoError(t, err) meta := &data.SignedCommon{Type: "Root", Version: 1, Expires: data.DefaultExpires("root")} b, err := json.MarshalCanonical(meta) assert.NoError(t, err) s := &data.Signed{Signed: b} Sign(cs, s, k) s.Signatures = append(s.Signatures, s.Signatures[0]) err = Verify(s, "root", 1, db) assert.IsType(t, ErrRoleThreshold{}, err) }
func TestMoreThanEnoughSigs(t *testing.T) { cs := NewEd25519() k1, err := cs.Create("root", data.ED25519Key) assert.NoError(t, err) k2, err := cs.Create("root", data.ED25519Key) assert.NoError(t, err) r, err := data.NewRole( "root", 1, []string{k1.ID(), k2.ID()}, nil, nil, ) assert.NoError(t, err) db := keys.NewDB() assert.NoError(t, err) db.AddKey(k1) db.AddKey(k2) err = db.AddRole(r) assert.NoError(t, err) meta := &data.SignedCommon{Type: "Root", Version: 1, Expires: data.DefaultExpires("root")} b, err := json.MarshalCanonical(meta) assert.NoError(t, err) s := &data.Signed{Signed: b} Sign(cs, s, k1, k2) assert.Equal(t, 2, len(s.Signatures)) err = Verify(s, "root", 1, db) assert.NoError(t, err) }
func TestUpdateDelegations(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) testKey, err := ed25519.Create("targets/test", data.ED25519Key) if err != nil { t.Fatal(err) } role, err := data.NewRole("targets/test", 1, []string{testKey.ID()}, []string{"test"}, []string{}) if err != nil { t.Fatal(err) } err = repo.UpdateDelegations(role, data.KeyList{testKey}, "") if err != nil { t.Fatal(err) } testDeepKey, err := ed25519.Create("targets/test/deep", data.ED25519Key) if err != nil { t.Fatal(err) } roleDeep, err := data.NewRole("targets/test/deep", 1, []string{testDeepKey.ID()}, []string{"test/deep"}, []string{}) if err != nil { t.Fatal(err) } err = repo.UpdateDelegations(roleDeep, data.KeyList{testDeepKey}, "") if err != nil { t.Fatal(err) } writeRepo(t, "/tmp/tufdelegation", repo) }
func (r *NotaryRepository) bootstrapClient() (*tufclient.Client, error) { var rootJSON []byte remote, err := getRemoteStore(r.baseURL, r.gun, r.roundTrip) if err == nil { // if remote store successfully set up, try and get root from remote rootJSON, err = remote.GetMeta("root", maxSize) } // 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 { 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 } result, cacheErr := r.fileStore.GetMeta("root", maxSize) if cacheErr != nil { // if cache didn't return a root, we cannot proceed - just return // the original error. return nil, err } rootJSON = result logrus.Debugf( "Using local cache instead of remote due to failure: %s", err.Error()) } // can't just unmarshal into SignedRoot because validate root // needs the root.Signed field to still be []byte for signature // validation root := &data.Signed{} err = json.Unmarshal(rootJSON, root) if err != nil { return nil, err } err = r.CertManager.ValidateRoot(root, r.gun) if err != nil { return nil, err } kdb := keys.NewDB() r.tufRepo = tuf.NewRepo(kdb, r.CryptoService) signedRoot, err := data.RootFromSigned(root) if err != nil { return nil, err } err = r.tufRepo.SetRoot(signedRoot) if err != nil { return nil, err } return tufclient.NewClient( r.tufRepo, remote, kdb, r.fileStore, ), nil }
func TestValidateTargetsParentInUpdate(t *testing.T) { _, baseRepo, cs, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) store := storage.NewMemStorage() k, err := cs.Create("targets/level1", data.ED25519Key) assert.NoError(t, err) r, err := data.NewRole("targets/level1", 1, []string{k.ID()}, []string{""}, nil) assert.NoError(t, err) baseRepo.UpdateDelegations(r, []data.PublicKey{k}) // no targets file is created for the new delegations, so force one baseRepo.InitTargets("targets/level1") targets, err := baseRepo.SignTargets("targets", data.DefaultExpires(data.CanonicalTargetsRole)) tgtsJSON, err := json.Marshal(targets) assert.NoError(t, err) update := storage.MetaUpdate{ Role: data.CanonicalTargetsRole, Version: 1, Data: tgtsJSON, } store.UpdateCurrent("gun", update) del, err := baseRepo.SignTargets("targets/level1", data.DefaultExpires(data.CanonicalTargetsRole)) assert.NoError(t, err) delJSON, err := json.Marshal(del) assert.NoError(t, err) delUpdate := storage.MetaUpdate{ Role: "targets/level1", Version: 1, Data: delJSON, } roles := map[string]storage.MetaUpdate{ "targets/level1": delUpdate, "targets": update, } kdb := keys.NewDB() valRepo := tuf.NewRepo(kdb, nil) valRepo.SetRoot(baseRepo.Root) // because we sort the roles, the list of returned updates // will contain shallower roles first, in this case "targets", // and then "targets/level1" updates, err := loadAndValidateTargets("gun", valRepo, roles, kdb, store) assert.NoError(t, err) assert.Len(t, updates, 2) assert.Equal(t, "targets", updates[0].Role) assert.Equal(t, tgtsJSON, updates[0].Data) assert.Equal(t, "targets/level1", updates[1].Role) assert.Equal(t, delJSON, updates[1].Data) }
// Removing targets from a role that doesn't exist fails func TestRemoveTargetsRoleDoesntExist(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) err := repo.RemoveTargets("targets/test", "f") assert.Error(t, err) assert.IsType(t, data.ErrInvalidRole{}, err) }
// If the parent role doesn't exist, GetDelegation fails with an ErrInvalidRole func TestGetDelegationParentMissing(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) _, _, err := repo.GetDelegation("targets/level1/level2") assert.Error(t, err) assert.IsType(t, data.ErrInvalidRole{}, err) }
func TestValidateTargetsRoleNotInParent(t *testing.T) { kdb, baseRepo, cs := testutils.EmptyRepo() store := storage.NewMemStorage() k, err := cs.Create("targets/level1", data.ED25519Key) assert.NoError(t, err) r, err := data.NewRole("targets/level1", 1, []string{k.ID()}, []string{""}, nil) assert.NoError(t, err) kdb.AddKey(k) err = kdb.AddRole(r) assert.NoError(t, err) baseRepo.InitTargets("targets/level1") targets, err := baseRepo.SignTargets("targets", data.DefaultExpires(data.CanonicalTargetsRole)) tgtsJSON, err := json.MarshalCanonical(targets) assert.NoError(t, err) update := storage.MetaUpdate{ Role: data.CanonicalTargetsRole, Version: 1, Data: tgtsJSON, } store.UpdateCurrent("gun", update) del, err := baseRepo.SignTargets("targets/level1", data.DefaultExpires(data.CanonicalTargetsRole)) assert.NoError(t, err) delJSON, err := json.MarshalCanonical(del) assert.NoError(t, err) delUpdate := storage.MetaUpdate{ Role: "targets/level1", Version: 1, Data: delJSON, } roles := map[string]storage.MetaUpdate{ "targets/level1": delUpdate, "targets": update, } kdb = keys.NewDB() valRepo := tuf.NewRepo(kdb, nil) valRepo.SetRoot(baseRepo.Root) // because we sort the roles, the list of returned updates // will contain shallower roles first, in this case "targets", // and then "targets/level1" updates, err := loadAndValidateTargets("gun", valRepo, roles, kdb, store) assert.NoError(t, err) assert.Len(t, updates, 1) assert.Equal(t, "targets", updates[0].Role) assert.Equal(t, tgtsJSON, updates[0].Data) }
func TestUpdateDelegationsReplaceRole(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) testKey, err := ed25519.Create("targets/test", data.ED25519Key) assert.NoError(t, err) role, err := data.NewRole("targets/test", 1, []string{testKey.ID()}, []string{"test"}, []string{}) assert.NoError(t, err) err = repo.UpdateDelegations(role, data.KeyList{testKey}) assert.NoError(t, err) r, ok := repo.Targets[data.CanonicalTargetsRole] assert.True(t, ok) assert.Len(t, r.Signed.Delegations.Roles, 1) assert.Len(t, r.Signed.Delegations.Keys, 1) keyIDs := r.Signed.Delegations.Roles[0].KeyIDs assert.Len(t, keyIDs, 1) assert.Equal(t, testKey.ID(), keyIDs[0]) // no empty delegation metadata created for new delegation _, ok = repo.Targets["targets/test"] assert.False(t, ok, "no targets file should be created for empty delegation") // create one now to assert that replacing the delegation doesn't delete the // metadata repo.InitTargets("targets/test") // create another role with the same name and ensure it replaces the // previous role testKey2, err := ed25519.Create("targets/test", data.ED25519Key) assert.NoError(t, err) role2, err := data.NewRole("targets/test", 1, []string{testKey2.ID()}, []string{"test"}, []string{}) assert.NoError(t, err) err = repo.UpdateDelegations(role2, data.KeyList{testKey2}) assert.NoError(t, err) r, ok = repo.Targets["targets"] assert.True(t, ok) assert.Len(t, r.Signed.Delegations.Roles, 1) assert.Len(t, r.Signed.Delegations.Keys, 1) keyIDs = r.Signed.Delegations.Roles[0].KeyIDs assert.Len(t, keyIDs, 1) assert.Equal(t, testKey2.ID(), keyIDs[0]) assert.True(t, r.Dirty) // delegation was not deleted _, ok = repo.Targets["targets/test"] assert.True(t, ok, "targets file should still be here") }
func TestValidateTargetsLoadParent(t *testing.T) { _, baseRepo, cs, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) store := storage.NewMemStorage() k, err := cs.Create("targets/level1", data.ED25519Key) assert.NoError(t, err) r, err := data.NewRole("targets/level1", 1, []string{k.ID()}, []string{""}, nil) assert.NoError(t, err) err = baseRepo.UpdateDelegations(r, []data.PublicKey{k}) assert.NoError(t, err) // no targets file is created for the new delegations, so force one baseRepo.InitTargets("targets/level1") // we're not going to validate things loaded from storage, so no need // to sign the base targets, just Marshal it and set it into storage tgtsJSON, err := json.Marshal(baseRepo.Targets["targets"]) assert.NoError(t, err) update := storage.MetaUpdate{ Role: data.CanonicalTargetsRole, Version: 1, Data: tgtsJSON, } store.UpdateCurrent("gun", update) // generate the update object we're doing to use to call loadAndValidateTargets del, err := baseRepo.SignTargets("targets/level1", data.DefaultExpires(data.CanonicalTargetsRole)) assert.NoError(t, err) delJSON, err := json.Marshal(del) assert.NoError(t, err) delUpdate := storage.MetaUpdate{ Role: "targets/level1", Version: 1, Data: delJSON, } roles := map[string]storage.MetaUpdate{"targets/level1": delUpdate} kdb := keys.NewDB() valRepo := tuf.NewRepo(kdb, nil) valRepo.SetRoot(baseRepo.Root) updates, err := loadAndValidateTargets("gun", valRepo, roles, kdb, store) assert.NoError(t, err) assert.Len(t, updates, 1) assert.Equal(t, "targets/level1", updates[0].Role) assert.Equal(t, delJSON, updates[0].Data) }
// EmptyRepo creates an in memory key database, crypto service // and initializes a repo with no targets or delegations. func EmptyRepo() (*keys.KeyDB, *tuf.Repo, signed.CryptoService) { c := signed.NewEd25519() kdb := keys.NewDB() r := tuf.NewRepo(kdb, c) for _, role := range []string{"root", "targets", "snapshot", "timestamp"} { key, _ := c.Create(role, data.ED25519Key) role, _ := data.NewRole(role, 1, []string{key.ID()}, nil, nil) kdb.AddKey(key) kdb.AddRole(role) } r.InitRepo(false) return kdb, r, c }
func TestUpdateDelegations(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) testKey, err := ed25519.Create("targets/test", data.ED25519Key) assert.NoError(t, err) role, err := data.NewRole("targets/test", 1, []string{testKey.ID()}, []string{"test"}, []string{}) assert.NoError(t, err) err = repo.UpdateDelegations(role, data.KeyList{testKey}) assert.NoError(t, err) // no empty metadata is created for this role _, ok := repo.Targets["targets/test"] assert.False(t, ok, "no empty targets file should be created for deepest delegation") r, ok := repo.Targets[data.CanonicalTargetsRole] assert.True(t, ok) assert.Len(t, r.Signed.Delegations.Roles, 1) assert.Len(t, r.Signed.Delegations.Keys, 1) keyIDs := r.Signed.Delegations.Roles[0].KeyIDs assert.Len(t, keyIDs, 1) assert.Equal(t, testKey.ID(), keyIDs[0]) testDeepKey, err := ed25519.Create("targets/test/deep", data.ED25519Key) assert.NoError(t, err) roleDeep, err := data.NewRole("targets/test/deep", 1, []string{testDeepKey.ID()}, []string{"test/deep"}, []string{}) assert.NoError(t, err) err = repo.UpdateDelegations(roleDeep, data.KeyList{testDeepKey}) assert.NoError(t, err) // this metadata didn't exist before, but creating targets/test/deep created // the targets/test metadata r, ok = repo.Targets["targets/test"] assert.True(t, ok) assert.Len(t, r.Signed.Delegations.Roles, 1) assert.Len(t, r.Signed.Delegations.Keys, 1) keyIDs = r.Signed.Delegations.Roles[0].KeyIDs assert.Len(t, keyIDs, 1) assert.Equal(t, testDeepKey.ID(), keyIDs[0]) assert.True(t, r.Dirty) // no empty delegation metadata is created for targets/test/deep _, ok = repo.Targets["targets/test/deep"] assert.False(t, ok, "no empty targets file should be created for deepest delegation") }
func TestDeleteDelegationsParentMissing(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) testRole, err := data.NewRole("targets/test/deep", 1, []string{}, []string{""}, []string{}) assert.NoError(t, err) err = repo.DeleteDelegation(*testRole) assert.Error(t, err) assert.IsType(t, data.ErrInvalidRole{}, err) r, ok := repo.Targets[data.CanonicalTargetsRole] assert.True(t, ok) assert.Len(t, r.Signed.Delegations.Roles, 0) }
// This changes the root key func TestSwizzlerChangeRootKey(t *testing.T) { f, origMeta := createNewSwizzler(t) f.ChangeRootKey() kdb := keys.NewDB() tufRepo := tuf.NewRepo(kdb, f.CryptoService) // we want to test these in a specific order roles := []string{data.CanonicalRootRole, data.CanonicalTargetsRole, data.CanonicalSnapshotRole, data.CanonicalTimestampRole, "targets/a", "targets/a/b"} for _, role := range roles { origMeta := origMeta[role] newMeta, err := f.MetadataCache.GetMeta(role, -1) require.NoError(t, err) // the threshold for base roles is set in root switch role { case data.CanonicalRootRole: require.False(t, bytes.Equal(origMeta, newMeta)) origRoot, newRoot := &data.SignedRoot{}, &data.SignedRoot{} require.NoError(t, json.Unmarshal(origMeta, origRoot)) require.NoError(t, json.Unmarshal(newMeta, newRoot)) require.NotEqual(t, len(origRoot.Signed.Keys), len(newRoot.Signed.Keys)) for r, origRole := range origRoot.Signed.Roles { newRole := newRoot.Signed.Roles[r] require.Len(t, origRole.KeyIDs, 1) require.Len(t, newRole.KeyIDs, 1) if r == data.CanonicalRootRole { require.NotEqual(t, origRole.KeyIDs[0], newRole.KeyIDs[0]) } else { require.Equal(t, origRole.KeyIDs[0], newRole.KeyIDs[0]) } } require.NoError(t, tufRepo.SetRoot(newRoot)) signedThing, err := newRoot.ToSigned() require.NoError(t, err) require.NoError(t, signed.Verify(signedThing, data.CanonicalRootRole, 1, kdb)) default: require.True(t, bytes.Equal(origMeta, newMeta), "bytes have changed for role %s", role) } } }
func TestApplyChangelist(t *testing.T) { kdb := keys.NewDB() role, err := data.NewRole("targets", 1, nil, nil, nil) assert.NoError(t, err) kdb.AddRole(role) repo := tuf.NewRepo(kdb, nil) err = repo.InitTargets() assert.NoError(t, err) hash := sha256.Sum256([]byte{}) f := &data.FileMeta{ Length: 1, Hashes: map[string][]byte{ "sha256": hash[:], }, } fjson, err := json.Marshal(f) assert.NoError(t, err) cl := changelist.NewMemChangelist() addChange := &changelist.TufChange{ Actn: changelist.ActionCreate, Role: changelist.ScopeTargets, ChangeType: "target", ChangePath: "latest", Data: fjson, } cl.Add(addChange) err = applyChangelist(repo, cl) assert.NoError(t, err) assert.NotNil(t, repo.Targets["targets"].Signed.Targets["latest"]) cl.Clear("") removeChange := &changelist.TufChange{ Actn: changelist.ActionDelete, Role: changelist.ScopeTargets, ChangeType: "target", ChangePath: "latest", Data: nil, } cl.Add(removeChange) err = applyChangelist(repo, cl) assert.NoError(t, err) _, ok := repo.Targets["targets"].Signed.Targets["latest"] assert.False(t, ok) }
// Adding targets to a role that doesn't exist fails func TestAddTargetsRoleDoesntExist(t *testing.T) { hash := sha256.Sum256([]byte{}) f := data.FileMeta{ Length: 1, Hashes: map[string][]byte{ "sha256": hash[:], }, } ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) _, err := repo.AddTargets("targets/test", data.Files{"f": f}) assert.Error(t, err) assert.IsType(t, data.ErrInvalidRole{}, err) }
// Can't delete a delegation if we don't have the parent's signing key func TestDeleteDelegationsMissingParentSigningKey(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) testKey, err := ed25519.Create("targets/test", data.ED25519Key) assert.NoError(t, err) role, err := data.NewRole("targets/test", 1, []string{testKey.ID()}, []string{"test"}, []string{}) assert.NoError(t, err) err = repo.UpdateDelegations(role, data.KeyList{testKey}) assert.NoError(t, err) r, ok := repo.Targets[data.CanonicalTargetsRole] assert.True(t, ok) assert.Len(t, r.Signed.Delegations.Roles, 1) assert.Len(t, r.Signed.Delegations.Keys, 1) keyIDs := r.Signed.Delegations.Roles[0].KeyIDs assert.Len(t, keyIDs, 1) assert.Equal(t, testKey.ID(), keyIDs[0]) // ensure that the metadata is there and snapshot is there targets, err := repo.InitTargets("targets/test") assert.NoError(t, err) targetsSigned, err := targets.ToSigned() assert.NoError(t, err) assert.NoError(t, repo.UpdateSnapshot("targets/test", targetsSigned)) _, ok = repo.Snapshot.Signed.Meta["targets/test"] assert.True(t, ok) // delete all signing keys repo.cryptoService = signed.NewEd25519() err = repo.DeleteDelegation(*role) assert.Error(t, err) assert.IsType(t, signed.ErrNoKeys{}, err) assert.Len(t, r.Signed.Delegations.Roles, 1) assert.Len(t, r.Signed.Delegations.Keys, 1) assert.True(t, r.Dirty) // metadata should be here still _, ok = repo.Targets["targets/test"] assert.True(t, ok) _, ok = repo.Snapshot.Signed.Meta["targets/test"] assert.True(t, ok) }
// bootstrapRepo loads the repository from the local file system. This attempts // to load metadata for all roles. Since server snapshots are supported, // if the snapshot metadata fails to load, that's ok. // This can also be unified with some cache reading tools from tuf/client. // This assumes that bootstrapRepo is only used by Publish() func (r *NotaryRepository) bootstrapRepo() error { kdb := keys.NewDB() tufRepo := tuf.NewRepo(kdb, r.CryptoService) logrus.Debugf("Loading trusted collection.") rootJSON, err := r.fileStore.GetMeta("root", 0) if err != nil { return err } root := &data.SignedRoot{} err = json.Unmarshal(rootJSON, root) if err != nil { return err } err = tufRepo.SetRoot(root) if err != nil { return err } targetsJSON, err := r.fileStore.GetMeta("targets", 0) if err != nil { return err } targets := &data.SignedTargets{} err = json.Unmarshal(targetsJSON, targets) if err != nil { return err } tufRepo.SetTargets("targets", targets) snapshotJSON, err := r.fileStore.GetMeta("snapshot", 0) if err == nil { snapshot := &data.SignedSnapshot{} err = json.Unmarshal(snapshotJSON, snapshot) if err != nil { return err } tufRepo.SetSnapshot(snapshot) } else if _, ok := err.(store.ErrMetaNotFound); !ok { return err } r.tufRepo = tufRepo return nil }
func TestDeleteDelegationsInvalidRole(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) // data.NewRole errors if the role isn't a valid TUF role so use one of the non-delegation // valid roles invalidRole, err := data.NewRole("root", 1, []string{}, []string{""}, []string{}) assert.NoError(t, err) err = repo.DeleteDelegation(*invalidRole) assert.Error(t, err) assert.IsType(t, data.ErrInvalidRole{}, err) r, ok := repo.Targets[data.CanonicalTargetsRole] assert.True(t, ok) assert.Len(t, r.Signed.Delegations.Roles, 0) }
func TestUpdateDelegationsNotEnoughKeys(t *testing.T) { ed25519 := signed.NewEd25519() keyDB := keys.NewDB() repo := initRepo(t, ed25519, keyDB) roleKey, err := ed25519.Create("Invalid Role", data.ED25519Key) assert.NoError(t, err) role, err := data.NewRole("targets/role", 2, []string{}, []string{""}, []string{}) assert.NoError(t, err) err = repo.UpdateDelegations(role, data.KeyList{roleKey}) assert.Error(t, err) assert.IsType(t, data.ErrInvalidRole{}, err) // no delegation metadata created for failed delegation _, ok := repo.Targets["targets/role"] assert.False(t, ok, "no targets file should be created since delegation failed") }