func witnessTargets(repo *tuf.Repo, invalid *tuf.Repo, role string) error { if r, ok := repo.Targets[role]; ok { // role is already valid, mark for re-signing/updating r.Dirty = true return nil } if roleObj, err := repo.GetDelegationRole(role); err == nil && invalid != nil { // A role with a threshold > len(keys) is technically invalid, but we let it build in the builder because // we want to be able to download the role (which may still have targets on it), add more keys, and then // witness the role, thus bringing it back to valid. However, if no keys have been added before witnessing, // then it is still an invalid role, and can't be witnessed because nothing can bring it back to valid. if roleObj.Threshold > len(roleObj.Keys) { return data.ErrInvalidRole{ Role: role, Reason: "role does not specify enough valid signing keys to meet its required threshold", } } if r, ok := invalid.Targets[role]; ok { // role is recognized but invalid, move to valid data and mark for re-signing repo.Targets[role] = r r.Dirty = true return nil } } // role isn't recognized, even as invalid return data.ErrInvalidRole{ Role: role, Reason: "this role is not known", } }
func changeTargetsDelegation(repo *tuf.Repo, c changelist.Change) error { switch c.Action() { case changelist.ActionCreate: td := changelist.TUFDelegation{} err := json.Unmarshal(c.Content(), &td) if err != nil { return err } // Try to create brand new role or update one // First add the keys, then the paths. We can only add keys and paths in this scenario err = repo.UpdateDelegationKeys(c.Scope(), td.AddKeys, []string{}, td.NewThreshold) if err != nil { return err } return repo.UpdateDelegationPaths(c.Scope(), td.AddPaths, []string{}, false) case changelist.ActionUpdate: td := changelist.TUFDelegation{} err := json.Unmarshal(c.Content(), &td) if err != nil { return err } delgRole, err := repo.GetDelegationRole(c.Scope()) if err != nil { return err } // We need to translate the keys from canonical ID to TUF ID for compatibility canonicalToTUFID := make(map[string]string) for tufID, pubKey := range delgRole.Keys { canonicalID, err := utils.CanonicalKeyID(pubKey) if err != nil { return err } canonicalToTUFID[canonicalID] = tufID } removeTUFKeyIDs := []string{} for _, canonID := range td.RemoveKeys { removeTUFKeyIDs = append(removeTUFKeyIDs, canonicalToTUFID[canonID]) } // If we specify the only keys left delete the role, else just delete specified keys if strings.Join(delgRole.ListKeyIDs(), ";") == strings.Join(removeTUFKeyIDs, ";") && len(td.AddKeys) == 0 { return repo.DeleteDelegation(c.Scope()) } err = repo.UpdateDelegationKeys(c.Scope(), td.AddKeys, removeTUFKeyIDs, td.NewThreshold) if err != nil { return err } return repo.UpdateDelegationPaths(c.Scope(), td.AddPaths, td.RemovePaths, td.ClearAllPaths) case changelist.ActionDelete: return repo.DeleteDelegation(c.Scope()) default: return fmt.Errorf("unsupported action against delegations: %s", c.Action()) } }
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 }