func (rb *repoBuilder) loadTargets(content []byte, minVersion int, allowExpired bool) error { roleName := data.CanonicalTargetsRole targetsRole, err := rb.repo.Root.BuildBaseRole(roleName) if err != nil { // this should never happen, since it's already been validated return err } signedObj, err := rb.bytesToSignedAndValidateSigs(targetsRole, content) if err != nil { return err } signedTargets, err := data.TargetsFromSigned(signedObj, roleName) if err != nil { return err } if err := signed.VerifyVersion(&(signedTargets.Signed.SignedCommon), minVersion); err != nil { return err } if !allowExpired { // check must go at the end because all other validation should pass if err := signed.VerifyExpiry(&(signedTargets.Signed.SignedCommon), roleName); err != nil { return err } } signedTargets.Signatures = signedObj.Signatures rb.repo.Targets[roleName] = signedTargets return nil }
// downloadTargets is responsible for downloading any targets file // including delegates roles. func (c *Client) downloadTargets(role string) error { role = data.RoleName(role) // this will really only do something for base targets role if c.local.Snapshot == nil { return ErrMissingMeta{role: role} } snap := c.local.Snapshot.Signed root := c.local.Root.Signed r := c.keysDB.GetRole(role) if r == nil { return fmt.Errorf("Invalid role: %s", role) } keyIDs := r.KeyIDs s, err := c.getTargetsFile(role, keyIDs, snap.Meta, root.ConsistentSnapshot, r.Threshold) if err != nil { logrus.Error("Error getting targets file:", err) return err } t, err := data.TargetsFromSigned(s) if err != nil { return err } err = c.local.SetTargets(role, t) if err != nil { return err } return nil }
func (rb *repoBuilder) loadDelegation(roleName string, content []byte, minVersion int, allowExpired bool) error { delegationRole, err := rb.repo.GetDelegationRole(roleName) if err != nil { return err } signedObj, err := rb.bytesToSignedAndValidateSigs(delegationRole.BaseRole, content) if err != nil { return err } signedTargets, err := data.TargetsFromSigned(signedObj, roleName) if err != nil { return err } if err := signed.VerifyVersion(&(signedTargets.Signed.SignedCommon), minVersion); err != nil { return err } if !allowExpired { // check must go at the end because all other validation should pass if err := signed.VerifyExpiry(&(signedTargets.Signed.SignedCommon), roleName); err != nil { return err } } rb.repo.Targets[roleName] = signedTargets return nil }
// RotateKey rotates the key for a role - this can invalidate that role's metadata // if it is not signed by that key. Particularly if the key being rotated is the // root key, because it is not signed by the new key, only the old key. func (m *MetadataSwizzler) RotateKey(role string, key data.PublicKey) error { roleSpecifier := data.CanonicalRootRole if data.IsDelegation(role) { roleSpecifier = path.Dir(role) } b, err := m.MetadataCache.GetSized(roleSpecifier, store.NoSizeLimit) if err != nil { return err } signedThing := &data.Signed{} if err := json.Unmarshal(b, signedThing); err != nil { return err } // get keys before the keys are rotated pubKeys, err := getPubKeys(m.CryptoService, signedThing, roleSpecifier) if err != nil { return err } if roleSpecifier == data.CanonicalRootRole { signedRoot, err := data.RootFromSigned(signedThing) if err != nil { return err } signedRoot.Signed.Roles[role].KeyIDs = []string{key.ID()} signedRoot.Signed.Keys[key.ID()] = key if signedThing, err = signedRoot.ToSigned(); err != nil { return err } } else { signedTargets, err := data.TargetsFromSigned(signedThing, roleSpecifier) if err != nil { return err } for _, roleObject := range signedTargets.Signed.Delegations.Roles { if roleObject.Name == role { roleObject.KeyIDs = []string{key.ID()} break } } signedTargets.Signed.Delegations.Keys[key.ID()] = key if signedThing, err = signedTargets.ToSigned(); err != nil { return err } } metaBytes, err := serializeMetadata(m.CryptoService, signedThing, roleSpecifier, pubKeys...) if err != nil { return err } return m.MetadataCache.Set(roleSpecifier, metaBytes) }
// SetThreshold sets a threshold for a metadata role - can invalidate metadata for which // the threshold is increased, if there aren't enough signatures or can be invalid because // the threshold is 0 func (m *MetadataSwizzler) SetThreshold(role string, newThreshold int) error { roleSpecifier := data.CanonicalRootRole if data.IsDelegation(role) { roleSpecifier = path.Dir(role) } b, err := m.MetadataCache.GetSized(roleSpecifier, store.NoSizeLimit) if err != nil { return err } signedThing := &data.Signed{} if err := json.Unmarshal(b, signedThing); err != nil { return err } if roleSpecifier == data.CanonicalRootRole { signedRoot, err := data.RootFromSigned(signedThing) if err != nil { return err } signedRoot.Signed.Roles[role].Threshold = newThreshold if signedThing, err = signedRoot.ToSigned(); err != nil { return err } } else { signedTargets, err := data.TargetsFromSigned(signedThing, roleSpecifier) if err != nil { return err } for _, roleObject := range signedTargets.Signed.Delegations.Roles { if roleObject.Name == role { roleObject.Threshold = newThreshold break } } if signedThing, err = signedTargets.ToSigned(); err != nil { return err } } var metaBytes []byte pubKeys, err := getPubKeys(m.CryptoService, signedThing, roleSpecifier) if err == nil { metaBytes, err = serializeMetadata(m.CryptoService, signedThing, roleSpecifier, pubKeys...) } if err != nil { return err } return m.MetadataCache.Set(roleSpecifier, metaBytes) }
// downloadTargets downloads all targets and delegated targets for the repository. // It uses a pre-order tree traversal as it's necessary to download parents first // to obtain the keys to validate children. func (c *Client) downloadTargets(role string) error { logrus.Debug("Downloading Targets...") stack := utils.NewStack() stack.Push(role) for !stack.Empty() { role, err := stack.PopString() if err != nil { return err } if c.local.Snapshot == nil { return ErrMissingMeta{role: role} } snap := c.local.Snapshot.Signed root := c.local.Root.Signed r := c.keysDB.GetRole(role) if r == nil { return fmt.Errorf("Invalid role: %s", role) } keyIDs := r.KeyIDs s, err := c.getTargetsFile(role, keyIDs, snap.Meta, root.ConsistentSnapshot, r.Threshold) if err != nil { if _, ok := err.(ErrMissingMeta); ok && role != data.CanonicalTargetsRole { // if the role meta hasn't been published, // that's ok, continue continue } logrus.Error("Error getting targets file:", err) return err } t, err := data.TargetsFromSigned(s) if err != nil { return err } err = c.local.SetTargets(role, t) if err != nil { return err } // push delegated roles contained in the targets file onto the stack for _, r := range t.Signed.Delegations.Roles { stack.Push(r.Name) } } return nil }
// downloadTargets downloads all targets and delegated targets for the repository. // It uses a pre-order tree traversal as it's necessary to download parents first // to obtain the keys to validate children. func (c *Client) downloadTargets(role string) error { logrus.Debug("Downloading Targets...") stack := utils.NewStack() stack.Push(role) for !stack.Empty() { role, err := stack.PopString() if err != nil { return err } if c.local.Snapshot == nil { return tuf.ErrNotLoaded{Role: data.CanonicalSnapshotRole} } snap := c.local.Snapshot.Signed root := c.local.Root.Signed s, err := c.getTargetsFile(role, snap.Meta, root.ConsistentSnapshot) if err != nil { if _, ok := err.(data.ErrMissingMeta); ok && role != data.CanonicalTargetsRole { // if the role meta hasn't been published, // that's ok, continue continue } logrus.Error("Error getting targets file:", err) return err } t, err := data.TargetsFromSigned(s, role) if err != nil { return err } err = c.local.SetTargets(role, t) if err != nil { return err } // push delegated roles contained in the targets file onto the stack for _, r := range t.Signed.Delegations.Roles { if path.Dir(r.Name) == role { // only load children that are direct 1st generation descendants // of the role we've just downloaded stack.Push(r.Name) } } } return nil }
func validateTargets(role string, roles map[string]storage.MetaUpdate, kdb *keys.KeyDB) (*data.SignedTargets, error) { // TODO: when delegations are being validated, validate parent // role exists for any delegation s := &data.Signed{} err := json.Unmarshal(roles[role].Data, s) if err != nil { return nil, fmt.Errorf("could not parse %s", role) } // version specifically gets validated when writing to store to // better handle race conditions there. if err := signed.Verify(s, role, 0, kdb); err != nil { return nil, err } t, err := data.TargetsFromSigned(s) if err != nil { return nil, err } if !data.ValidTUFType(t.Signed.Type, data.CanonicalTargetsRole) { return nil, fmt.Errorf("%s has wrong type", role) } return t, nil }
func (rb *repoBuilder) loadDelegation(roleName string, content []byte, minVersion int, allowExpired bool) error { delegationRole, err := rb.repo.GetDelegationRole(roleName) if err != nil { return err } // bytesToSigned checks checksum signedObj, err := rb.bytesToSigned(content, roleName) if err != nil { return err } signedTargets, err := data.TargetsFromSigned(signedObj, roleName) if err != nil { return err } if err := signed.VerifyVersion(&(signedTargets.Signed.SignedCommon), minVersion); err != nil { // don't capture in invalidRoles because the role we received is a rollback return err } // verify signature if err := signed.VerifySignatures(signedObj, delegationRole.BaseRole); err != nil { rb.invalidRoles.Targets[roleName] = signedTargets return err } if !allowExpired { // check must go at the end because all other validation should pass if err := signed.VerifyExpiry(&(signedTargets.Signed.SignedCommon), roleName); err != nil { rb.invalidRoles.Targets[roleName] = signedTargets return err } } signedTargets.Signatures = signedObj.Signatures rb.repo.Targets[roleName] = signedTargets return nil }
func validateTargets(role string, roles map[string]storage.MetaUpdate, repo *tuf.Repo) (*data.SignedTargets, error) { // TODO: when delegations are being validated, validate parent // role exists for any delegation s := &data.Signed{} err := json.Unmarshal(roles[role].Data, s) if err != nil { return nil, fmt.Errorf("could not parse %s", role) } // version specifically gets validated when writing to store to // better handle race conditions there. var targetOrDelgRole data.BaseRole if role == data.CanonicalTargetsRole { targetOrDelgRole, err = repo.GetBaseRole(role) if err != nil { logrus.Debugf("no %s role loaded", role) return nil, err } } else { delgRole, err := repo.GetDelegationRole(role) if err != nil { logrus.Debugf("no %s delegation role loaded", role) return nil, err } targetOrDelgRole = delgRole.BaseRole } if err := signed.Verify(s, targetOrDelgRole, 0); err != nil { return nil, err } t, err := data.TargetsFromSigned(s) if err != nil { return nil, err } if !data.ValidTUFType(t.Signed.Type, data.CanonicalTargetsRole) { return nil, fmt.Errorf("%s has wrong type", role) } return t, nil }
func (c Client) getTargetsFile(role string, keyIDs []string, snapshotMeta data.Files, consistent bool, threshold int) (*data.Signed, error) { // require role exists in snapshots roleMeta, ok := snapshotMeta[role] if !ok { return nil, ErrMissingMeta{role: role} } expectedSha256, ok := snapshotMeta[role].Hashes["sha256"] if !ok { return nil, ErrMissingMeta{role: role} } // try to get meta file from content addressed cache var download bool old := &data.Signed{} version := 0 raw, err := c.cache.GetMeta(role, roleMeta.Length) if err != nil || raw == nil { logrus.Debugf("Couldn't not find cached %s, must download", role) download = true } else { // file may have been tampered with on disk. Always check the hash! genHash := sha256.Sum256(raw) if !bytes.Equal(genHash[:], expectedSha256) { download = true } err := json.Unmarshal(raw, old) if err == nil { targ, err := data.TargetsFromSigned(old) if err == nil { version = targ.Signed.Version } else { download = true } } else { download = true } } size := snapshotMeta[role].Length var s *data.Signed if download { rolePath, err := c.RoleTargetsPath(role, hex.EncodeToString(expectedSha256), consistent) if err != nil { return nil, err } raw, s, err = c.downloadSigned(rolePath, size, expectedSha256) if err != nil { return nil, err } } else { logrus.Debug("using cached ", role) s = old } err = signed.Verify(s, role, version, c.keysDB) if err != nil { return nil, err } logrus.Debugf("successfully verified %s", role) if download { // if we error when setting meta, we should continue. err = c.cache.SetMeta(role, raw) if err != nil { logrus.Errorf("Failed to write snapshot to local cache: %s", err.Error()) } } return s, nil }
func (c Client) getTargetsFile(role string, snapshotMeta data.Files, consistent bool) (*data.Signed, error) { // require role exists in snapshots roleMeta, ok := snapshotMeta[role] if !ok { return nil, data.ErrMissingMeta{Role: role} } expectedSha256, ok := snapshotMeta[role].Hashes["sha256"] if !ok { return nil, data.ErrMissingMeta{Role: role} } // try to get meta file from content addressed cache var download bool old := &data.Signed{} version := 0 raw, err := c.cache.GetMeta(role, roleMeta.Length) if err != nil || raw == nil { logrus.Debugf("Couldn't not find cached %s, must download", role) download = true } else { // file may have been tampered with on disk. Always check the hash! genHash := sha256.Sum256(raw) if !bytes.Equal(genHash[:], expectedSha256) { download = true } err := json.Unmarshal(raw, old) if err == nil { targ, err := data.TargetsFromSigned(old, role) if err == nil { version = targ.Signed.Version } else { download = true } } else { download = true } } size := snapshotMeta[role].Length var s *data.Signed if download { raw, s, err = c.downloadSigned(role, size, expectedSha256) if err != nil { return nil, err } } else { logrus.Debug("using cached ", role) s = old } var targetOrDelgRole data.BaseRole if data.IsDelegation(role) { delgRole, err := c.local.GetDelegationRole(role) if err != nil { logrus.Debugf("no %s delegation role loaded", role) return nil, err } targetOrDelgRole = delgRole.BaseRole } else { targetOrDelgRole, err = c.local.GetBaseRole(role) if err != nil { logrus.Debugf("no %s role loaded", role) return nil, err } } if err = signed.Verify(s, targetOrDelgRole, version); err != nil { return nil, err } logrus.Debugf("successfully verified %s", role) if download { // if we error when setting meta, we should continue. err = c.cache.SetMeta(role, raw) if err != nil { logrus.Errorf("Failed to write %s to local cache: %s", role, err.Error()) } } return s, nil }