mirror of https://github.com/docker/docs.git
Merge pull request #555 from docker/remove-kdb-from-verify
Remove keyDB from signed.Verify
This commit is contained in:
commit
b673a15a49
|
@ -79,7 +79,7 @@ func validateUpdate(cs signed.CryptoService, gun string, updates []storage.MetaU
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
targetsToUpdate, err := loadAndValidateTargets(gun, repo, roles, kdb, store)
|
targetsToUpdate, err := loadAndValidateTargets(gun, repo, roles, store)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ func validateUpdate(cs signed.CryptoService, gun string, updates []storage.MetaU
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateSnapshot(snapshotRole, oldSnap, roles[snapshotRole], roles, kdb); err != nil {
|
if err := validateSnapshot(snapshotRole, oldSnap, roles[snapshotRole], roles, repo); err != nil {
|
||||||
logrus.Error("ErrBadSnapshot: ", err.Error())
|
logrus.Error("ErrBadSnapshot: ", err.Error())
|
||||||
return nil, validation.ErrBadSnapshot{Msg: err.Error()}
|
return nil, validation.ErrBadSnapshot{Msg: err.Error()}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ func validateUpdate(cs signed.CryptoService, gun string, updates []storage.MetaU
|
||||||
// Then:
|
// Then:
|
||||||
// - generate a new snapshot
|
// - generate a new snapshot
|
||||||
// - add it to the updates
|
// - add it to the updates
|
||||||
update, err := generateSnapshot(gun, kdb, repo, store)
|
update, err := generateSnapshot(gun, repo, store)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ func validateUpdate(cs signed.CryptoService, gun string, updates []storage.MetaU
|
||||||
return updatesToApply, nil
|
return updatesToApply, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadAndValidateTargets(gun string, repo *tuf.Repo, roles map[string]storage.MetaUpdate, kdb *keys.KeyDB, store storage.MetaStore) ([]storage.MetaUpdate, error) {
|
func loadAndValidateTargets(gun string, repo *tuf.Repo, roles map[string]storage.MetaUpdate, store storage.MetaStore) ([]storage.MetaUpdate, error) {
|
||||||
targetsRoles := make(utils.RoleList, 0)
|
targetsRoles := make(utils.RoleList, 0)
|
||||||
for role := range roles {
|
for role := range roles {
|
||||||
if role == data.CanonicalTargetsRole || data.IsDelegation(role) {
|
if role == data.CanonicalTargetsRole || data.IsDelegation(role) {
|
||||||
|
@ -160,8 +160,8 @@ func loadAndValidateTargets(gun string, repo *tuf.Repo, roles map[string]storage
|
||||||
t *data.SignedTargets
|
t *data.SignedTargets
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if t, err = validateTargets(role, roles, kdb); err != nil {
|
if t, err = validateTargets(role, roles, repo); err != nil {
|
||||||
if err == signed.ErrUnknownRole {
|
if _, ok := err.(tuf.ErrNotLoaded); ok {
|
||||||
// role wasn't found in its parent. It has been removed
|
// role wasn't found in its parent. It has been removed
|
||||||
// or never existed. Drop this role from the update
|
// or never existed. Drop this role from the update
|
||||||
// (by not adding it to updatesToApply)
|
// (by not adding it to updatesToApply)
|
||||||
|
@ -193,9 +193,9 @@ func loadTargetsFromStore(gun, role string, repo *tuf.Repo, store storage.MetaSt
|
||||||
return repo.SetTargets(role, t)
|
return repo.SetTargets(role, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateSnapshot(gun string, kdb *keys.KeyDB, repo *tuf.Repo, store storage.MetaStore) (*storage.MetaUpdate, error) {
|
func generateSnapshot(gun string, repo *tuf.Repo, store storage.MetaStore) (*storage.MetaUpdate, error) {
|
||||||
role := kdb.GetRole(data.CanonicalSnapshotRole)
|
role, err := repo.GetRoleWithKeys(data.CanonicalSnapshotRole)
|
||||||
if role == nil {
|
if err != nil {
|
||||||
return nil, validation.ErrBadRoot{Msg: "root did not include snapshot role"}
|
return nil, validation.ErrBadRoot{Msg: "root did not include snapshot role"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,7 +257,7 @@ func generateSnapshot(gun string, kdb *keys.KeyDB, repo *tuf.Repo, store storage
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateSnapshot(role string, oldSnap *data.SignedSnapshot, snapUpdate storage.MetaUpdate, roles map[string]storage.MetaUpdate, kdb *keys.KeyDB) error {
|
func validateSnapshot(role string, oldSnap *data.SignedSnapshot, snapUpdate storage.MetaUpdate, roles map[string]storage.MetaUpdate, repo *tuf.Repo) error {
|
||||||
s := &data.Signed{}
|
s := &data.Signed{}
|
||||||
err := json.Unmarshal(snapUpdate.Data, s)
|
err := json.Unmarshal(snapUpdate.Data, s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -265,7 +265,11 @@ func validateSnapshot(role string, oldSnap *data.SignedSnapshot, snapUpdate stor
|
||||||
}
|
}
|
||||||
// version specifically gets validated when writing to store to
|
// version specifically gets validated when writing to store to
|
||||||
// better handle race conditions there.
|
// better handle race conditions there.
|
||||||
if err := signed.Verify(s, role, 0, kdb); err != nil {
|
snapshotRole, err := repo.GetRoleWithKeys(role)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := signed.Verify(s, snapshotRole, 0); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,7 +319,7 @@ func checkHashes(meta data.FileMeta, update []byte) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateTargets(role string, roles map[string]storage.MetaUpdate, kdb *keys.KeyDB) (*data.SignedTargets, error) {
|
func validateTargets(role string, roles map[string]storage.MetaUpdate, repo *tuf.Repo) (*data.SignedTargets, error) {
|
||||||
// TODO: when delegations are being validated, validate parent
|
// TODO: when delegations are being validated, validate parent
|
||||||
// role exists for any delegation
|
// role exists for any delegation
|
||||||
s := &data.Signed{}
|
s := &data.Signed{}
|
||||||
|
@ -325,7 +329,11 @@ func validateTargets(role string, roles map[string]storage.MetaUpdate, kdb *keys
|
||||||
}
|
}
|
||||||
// version specifically gets validated when writing to store to
|
// version specifically gets validated when writing to store to
|
||||||
// better handle race conditions there.
|
// better handle race conditions there.
|
||||||
if err := signed.Verify(s, role, 0, kdb); err != nil {
|
targetsRole, err := repo.GetRoleWithKeys(role)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := signed.Verify(s, targetsRole, 0); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t, err := data.TargetsFromSigned(s)
|
t, err := data.TargetsFromSigned(s)
|
||||||
|
|
|
@ -270,11 +270,10 @@ func TestValidateSnapshotGenerateWithPrev(t *testing.T) {
|
||||||
kdb, repo, cs, err := testutils.EmptyRepo("docker.com/notary")
|
kdb, repo, cs, err := testutils.EmptyRepo("docker.com/notary")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
store := storage.NewMemStorage()
|
store := storage.NewMemStorage()
|
||||||
snapRole := kdb.GetRole(data.CanonicalSnapshotRole)
|
snapRole, err := repo.GetRoleWithKeys(data.CanonicalSnapshotRole)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
for _, id := range snapRole.KeyIDs {
|
for _, k := range snapRole.Keys {
|
||||||
k := kdb.GetKey(id)
|
|
||||||
assert.NotNil(t, k)
|
|
||||||
err := store.SetKey("testGUN", data.CanonicalSnapshotRole, k.Algorithm(), k.Public())
|
err := store.SetKey("testGUN", data.CanonicalSnapshotRole, k.Algorithm(), k.Public())
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -311,11 +310,10 @@ func TestValidateSnapshotGeneratePrevCorrupt(t *testing.T) {
|
||||||
kdb, repo, cs, err := testutils.EmptyRepo("docker.com/notary")
|
kdb, repo, cs, err := testutils.EmptyRepo("docker.com/notary")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
store := storage.NewMemStorage()
|
store := storage.NewMemStorage()
|
||||||
snapRole := kdb.GetRole(data.CanonicalSnapshotRole)
|
snapRole, err := repo.GetRoleWithKeys(data.CanonicalSnapshotRole)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
for _, id := range snapRole.KeyIDs {
|
for _, k := range snapRole.Keys {
|
||||||
k := kdb.GetKey(id)
|
|
||||||
assert.NotNil(t, k)
|
|
||||||
err := store.SetKey("testGUN", data.CanonicalSnapshotRole, k.Algorithm(), k.Public())
|
err := store.SetKey("testGUN", data.CanonicalSnapshotRole, k.Algorithm(), k.Public())
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -342,11 +340,10 @@ func TestValidateSnapshotGenerateNoTargets(t *testing.T) {
|
||||||
kdb, repo, cs, err := testutils.EmptyRepo("docker.com/notary")
|
kdb, repo, cs, err := testutils.EmptyRepo("docker.com/notary")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
store := storage.NewMemStorage()
|
store := storage.NewMemStorage()
|
||||||
snapRole := kdb.GetRole(data.CanonicalSnapshotRole)
|
snapRole, err := repo.GetRoleWithKeys(data.CanonicalSnapshotRole)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
for _, id := range snapRole.KeyIDs {
|
for _, k := range snapRole.Keys {
|
||||||
k := kdb.GetKey(id)
|
|
||||||
assert.NotNil(t, k)
|
|
||||||
err := store.SetKey("testGUN", data.CanonicalSnapshotRole, k.Algorithm(), k.Public())
|
err := store.SetKey("testGUN", data.CanonicalSnapshotRole, k.Algorithm(), k.Public())
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -367,11 +364,10 @@ func TestValidateSnapshotGenerate(t *testing.T) {
|
||||||
kdb, repo, cs, err := testutils.EmptyRepo("docker.com/notary")
|
kdb, repo, cs, err := testutils.EmptyRepo("docker.com/notary")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
store := storage.NewMemStorage()
|
store := storage.NewMemStorage()
|
||||||
snapRole := kdb.GetRole(data.CanonicalSnapshotRole)
|
snapRole, err := repo.GetRoleWithKeys(data.CanonicalSnapshotRole)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
for _, id := range snapRole.KeyIDs {
|
for _, k := range snapRole.Keys {
|
||||||
k := kdb.GetKey(id)
|
|
||||||
assert.NotNil(t, k)
|
|
||||||
err := store.SetKey("testGUN", data.CanonicalSnapshotRole, k.Algorithm(), k.Public())
|
err := store.SetKey("testGUN", data.CanonicalSnapshotRole, k.Algorithm(), k.Public())
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -799,18 +795,18 @@ func TestValidateTargetsModifiedHash(t *testing.T) {
|
||||||
|
|
||||||
// ### generateSnapshot tests ###
|
// ### generateSnapshot tests ###
|
||||||
func TestGenerateSnapshotNoRole(t *testing.T) {
|
func TestGenerateSnapshotNoRole(t *testing.T) {
|
||||||
kdb := keys.NewDB()
|
repo := tuf.NewRepo(keys.NewDB(), nil)
|
||||||
_, err := generateSnapshot("gun", kdb, nil, nil)
|
_, err := generateSnapshot("gun", repo, nil)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.IsType(t, validation.ErrBadRoot{}, err)
|
assert.IsType(t, validation.ErrBadRoot{}, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateSnapshotNoKey(t *testing.T) {
|
func TestGenerateSnapshotNoKey(t *testing.T) {
|
||||||
kdb, _, _, err := testutils.EmptyRepo("docker.com/notary")
|
_, repo, _, err := testutils.EmptyRepo("docker.com/notary")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
store := storage.NewMemStorage()
|
store := storage.NewMemStorage()
|
||||||
|
|
||||||
_, err = generateSnapshot("gun", kdb, nil, store)
|
_, err = generateSnapshot("gun", repo, store)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.IsType(t, validation.ErrBadHierarchy{}, err)
|
assert.IsType(t, validation.ErrBadHierarchy{}, err)
|
||||||
}
|
}
|
||||||
|
@ -904,7 +900,7 @@ func TestValidateTargetsLoadParent(t *testing.T) {
|
||||||
valRepo := tuf.NewRepo(kdb, nil)
|
valRepo := tuf.NewRepo(kdb, nil)
|
||||||
valRepo.SetRoot(baseRepo.Root)
|
valRepo.SetRoot(baseRepo.Root)
|
||||||
|
|
||||||
updates, err := loadAndValidateTargets("gun", valRepo, roles, kdb, store)
|
updates, err := loadAndValidateTargets("gun", valRepo, roles, store)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, updates, 1)
|
assert.Len(t, updates, 1)
|
||||||
assert.Equal(t, "targets/level1", updates[0].Role)
|
assert.Equal(t, "targets/level1", updates[0].Role)
|
||||||
|
@ -960,7 +956,7 @@ func TestValidateTargetsParentInUpdate(t *testing.T) {
|
||||||
// because we sort the roles, the list of returned updates
|
// because we sort the roles, the list of returned updates
|
||||||
// will contain shallower roles first, in this case "targets",
|
// will contain shallower roles first, in this case "targets",
|
||||||
// and then "targets/level1"
|
// and then "targets/level1"
|
||||||
updates, err := loadAndValidateTargets("gun", valRepo, roles, kdb, store)
|
updates, err := loadAndValidateTargets("gun", valRepo, roles, store)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, updates, 2)
|
assert.Len(t, updates, 2)
|
||||||
assert.Equal(t, "targets", updates[0].Role)
|
assert.Equal(t, "targets", updates[0].Role)
|
||||||
|
@ -1002,7 +998,7 @@ func TestValidateTargetsParentNotFound(t *testing.T) {
|
||||||
valRepo := tuf.NewRepo(kdb, nil)
|
valRepo := tuf.NewRepo(kdb, nil)
|
||||||
valRepo.SetRoot(baseRepo.Root)
|
valRepo.SetRoot(baseRepo.Root)
|
||||||
|
|
||||||
_, err = loadAndValidateTargets("gun", valRepo, roles, kdb, store)
|
_, err = loadAndValidateTargets("gun", valRepo, roles, store)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.IsType(t, storage.ErrNotFound{}, err)
|
assert.IsType(t, storage.ErrNotFound{}, err)
|
||||||
}
|
}
|
||||||
|
@ -1057,7 +1053,7 @@ func TestValidateTargetsRoleNotInParent(t *testing.T) {
|
||||||
// because we sort the roles, the list of returned updates
|
// because we sort the roles, the list of returned updates
|
||||||
// will contain shallower roles first, in this case "targets",
|
// will contain shallower roles first, in this case "targets",
|
||||||
// and then "targets/level1"
|
// and then "targets/level1"
|
||||||
updates, err := loadAndValidateTargets("gun", valRepo, roles, kdb, store)
|
updates, err := loadAndValidateTargets("gun", valRepo, roles, store)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, updates, 1)
|
assert.Len(t, updates, 1)
|
||||||
assert.Equal(t, "targets", updates[0].Role)
|
assert.Equal(t, "targets", updates[0].Role)
|
||||||
|
|
|
@ -200,12 +200,16 @@ func (c *Client) downloadRoot() error {
|
||||||
|
|
||||||
func (c Client) verifyRoot(role string, s *data.Signed, minVersion int) error {
|
func (c Client) verifyRoot(role string, s *data.Signed, minVersion int) error {
|
||||||
// this will confirm that the root has been signed by the old root role
|
// this will confirm that the root has been signed by the old root role
|
||||||
// as c.keysDB contains the root keys we bootstrapped with.
|
// with the root keys we bootstrapped with.
|
||||||
// Still need to determine if there has been a root key update and
|
// Still need to determine if there has been a root key update and
|
||||||
// confirm signature with new root key
|
// confirm signature with new root key
|
||||||
logrus.Debug("verifying root with existing keys")
|
logrus.Debug("verifying root with existing keys")
|
||||||
err := signed.Verify(s, role, minVersion, c.keysDB)
|
rootRole, err := c.local.GetRoleWithKeys(role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logrus.Debug("no previous root role loaded")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = signed.Verify(s, rootRole, minVersion); err != nil {
|
||||||
logrus.Debug("root did not verify with existing keys")
|
logrus.Debug("root did not verify with existing keys")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -227,7 +231,12 @@ func (c Client) verifyRoot(role string, s *data.Signed, minVersion int) error {
|
||||||
// TODO(endophage): be more intelligent and only re-verify if we detect
|
// TODO(endophage): be more intelligent and only re-verify if we detect
|
||||||
// there has been a change in root keys
|
// there has been a change in root keys
|
||||||
logrus.Debug("verifying root with updated keys")
|
logrus.Debug("verifying root with updated keys")
|
||||||
err = signed.Verify(s, role, minVersion, c.keysDB)
|
rootRole, err = c.local.GetRoleWithKeys(role)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Debug("root role with new keys not loaded")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = signed.Verify(s, rootRole, minVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debug("root did not verify with new keys")
|
logrus.Debug("root did not verify with new keys")
|
||||||
return err
|
return err
|
||||||
|
@ -267,7 +276,7 @@ func (c *Client) downloadTimestamp() error {
|
||||||
// from remote, only using the cache one if we couldn't reach remote.
|
// from remote, only using the cache one if we couldn't reach remote.
|
||||||
raw, s, err := c.downloadSigned(role, notary.MaxTimestampSize, nil)
|
raw, s, err := c.downloadSigned(role, notary.MaxTimestampSize, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ts, err = c.verifyTimestamp(s, version, c.keysDB)
|
ts, err = c.verifyTimestamp(s, version)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
logrus.Debug("successfully verified downloaded timestamp")
|
logrus.Debug("successfully verified downloaded timestamp")
|
||||||
c.cache.SetMeta(role, raw)
|
c.cache.SetMeta(role, raw)
|
||||||
|
@ -282,7 +291,7 @@ func (c *Client) downloadTimestamp() error {
|
||||||
}
|
}
|
||||||
logrus.Debug(err.Error())
|
logrus.Debug(err.Error())
|
||||||
logrus.Warn("Error while downloading remote metadata, using cached timestamp - this might not be the latest version available remotely")
|
logrus.Warn("Error while downloading remote metadata, using cached timestamp - this might not be the latest version available remotely")
|
||||||
ts, err = c.verifyTimestamp(old, version, c.keysDB)
|
ts, err = c.verifyTimestamp(old, version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -292,8 +301,13 @@ func (c *Client) downloadTimestamp() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifies that a timestamp is valid, and returned the SignedTimestamp object to add to the tuf repo
|
// verifies that a timestamp is valid, and returned the SignedTimestamp object to add to the tuf repo
|
||||||
func (c *Client) verifyTimestamp(s *data.Signed, minVersion int, kdb *keys.KeyDB) (*data.SignedTimestamp, error) {
|
func (c *Client) verifyTimestamp(s *data.Signed, minVersion int) (*data.SignedTimestamp, error) {
|
||||||
if err := signed.Verify(s, data.CanonicalTimestampRole, minVersion, kdb); err != nil {
|
timestampRole, err := c.local.GetRoleWithKeys(data.CanonicalTimestampRole)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Debug("no timestamp role loaded")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := signed.Verify(s, timestampRole, minVersion); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return data.TimestampFromSigned(s)
|
return data.TimestampFromSigned(s)
|
||||||
|
@ -351,7 +365,12 @@ func (c *Client) downloadSnapshot() error {
|
||||||
s = old
|
s = old
|
||||||
}
|
}
|
||||||
|
|
||||||
err = signed.Verify(s, role, version, c.keysDB)
|
snapshotRole, err := c.local.GetRoleWithKeys(role)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Debug("no snapshot role loaded")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = signed.Verify(s, snapshotRole, version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -489,8 +508,12 @@ func (c Client) getTargetsFile(role string, keyIDs []string, snapshotMeta data.F
|
||||||
s = old
|
s = old
|
||||||
}
|
}
|
||||||
|
|
||||||
err = signed.Verify(s, role, version, c.keysDB)
|
targetsRole, err := c.local.GetRoleWithKeys(role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logrus.Debugf("no %s role loaded", role)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = signed.Verify(s, targetsRole, version); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
logrus.Debugf("successfully verified %s", role)
|
logrus.Debugf("successfully verified %s", role)
|
||||||
|
|
|
@ -2,10 +2,11 @@ package data
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Canonical base role names
|
// Canonical base role names
|
||||||
|
@ -244,3 +245,9 @@ func subtractStrSlices(orig, remove []string) []string {
|
||||||
}
|
}
|
||||||
return keep
|
return keep
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RoleWithKeys is a role that has the signing keys for the role embedded
|
||||||
|
type RoleWithKeys struct {
|
||||||
|
Role
|
||||||
|
Keys Keys
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/go/canonical/json"
|
"github.com/docker/go/canonical/json"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/keys"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Various basic signing errors
|
// Various basic signing errors
|
||||||
|
@ -57,18 +56,18 @@ func VerifyRoot(s *data.Signed, minVersion int, keys map[string]data.PublicKey)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// threshold of 1 so return on first success
|
// threshold of 1 so return on first success
|
||||||
return verifyMeta(s, "root", minVersion)
|
return verifyMeta(s, data.CanonicalRootRole, minVersion)
|
||||||
}
|
}
|
||||||
return ErrRoleThreshold{}
|
return ErrRoleThreshold{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify checks the signatures and metadata (expiry, version) for the signed role
|
// Verify checks the signatures and metadata (expiry, version) for the signed role
|
||||||
// data
|
// data
|
||||||
func Verify(s *data.Signed, role string, minVersion int, db *keys.KeyDB) error {
|
func Verify(s *data.Signed, role *data.RoleWithKeys, minVersion int) error {
|
||||||
if err := verifyMeta(s, role, minVersion); err != nil {
|
if err := verifyMeta(s, role.Name, minVersion); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return VerifySignatures(s, role, db)
|
return VerifySignatures(s, role)
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyMeta(s *data.Signed, role string, minVersion int) error {
|
func verifyMeta(s *data.Signed, role string, minVersion int) error {
|
||||||
|
@ -96,21 +95,18 @@ func IsExpired(t time.Time) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifySignatures checks the we have sufficient valid signatures for the given role
|
// VerifySignatures checks the we have sufficient valid signatures for the given role
|
||||||
func VerifySignatures(s *data.Signed, role string, db *keys.KeyDB) error {
|
func VerifySignatures(s *data.Signed, roleData *data.RoleWithKeys) error {
|
||||||
if len(s.Signatures) == 0 {
|
if len(s.Signatures) == 0 {
|
||||||
return ErrNoSignatures
|
return ErrNoSignatures
|
||||||
}
|
}
|
||||||
|
|
||||||
roleData := db.GetRole(role)
|
|
||||||
if roleData == nil {
|
|
||||||
return ErrUnknownRole
|
|
||||||
}
|
|
||||||
|
|
||||||
if roleData.Threshold < 1 {
|
if roleData.Threshold < 1 {
|
||||||
return ErrRoleThreshold{}
|
return ErrRoleThreshold{}
|
||||||
}
|
}
|
||||||
logrus.Debugf("%s role has key IDs: %s", role, strings.Join(roleData.KeyIDs, ","))
|
logrus.Debugf("%s role has key IDs: %s", roleData.Name, strings.Join(roleData.KeyIDs, ","))
|
||||||
|
|
||||||
|
// remarshal the signed part so we can verify the signature, since the signature has
|
||||||
|
// to be of a canonically marshalled signed object
|
||||||
var decoded map[string]interface{}
|
var decoded map[string]interface{}
|
||||||
if err := json.Unmarshal(s.Signed, &decoded); err != nil {
|
if err := json.Unmarshal(s.Signed, &decoded); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -127,8 +123,8 @@ func VerifySignatures(s *data.Signed, role string, db *keys.KeyDB) error {
|
||||||
logrus.Debugf("continuing b/c keyid was invalid: %s for roledata %s\n", sig.KeyID, roleData)
|
logrus.Debugf("continuing b/c keyid was invalid: %s for roledata %s\n", sig.KeyID, roleData)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
key := db.GetKey(sig.KeyID)
|
key, ok := roleData.Keys[sig.KeyID]
|
||||||
if key == nil {
|
if !ok {
|
||||||
logrus.Debugf("continuing b/c keyid lookup was nil: %s\n", sig.KeyID)
|
logrus.Debugf("continuing b/c keyid lookup was nil: %s\n", sig.KeyID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -153,28 +149,3 @@ func VerifySignatures(s *data.Signed, role string, db *keys.KeyDB) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshal unmarshals and verifys the raw bytes for a given role's metadata
|
|
||||||
func Unmarshal(b []byte, v interface{}, role string, minVersion int, db *keys.KeyDB) error {
|
|
||||||
s := &data.Signed{}
|
|
||||||
if err := json.Unmarshal(b, s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := Verify(s, role, minVersion, db); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return json.Unmarshal(s.Signed, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalTrusted unmarshals and verifies signatures only, not metadata, for a
|
|
||||||
// given role's metadata
|
|
||||||
func UnmarshalTrusted(b []byte, v interface{}, role string, db *keys.KeyDB) error {
|
|
||||||
s := &data.Signed{}
|
|
||||||
if err := json.Unmarshal(b, s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := VerifySignatures(s, role, db); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return json.Unmarshal(s.Signed, v)
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/keys"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRoleNoKeys(t *testing.T) {
|
func TestRoleNoKeys(t *testing.T) {
|
||||||
|
@ -24,17 +23,15 @@ func TestRoleNoKeys(t *testing.T) {
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
db := keys.NewDB()
|
roleWithKeys := &data.RoleWithKeys{Role: *r, Keys: data.Keys{k.ID(): k}}
|
||||||
assert.NoError(t, err)
|
|
||||||
err = db.AddRole(r)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
meta := &data.SignedCommon{Type: "Root", Version: 1, Expires: data.DefaultExpires("root")}
|
meta := &data.SignedCommon{Type: "Root", Version: 1, Expires: data.DefaultExpires("root")}
|
||||||
|
|
||||||
b, err := json.MarshalCanonical(meta)
|
b, err := json.MarshalCanonical(meta)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
s := &data.Signed{Signed: b}
|
s := &data.Signed{Signed: b}
|
||||||
Sign(cs, s, k)
|
Sign(cs, s, k)
|
||||||
err = Verify(s, "root", 1, db)
|
err = Verify(s, roleWithKeys, 1)
|
||||||
assert.IsType(t, ErrRoleThreshold{}, err)
|
assert.IsType(t, ErrRoleThreshold{}, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,18 +47,15 @@ func TestNotEnoughSigs(t *testing.T) {
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
db := keys.NewDB()
|
roleWithKeys := &data.RoleWithKeys{Role: *r, Keys: data.Keys{k.ID(): k}}
|
||||||
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")}
|
meta := &data.SignedCommon{Type: "Root", Version: 1, Expires: data.DefaultExpires("root")}
|
||||||
|
|
||||||
b, err := json.MarshalCanonical(meta)
|
b, err := json.MarshalCanonical(meta)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
s := &data.Signed{Signed: b}
|
s := &data.Signed{Signed: b}
|
||||||
Sign(cs, s, k)
|
Sign(cs, s, k)
|
||||||
err = Verify(s, "root", 1, db)
|
err = Verify(s, roleWithKeys, 1)
|
||||||
assert.IsType(t, ErrRoleThreshold{}, err)
|
assert.IsType(t, ErrRoleThreshold{}, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,12 +73,8 @@ func TestMoreThanEnoughSigs(t *testing.T) {
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
db := keys.NewDB()
|
roleWithKeys := &data.RoleWithKeys{Role: *r, Keys: data.Keys{k1.ID(): k1, k2.ID(): k2}}
|
||||||
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")}
|
meta := &data.SignedCommon{Type: "Root", Version: 1, Expires: data.DefaultExpires("root")}
|
||||||
|
|
||||||
b, err := json.MarshalCanonical(meta)
|
b, err := json.MarshalCanonical(meta)
|
||||||
|
@ -92,7 +82,7 @@ func TestMoreThanEnoughSigs(t *testing.T) {
|
||||||
s := &data.Signed{Signed: b}
|
s := &data.Signed{Signed: b}
|
||||||
Sign(cs, s, k1, k2)
|
Sign(cs, s, k1, k2)
|
||||||
assert.Equal(t, 2, len(s.Signatures))
|
assert.Equal(t, 2, len(s.Signatures))
|
||||||
err = Verify(s, "root", 1, db)
|
err = Verify(s, roleWithKeys, 1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,11 +98,8 @@ func TestDuplicateSigs(t *testing.T) {
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
db := keys.NewDB()
|
roleWithKeys := &data.RoleWithKeys{Role: *r, Keys: data.Keys{k.ID(): k}}
|
||||||
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")}
|
meta := &data.SignedCommon{Type: "Root", Version: 1, Expires: data.DefaultExpires("root")}
|
||||||
|
|
||||||
b, err := json.MarshalCanonical(meta)
|
b, err := json.MarshalCanonical(meta)
|
||||||
|
@ -120,7 +107,7 @@ func TestDuplicateSigs(t *testing.T) {
|
||||||
s := &data.Signed{Signed: b}
|
s := &data.Signed{Signed: b}
|
||||||
Sign(cs, s, k)
|
Sign(cs, s, k)
|
||||||
s.Signatures = append(s.Signatures, s.Signatures[0])
|
s.Signatures = append(s.Signatures, s.Signatures[0])
|
||||||
err = Verify(s, "root", 1, db)
|
err = Verify(s, roleWithKeys, 1)
|
||||||
assert.IsType(t, ErrRoleThreshold{}, err)
|
assert.IsType(t, ErrRoleThreshold{}, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,12 +125,8 @@ func TestUnknownKeyBelowThreshold(t *testing.T) {
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
db := keys.NewDB()
|
roleWithKeys := &data.RoleWithKeys{Role: *r, Keys: data.Keys{k.ID(): k, unknown.ID(): unknown}}
|
||||||
assert.NoError(t, err)
|
|
||||||
db.AddKey(k)
|
|
||||||
db.AddKey(unknown)
|
|
||||||
err = db.AddRole(r)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
meta := &data.SignedCommon{Type: "Root", Version: 1, Expires: data.DefaultExpires("root")}
|
meta := &data.SignedCommon{Type: "Root", Version: 1, Expires: data.DefaultExpires("root")}
|
||||||
|
|
||||||
b, err := json.MarshalCanonical(meta)
|
b, err := json.MarshalCanonical(meta)
|
||||||
|
@ -151,23 +134,22 @@ func TestUnknownKeyBelowThreshold(t *testing.T) {
|
||||||
s := &data.Signed{Signed: b}
|
s := &data.Signed{Signed: b}
|
||||||
Sign(cs, s, k, unknown)
|
Sign(cs, s, k, unknown)
|
||||||
s.Signatures = append(s.Signatures)
|
s.Signatures = append(s.Signatures)
|
||||||
err = Verify(s, "root", 1, db)
|
err = Verify(s, roleWithKeys, 1)
|
||||||
assert.IsType(t, ErrRoleThreshold{}, err)
|
assert.IsType(t, ErrRoleThreshold{}, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test(t *testing.T) {
|
func Test(t *testing.T) {
|
||||||
cryptoService := NewEd25519()
|
cryptoService := NewEd25519()
|
||||||
type test struct {
|
type test struct {
|
||||||
name string
|
name string
|
||||||
keys []data.PublicKey
|
roleData *data.RoleWithKeys
|
||||||
roles map[string]*data.Role
|
s *data.Signed
|
||||||
s *data.Signed
|
ver int
|
||||||
ver int
|
exp *time.Time
|
||||||
exp *time.Time
|
typ string
|
||||||
typ string
|
role string
|
||||||
role string
|
err error
|
||||||
err error
|
mut func(*test)
|
||||||
mut func(*test)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expiredTime := time.Now().Add(-time.Hour)
|
expiredTime := time.Now().Add(-time.Hour)
|
||||||
|
@ -204,7 +186,6 @@ func Test(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, run := range tests {
|
for _, run := range tests {
|
||||||
db := keys.NewDB()
|
|
||||||
if run.role == "" {
|
if run.role == "" {
|
||||||
run.role = "root"
|
run.role = "root"
|
||||||
}
|
}
|
||||||
|
@ -218,9 +199,8 @@ func Test(t *testing.T) {
|
||||||
if run.typ == "" {
|
if run.typ == "" {
|
||||||
run.typ = data.TUFTypes[run.role]
|
run.typ = data.TUFTypes[run.role]
|
||||||
}
|
}
|
||||||
if run.keys == nil && run.s == nil {
|
if run.s == nil {
|
||||||
k, _ := cryptoService.Create("root", data.ED25519Key)
|
k, _ := cryptoService.Create("root", data.ED25519Key)
|
||||||
db.AddKey(k)
|
|
||||||
r, err := data.NewRole(
|
r, err := data.NewRole(
|
||||||
"root",
|
"root",
|
||||||
1,
|
1,
|
||||||
|
@ -229,7 +209,7 @@ func Test(t *testing.T) {
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
db.AddRole(r)
|
run.roleData = &data.RoleWithKeys{Role: *r, Keys: data.Keys{k.ID(): k}}
|
||||||
meta := &data.SignedCommon{Type: run.typ, Version: run.ver, Expires: *run.exp}
|
meta := &data.SignedCommon{Type: run.typ, Version: run.ver, Expires: *run.exp}
|
||||||
|
|
||||||
b, err := json.MarshalCanonical(meta)
|
b, err := json.MarshalCanonical(meta)
|
||||||
|
@ -242,7 +222,7 @@ func Test(t *testing.T) {
|
||||||
run.mut(&run)
|
run.mut(&run)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := Verify(run.s, run.role, minVer, db)
|
err := Verify(run.s, run.roleData, minVer)
|
||||||
if e, ok := run.err.(ErrExpired); ok {
|
if e, ok := run.err.(ErrExpired); ok {
|
||||||
assertErrExpired(t, err, e)
|
assertErrExpired(t, err, e)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -406,12 +406,14 @@ func TestSwizzlerChangeRootKey(t *testing.T) {
|
||||||
|
|
||||||
require.NotEqual(t, len(origRoot.Signed.Keys), len(newRoot.Signed.Keys))
|
require.NotEqual(t, len(origRoot.Signed.Keys), len(newRoot.Signed.Keys))
|
||||||
|
|
||||||
|
var rootRole data.Role
|
||||||
for r, origRole := range origRoot.Signed.Roles {
|
for r, origRole := range origRoot.Signed.Roles {
|
||||||
newRole := newRoot.Signed.Roles[r]
|
newRole := newRoot.Signed.Roles[r]
|
||||||
require.Len(t, origRole.KeyIDs, 1)
|
require.Len(t, origRole.KeyIDs, 1)
|
||||||
require.Len(t, newRole.KeyIDs, 1)
|
require.Len(t, newRole.KeyIDs, 1)
|
||||||
if r == data.CanonicalRootRole {
|
if r == data.CanonicalRootRole {
|
||||||
require.NotEqual(t, origRole.KeyIDs[0], newRole.KeyIDs[0])
|
require.NotEqual(t, origRole.KeyIDs[0], newRole.KeyIDs[0])
|
||||||
|
rootRole = data.Role{RootRole: *newRole, Name: data.CanonicalRootRole}
|
||||||
} else {
|
} else {
|
||||||
require.Equal(t, origRole.KeyIDs[0], newRole.KeyIDs[0])
|
require.Equal(t, origRole.KeyIDs[0], newRole.KeyIDs[0])
|
||||||
}
|
}
|
||||||
|
@ -420,7 +422,9 @@ func TestSwizzlerChangeRootKey(t *testing.T) {
|
||||||
require.NoError(t, tufRepo.SetRoot(newRoot))
|
require.NoError(t, tufRepo.SetRoot(newRoot))
|
||||||
signedThing, err := newRoot.ToSigned()
|
signedThing, err := newRoot.ToSigned()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, signed.Verify(signedThing, data.CanonicalRootRole, 1, kdb))
|
newKey := newRoot.Signed.Keys[rootRole.KeyIDs[0]]
|
||||||
|
require.NoError(t, signed.Verify(signedThing,
|
||||||
|
&data.RoleWithKeys{Role: rootRole, Keys: map[string]data.PublicKey{newKey.ID(): newKey}}, 1))
|
||||||
default:
|
default:
|
||||||
require.True(t, bytes.Equal(origMeta, newMeta), "bytes have changed for role %s", role)
|
require.True(t, bytes.Equal(origMeta, newMeta), "bytes have changed for role %s", role)
|
||||||
}
|
}
|
||||||
|
|
16
tuf/tuf.go
16
tuf/tuf.go
|
@ -771,3 +771,19 @@ func (tr Repo) sign(signedData *data.Signed, role data.Role) (*data.Signed, erro
|
||||||
}
|
}
|
||||||
return signedData, nil
|
return signedData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRoleWithKeys returns a RoleWithKeys object, given a role name.
|
||||||
|
func (tr Repo) GetRoleWithKeys(role string) (*data.RoleWithKeys, error) {
|
||||||
|
roleData := tr.keysDB.GetRole(role)
|
||||||
|
if roleData == nil {
|
||||||
|
return nil, ErrNotLoaded{role: role}
|
||||||
|
}
|
||||||
|
keysInRole := make(data.Keys)
|
||||||
|
for _, keyID := range roleData.KeyIDs {
|
||||||
|
k := tr.keysDB.GetKey(keyID)
|
||||||
|
if k != nil {
|
||||||
|
keysInRole[keyID] = k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &data.RoleWithKeys{Role: *roleData, Keys: keysInRole}, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue