...

Source file src/github.com/theupdateframework/go-tuf/repo.go

Documentation: github.com/theupdateframework/go-tuf

     1  package tuf
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"log"
    11  	"path"
    12  	"sort"
    13  	"strings"
    14  	"time"
    15  
    16  	"github.com/secure-systems-lab/go-securesystemslib/cjson"
    17  	"github.com/theupdateframework/go-tuf/data"
    18  	"github.com/theupdateframework/go-tuf/internal/roles"
    19  	"github.com/theupdateframework/go-tuf/internal/sets"
    20  	"github.com/theupdateframework/go-tuf/internal/signer"
    21  	"github.com/theupdateframework/go-tuf/pkg/keys"
    22  	"github.com/theupdateframework/go-tuf/pkg/targets"
    23  	"github.com/theupdateframework/go-tuf/sign"
    24  	"github.com/theupdateframework/go-tuf/util"
    25  	"github.com/theupdateframework/go-tuf/verify"
    26  )
    27  
    28  const (
    29  	// The maximum number of delegations to visit while traversing the delegations graph.
    30  	defaultMaxDelegations = 32
    31  )
    32  
    33  // topLevelMetadata determines the order signatures are verified when committing.
    34  var topLevelMetadata = []string{
    35  	"root.json",
    36  	"targets.json",
    37  	"snapshot.json",
    38  	"timestamp.json",
    39  }
    40  
    41  // TargetsWalkFunc is a function of a target path name and a target payload used to
    42  // execute some function on each staged target file. For example, it may normalize path
    43  // names and generate target file metadata with additional custom metadata.
    44  type TargetsWalkFunc func(path string, target io.Reader) error
    45  
    46  type Repo struct {
    47  	local          LocalStore
    48  	hashAlgorithms []string
    49  	meta           map[string]json.RawMessage
    50  	prefix         string
    51  	indent         string
    52  	logger         *log.Logger
    53  }
    54  
    55  type RepoOpts func(r *Repo)
    56  
    57  func WithLogger(logger *log.Logger) RepoOpts {
    58  	return func(r *Repo) {
    59  		r.logger = logger
    60  	}
    61  }
    62  
    63  func WithHashAlgorithms(hashAlgorithms ...string) RepoOpts {
    64  	return func(r *Repo) {
    65  		r.hashAlgorithms = hashAlgorithms
    66  	}
    67  }
    68  
    69  func WithPrefix(prefix string) RepoOpts {
    70  	return func(r *Repo) {
    71  		r.prefix = prefix
    72  	}
    73  }
    74  
    75  func WithIndex(indent string) RepoOpts {
    76  	return func(r *Repo) {
    77  		r.indent = indent
    78  	}
    79  }
    80  
    81  func NewRepo(local LocalStore, hashAlgorithms ...string) (*Repo, error) {
    82  	return NewRepoIndent(local, "", "", hashAlgorithms...)
    83  }
    84  
    85  func NewRepoIndent(local LocalStore, prefix string, indent string,
    86  	hashAlgorithms ...string) (*Repo, error) {
    87  	r := &Repo{
    88  		local:          local,
    89  		hashAlgorithms: hashAlgorithms,
    90  		prefix:         prefix,
    91  		indent:         indent,
    92  		logger:         log.New(io.Discard, "", 0),
    93  	}
    94  
    95  	var err error
    96  	r.meta, err = local.GetMeta()
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  	return r, nil
   101  }
   102  
   103  func NewRepoWithOpts(local LocalStore, opts ...RepoOpts) (*Repo, error) {
   104  	r, err := NewRepo(local)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	for _, opt := range opts {
   109  		opt(r)
   110  	}
   111  	return r, nil
   112  }
   113  
   114  func (r *Repo) Init(consistentSnapshot bool) error {
   115  	t, err := r.topLevelTargets()
   116  	if err != nil {
   117  		return err
   118  	}
   119  	if len(t.Targets) > 0 {
   120  		return ErrInitNotAllowed
   121  	}
   122  	root := data.NewRoot()
   123  	root.ConsistentSnapshot = consistentSnapshot
   124  	// Set root version to 1 for a new root.
   125  	root.Version = 1
   126  	if err = r.setMeta("root.json", root); err != nil {
   127  		return err
   128  	}
   129  
   130  	t.Version = 1
   131  	if err = r.setMeta("targets.json", t); err != nil {
   132  		return err
   133  	}
   134  
   135  	r.logger.Println("Repository initialized")
   136  	return nil
   137  }
   138  
   139  func (r *Repo) topLevelKeysDB() (*verify.DB, error) {
   140  	db := verify.NewDB()
   141  	root, err := r.root()
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  	for id, k := range root.Keys {
   146  		if err := db.AddKey(id, k); err != nil {
   147  			return nil, err
   148  		}
   149  	}
   150  	for name, role := range root.Roles {
   151  		if err := db.AddRole(name, role); err != nil {
   152  			return nil, err
   153  		}
   154  	}
   155  	return db, nil
   156  }
   157  
   158  func (r *Repo) root() (*data.Root, error) {
   159  	rootJSON, ok := r.meta["root.json"]
   160  	if !ok {
   161  		return data.NewRoot(), nil
   162  	}
   163  	s := &data.Signed{}
   164  	if err := json.Unmarshal(rootJSON, s); err != nil {
   165  		return nil, err
   166  	}
   167  	root := &data.Root{}
   168  	if err := json.Unmarshal(s.Signed, root); err != nil {
   169  		return nil, err
   170  	}
   171  	return root, nil
   172  }
   173  
   174  func (r *Repo) snapshot() (*data.Snapshot, error) {
   175  	snapshotJSON, ok := r.meta["snapshot.json"]
   176  	if !ok {
   177  		return data.NewSnapshot(), nil
   178  	}
   179  	s := &data.Signed{}
   180  	if err := json.Unmarshal(snapshotJSON, s); err != nil {
   181  		return nil, err
   182  	}
   183  	snapshot := &data.Snapshot{}
   184  	if err := json.Unmarshal(s.Signed, snapshot); err != nil {
   185  		return nil, err
   186  	}
   187  	return snapshot, nil
   188  }
   189  
   190  func (r *Repo) RootVersion() (int64, error) {
   191  	root, err := r.root()
   192  	if err != nil {
   193  		return -1, err
   194  	}
   195  	return root.Version, nil
   196  }
   197  
   198  func (r *Repo) GetThreshold(keyRole string) (int, error) {
   199  	if roles.IsDelegatedTargetsRole(keyRole) {
   200  		// The signature threshold for a delegated targets role
   201  		// depends on the incoming delegation edge.
   202  		return -1, ErrInvalidRole{keyRole, "only thresholds for top-level roles supported"}
   203  	}
   204  	root, err := r.root()
   205  	if err != nil {
   206  		return -1, err
   207  	}
   208  	role, ok := root.Roles[keyRole]
   209  	if !ok {
   210  		return -1, ErrInvalidRole{keyRole, "role missing from root metadata"}
   211  	}
   212  
   213  	return role.Threshold, nil
   214  }
   215  
   216  func (r *Repo) SetThreshold(keyRole string, t int) error {
   217  	if roles.IsDelegatedTargetsRole(keyRole) {
   218  		// The signature threshold for a delegated targets role
   219  		// depends on the incoming delegation edge.
   220  		return ErrInvalidRole{keyRole, "only thresholds for top-level roles supported"}
   221  	}
   222  	root, err := r.root()
   223  	if err != nil {
   224  		return err
   225  	}
   226  	role, ok := root.Roles[keyRole]
   227  	if !ok {
   228  		return ErrInvalidRole{keyRole, "role missing from root metadata"}
   229  	}
   230  	if role.Threshold == t {
   231  		// Change was a no-op.
   232  		return nil
   233  	}
   234  	role.Threshold = t
   235  	if !r.local.FileIsStaged("root.json") {
   236  		root.Version++
   237  	}
   238  	return r.setMeta("root.json", root)
   239  }
   240  
   241  func (r *Repo) Targets() (data.TargetFiles, error) {
   242  	targets, err := r.topLevelTargets()
   243  	if err != nil {
   244  		return nil, err
   245  	}
   246  	return targets.Targets, nil
   247  }
   248  
   249  func (r *Repo) SetTargetsVersion(v int64) error {
   250  	t, err := r.topLevelTargets()
   251  	if err != nil {
   252  		return err
   253  	}
   254  	t.Version = v
   255  	return r.setMeta("targets.json", t)
   256  }
   257  
   258  func (r *Repo) TargetsVersion() (int64, error) {
   259  	t, err := r.topLevelTargets()
   260  	if err != nil {
   261  		return -1, err
   262  	}
   263  	return t.Version, nil
   264  }
   265  
   266  func (r *Repo) SetTimestampVersion(v int64) error {
   267  	ts, err := r.timestamp()
   268  	if err != nil {
   269  		return err
   270  	}
   271  	ts.Version = v
   272  	return r.setMeta("timestamp.json", ts)
   273  }
   274  
   275  func (r *Repo) TimestampVersion() (int64, error) {
   276  	ts, err := r.timestamp()
   277  	if err != nil {
   278  		return -1, err
   279  	}
   280  	return ts.Version, nil
   281  }
   282  
   283  func (r *Repo) SetSnapshotVersion(v int64) error {
   284  	s, err := r.snapshot()
   285  	if err != nil {
   286  		return err
   287  	}
   288  
   289  	s.Version = v
   290  	return r.setMeta("snapshot.json", s)
   291  }
   292  
   293  func (r *Repo) SnapshotVersion() (int64, error) {
   294  	s, err := r.snapshot()
   295  	if err != nil {
   296  		return -1, err
   297  	}
   298  	return s.Version, nil
   299  }
   300  
   301  func (r *Repo) topLevelTargets() (*data.Targets, error) {
   302  	return r.targets("targets")
   303  }
   304  
   305  func (r *Repo) targets(metaName string) (*data.Targets, error) {
   306  	targetsJSON, ok := r.meta[metaName+".json"]
   307  	if !ok {
   308  		return data.NewTargets(), nil
   309  	}
   310  	s := &data.Signed{}
   311  	if err := json.Unmarshal(targetsJSON, s); err != nil {
   312  		return nil, fmt.Errorf("error unmarshalling for targets %q: %w", metaName, err)
   313  	}
   314  	targets := &data.Targets{}
   315  	if err := json.Unmarshal(s.Signed, targets); err != nil {
   316  		return nil, fmt.Errorf("error unmarshalling signed data for targets %q: %w", metaName, err)
   317  	}
   318  	return targets, nil
   319  }
   320  
   321  func (r *Repo) timestamp() (*data.Timestamp, error) {
   322  	timestampJSON, ok := r.meta["timestamp.json"]
   323  	if !ok {
   324  		return data.NewTimestamp(), nil
   325  	}
   326  	s := &data.Signed{}
   327  	if err := json.Unmarshal(timestampJSON, s); err != nil {
   328  		return nil, err
   329  	}
   330  	timestamp := &data.Timestamp{}
   331  	if err := json.Unmarshal(s.Signed, timestamp); err != nil {
   332  		return nil, err
   333  	}
   334  	return timestamp, nil
   335  }
   336  
   337  func (r *Repo) ChangePassphrase(keyRole string) error {
   338  	if p, ok := r.local.(PassphraseChanger); ok {
   339  		return p.ChangePassphrase(keyRole)
   340  	}
   341  
   342  	return ErrChangePassphraseNotSupported
   343  }
   344  
   345  func (r *Repo) GenKey(role string) ([]string, error) {
   346  	// Not compatible with delegated targets roles, since delegated targets keys
   347  	// are associated with a delegation (edge), not a role (node).
   348  
   349  	return r.GenKeyWithExpires(role, data.DefaultExpires(role))
   350  }
   351  
   352  func (r *Repo) GenKeyWithExpires(keyRole string, expires time.Time) (keyids []string, err error) {
   353  	return r.GenKeyWithSchemeAndExpires(keyRole, expires, data.KeySchemeEd25519)
   354  }
   355  
   356  func (r *Repo) GenKeyWithSchemeAndExpires(role string, expires time.Time, keyScheme data.KeyScheme) ([]string, error) {
   357  	var signer keys.Signer
   358  	var err error
   359  	switch keyScheme {
   360  	case data.KeySchemeEd25519:
   361  		signer, err = keys.GenerateEd25519Key()
   362  	case data.KeySchemeECDSA_SHA2_P256:
   363  		signer, err = keys.GenerateEcdsaKey()
   364  	case data.KeySchemeRSASSA_PSS_SHA256:
   365  		signer, err = keys.GenerateRsaKey()
   366  	default:
   367  		return nil, errors.New("unknown key type")
   368  	}
   369  	if err != nil {
   370  		return nil, err
   371  	}
   372  
   373  	// Not compatible with delegated targets roles, since delegated targets keys
   374  	// are associated with a delegation (edge), not a role (node).
   375  
   376  	if err = r.AddPrivateKeyWithExpires(role, signer, expires); err != nil {
   377  		return nil, err
   378  	}
   379  	return signer.PublicData().IDs(), nil
   380  }
   381  
   382  func (r *Repo) AddKeyWithSchemeAndExpires(role string, expires time.Time, keyScheme data.KeyScheme, publicValue string) ([]string, error) {
   383  	var verifier keys.Verifier
   384  	var keyType data.KeyType
   385  	switch keyScheme {
   386  	case data.KeySchemeEd25519:
   387  		verifier = keys.NewEd25519Verifier()
   388  		keyType = data.KeyTypeEd25519
   389  	case data.KeySchemeECDSA_SHA2_P256:
   390  		verifier = keys.NewEcdsaVerifier()
   391  		keyType = data.KeyTypeECDSA_SHA2_P256
   392  	case data.KeySchemeRSASSA_PSS_SHA256:
   393  		verifier = keys.NewRsaVerifier()
   394  		keyType = data.KeyTypeRSASSA_PSS_SHA256
   395  	default:
   396  		return nil, errors.New("unknown key type")
   397  	}
   398  
   399  	publicValueData, err := json.Marshal(map[string]string{
   400  		"public": publicValue,
   401  	})
   402  	if err != nil {
   403  		return nil, err
   404  	}
   405  
   406  	if err := verifier.UnmarshalPublicKey(&data.PublicKey{
   407  		Type:       keyType,
   408  		Scheme:     keyScheme,
   409  		Algorithms: data.HashAlgorithms,
   410  		Value:      publicValueData,
   411  	}); err != nil {
   412  		return nil, err
   413  	}
   414  
   415  	publicKey := verifier.MarshalPublicKey()
   416  
   417  	// Not compatible with delegated targets roles, since delegated targets keys
   418  	// are associated with a delegation (edge), not a role (node).
   419  	if err := r.AddVerificationKeyWithExpiration(role, publicKey, expires); err != nil {
   420  		return nil, err
   421  	}
   422  	return publicKey.IDs(), nil
   423  }
   424  
   425  func (r *Repo) AddPrivateKey(role string, signer keys.Signer) error {
   426  	// Not compatible with delegated targets roles, since delegated targets keys
   427  	// are associated with a delegation (edge), not a role (node).
   428  
   429  	return r.AddPrivateKeyWithExpires(role, signer, data.DefaultExpires(role))
   430  }
   431  
   432  func (r *Repo) AddPrivateKeyWithExpires(keyRole string, signer keys.Signer, expires time.Time) error {
   433  	// Not compatible with delegated targets roles, since delegated targets keys
   434  	// are associated with a delegation (edge), not a role (node).
   435  
   436  	if roles.IsDelegatedTargetsRole(keyRole) {
   437  		return ErrInvalidRole{keyRole, "only support adding keys for top-level roles"}
   438  	}
   439  
   440  	if !validExpires(expires) {
   441  		return ErrInvalidExpires{expires}
   442  	}
   443  
   444  	// Must add signer before adding verification key, so
   445  	// root.json can be signed when a new root key is added.
   446  	if err := r.local.SaveSigner(keyRole, signer); err != nil {
   447  		return err
   448  	}
   449  
   450  	if err := r.AddVerificationKeyWithExpiration(keyRole, signer.PublicData(), expires); err != nil {
   451  		return err
   452  	}
   453  
   454  	return nil
   455  }
   456  
   457  func (r *Repo) AddVerificationKey(keyRole string, pk *data.PublicKey) error {
   458  	// Not compatible with delegated targets roles, since delegated targets keys
   459  	// are associated with a delegation (edge), not a role (node).
   460  
   461  	return r.AddVerificationKeyWithExpiration(keyRole, pk, data.DefaultExpires(keyRole))
   462  }
   463  
   464  func (r *Repo) AddVerificationKeyWithExpiration(keyRole string, pk *data.PublicKey, expires time.Time) error {
   465  	// Not compatible with delegated targets roles, since delegated targets keys
   466  	// are associated with a delegation (edge), not a role (node).
   467  
   468  	if roles.IsDelegatedTargetsRole(keyRole) {
   469  		return ErrInvalidRole{
   470  			Role:   keyRole,
   471  			Reason: "only top-level targets roles are supported",
   472  		}
   473  	}
   474  
   475  	if !validExpires(expires) {
   476  		return ErrInvalidExpires{expires}
   477  	}
   478  
   479  	root, err := r.root()
   480  	if err != nil {
   481  		return err
   482  	}
   483  
   484  	role, ok := root.Roles[keyRole]
   485  	if !ok {
   486  		role = &data.Role{KeyIDs: []string{}, Threshold: 1}
   487  		root.Roles[keyRole] = role
   488  	}
   489  	changed := false
   490  	if role.AddKeyIDs(pk.IDs()) {
   491  		changed = true
   492  	}
   493  
   494  	if root.AddKey(pk) {
   495  		changed = true
   496  	}
   497  
   498  	if !changed {
   499  		return nil
   500  	}
   501  
   502  	root.Expires = expires.Round(time.Second)
   503  	if !r.local.FileIsStaged("root.json") {
   504  		root.Version++
   505  	}
   506  
   507  	return r.setMeta("root.json", root)
   508  }
   509  
   510  func validExpires(expires time.Time) bool {
   511  	return time.Until(expires) > 0
   512  }
   513  
   514  func (r *Repo) RootKeys() ([]*data.PublicKey, error) {
   515  	root, err := r.root()
   516  	if err != nil {
   517  		return nil, err
   518  	}
   519  	role, ok := root.Roles["root"]
   520  	if !ok {
   521  		return nil, nil
   522  	}
   523  
   524  	// We might have multiple key ids that correspond to the same key, so
   525  	// make sure we only return unique keys.
   526  	seen := make(map[string]struct{})
   527  	rootKeys := []*data.PublicKey{}
   528  	for _, id := range role.KeyIDs {
   529  		key, ok := root.Keys[id]
   530  		if !ok {
   531  			return nil, fmt.Errorf("tuf: invalid root metadata")
   532  		}
   533  		found := false
   534  		if _, ok := seen[id]; ok {
   535  			found = true
   536  			break
   537  		}
   538  		if !found {
   539  			for _, id := range key.IDs() {
   540  				seen[id] = struct{}{}
   541  			}
   542  			rootKeys = append(rootKeys, key)
   543  		}
   544  	}
   545  	return rootKeys, nil
   546  }
   547  
   548  func (r *Repo) RevokeKey(role, id string) error {
   549  	// Not compatible with delegated targets roles, since delegated targets keys
   550  	// are associated with a delegation (edge), not a role (node).
   551  
   552  	return r.RevokeKeyWithExpires(role, id, data.DefaultExpires("root"))
   553  }
   554  
   555  func (r *Repo) RevokeKeyWithExpires(keyRole, id string, expires time.Time) error {
   556  	// Not compatible with delegated targets roles, since delegated targets keys
   557  	// are associated with a delegation (edge), not a role (node).
   558  
   559  	if roles.IsDelegatedTargetsRole(keyRole) {
   560  		return ErrInvalidRole{keyRole, "only revocations for top-level roles supported"}
   561  	}
   562  
   563  	if !validExpires(expires) {
   564  		return ErrInvalidExpires{expires}
   565  	}
   566  
   567  	root, err := r.root()
   568  	if err != nil {
   569  		return err
   570  	}
   571  
   572  	key, ok := root.Keys[id]
   573  	if !ok {
   574  		return ErrKeyNotFound{keyRole, id}
   575  	}
   576  
   577  	role, ok := root.Roles[keyRole]
   578  	if !ok {
   579  		return ErrKeyNotFound{keyRole, id}
   580  	}
   581  
   582  	// Create a list of filtered key IDs that do not contain the revoked key IDs.
   583  	filteredKeyIDs := make([]string, 0, len(role.KeyIDs))
   584  
   585  	// There may be multiple keyids that correspond to this key, so
   586  	// filter all of them out.
   587  	for _, keyID := range role.KeyIDs {
   588  		if !key.ContainsID(keyID) {
   589  			filteredKeyIDs = append(filteredKeyIDs, keyID)
   590  		}
   591  	}
   592  	if len(filteredKeyIDs) == len(role.KeyIDs) {
   593  		return ErrKeyNotFound{keyRole, id}
   594  	}
   595  	role.KeyIDs = filteredKeyIDs
   596  	root.Roles[keyRole] = role
   597  
   598  	// Only delete the key from root.Keys if the key is no longer in use by
   599  	// any other role.
   600  	key_in_use := false
   601  	for _, role := range root.Roles {
   602  		for _, keyID := range role.KeyIDs {
   603  			if key.ContainsID(keyID) {
   604  				key_in_use = true
   605  			}
   606  		}
   607  	}
   608  	if !key_in_use {
   609  		for _, keyID := range key.IDs() {
   610  			delete(root.Keys, keyID)
   611  		}
   612  	}
   613  	root.Expires = expires.Round(time.Second)
   614  	if !r.local.FileIsStaged("root.json") {
   615  		root.Version++
   616  	}
   617  
   618  	err = r.setMeta("root.json", root)
   619  	if err == nil {
   620  		r.logger.Println("Revoked", keyRole, "key with ID", id, "in root metadata")
   621  	}
   622  	return err
   623  }
   624  
   625  // AddDelegatedRole is equivalent to AddDelegatedRoleWithExpires, but
   626  // with a default expiration time.
   627  func (r *Repo) AddDelegatedRole(delegator string, delegatedRole data.DelegatedRole, keys []*data.PublicKey) error {
   628  	return r.AddDelegatedRoleWithExpires(delegator, delegatedRole, keys, data.DefaultExpires("targets"))
   629  }
   630  
   631  // AddDelegatedRoleWithExpires adds a delegation from the delegator to the
   632  // role specified in the role argument. Key IDs referenced in role.KeyIDs
   633  // should have corresponding Key entries in the keys argument. New metadata is
   634  // written with the given expiration time.
   635  func (r *Repo) AddDelegatedRoleWithExpires(delegator string, delegatedRole data.DelegatedRole, keys []*data.PublicKey, expires time.Time) error {
   636  	expires = expires.Round(time.Second)
   637  
   638  	t, err := r.targets(delegator)
   639  	if err != nil {
   640  		return fmt.Errorf("error getting delegator (%q) metadata: %w", delegator, err)
   641  	}
   642  
   643  	if t.Delegations == nil {
   644  		t.Delegations = &data.Delegations{}
   645  		t.Delegations.Keys = make(map[string]*data.PublicKey)
   646  	}
   647  
   648  	for _, keyID := range delegatedRole.KeyIDs {
   649  		for _, key := range keys {
   650  			if key.ContainsID(keyID) {
   651  				t.Delegations.Keys[keyID] = key
   652  				break
   653  			}
   654  		}
   655  	}
   656  
   657  	for _, r := range t.Delegations.Roles {
   658  		if r.Name == delegatedRole.Name {
   659  			return fmt.Errorf("role: %s is already delegated to by %s", delegatedRole.Name, r.Name)
   660  		}
   661  	}
   662  	t.Delegations.Roles = append(t.Delegations.Roles, delegatedRole)
   663  	t.Expires = expires
   664  
   665  	delegatorFile := delegator + ".json"
   666  	if !r.local.FileIsStaged(delegatorFile) {
   667  		t.Version++
   668  	}
   669  
   670  	err = r.setMeta(delegatorFile, t)
   671  	if err != nil {
   672  		return fmt.Errorf("error setting metadata for %q: %w", delegatorFile, err)
   673  	}
   674  
   675  	delegatee := delegatedRole.Name
   676  	dt, err := r.targets(delegatee)
   677  	if err != nil {
   678  		return fmt.Errorf("error getting delegatee (%q) metadata: %w", delegatee, err)
   679  	}
   680  	dt.Expires = expires
   681  
   682  	delegateeFile := delegatee + ".json"
   683  	if !r.local.FileIsStaged(delegateeFile) {
   684  		dt.Version++
   685  	}
   686  
   687  	err = r.setMeta(delegateeFile, dt)
   688  	if err != nil {
   689  		return fmt.Errorf("error setting metadata for %q: %w", delegateeFile, err)
   690  	}
   691  
   692  	return nil
   693  }
   694  
   695  // AddDelegatedRolesForPathHashBins is equivalent to
   696  // AddDelegatedRolesForPathHashBinsWithExpires, but with a default
   697  // expiration time.
   698  func (r *Repo) AddDelegatedRolesForPathHashBins(delegator string, bins *targets.HashBins, keys []*data.PublicKey, threshold int) error {
   699  	return r.AddDelegatedRolesForPathHashBinsWithExpires(delegator, bins, keys, threshold, data.DefaultExpires("targets"))
   700  }
   701  
   702  // AddDelegatedRolesForPathHashBinsWithExpires adds delegations to the
   703  // delegator role for the given hash bins configuration. New metadata is
   704  // written with the given expiration time.
   705  func (r *Repo) AddDelegatedRolesForPathHashBinsWithExpires(delegator string, bins *targets.HashBins, keys []*data.PublicKey, threshold int, expires time.Time) error {
   706  	keyIDs := []string{}
   707  	for _, key := range keys {
   708  		keyIDs = append(keyIDs, key.IDs()...)
   709  	}
   710  
   711  	n := bins.NumBins()
   712  	for i := uint64(0); i < n; i += 1 {
   713  		bin := bins.GetBin(i)
   714  		name := bin.RoleName()
   715  		err := r.AddDelegatedRoleWithExpires(delegator, data.DelegatedRole{
   716  			Name:             name,
   717  			KeyIDs:           sets.DeduplicateStrings(keyIDs),
   718  			PathHashPrefixes: bin.HashPrefixes(),
   719  			Threshold:        threshold,
   720  		}, keys, expires)
   721  		if err != nil {
   722  			return fmt.Errorf("error adding delegation from %v to %v: %w", delegator, name, err)
   723  		}
   724  	}
   725  
   726  	return nil
   727  }
   728  
   729  // ResetTargetsDelegation is equivalent to ResetTargetsDelegationsWithExpires
   730  // with a default expiry time.
   731  func (r *Repo) ResetTargetsDelegations(delegator string) error {
   732  	return r.ResetTargetsDelegationsWithExpires(delegator, data.DefaultExpires("targets"))
   733  }
   734  
   735  // ResetTargetsDelegationsWithExpires removes all targets delegations from the
   736  // given delegator role. New metadata is written with the given expiration
   737  // time.
   738  func (r *Repo) ResetTargetsDelegationsWithExpires(delegator string, expires time.Time) error {
   739  	t, err := r.targets(delegator)
   740  	if err != nil {
   741  		return fmt.Errorf("error getting delegator (%q) metadata: %w", delegator, err)
   742  	}
   743  
   744  	t.Delegations = nil
   745  
   746  	t.Expires = expires.Round(time.Second)
   747  
   748  	delegatorFile := delegator + ".json"
   749  	if !r.local.FileIsStaged(delegatorFile) {
   750  		t.Version++
   751  	}
   752  
   753  	err = r.setMeta(delegatorFile, t)
   754  	if err != nil {
   755  		return fmt.Errorf("error setting metadata for %q: %w", delegatorFile, err)
   756  	}
   757  
   758  	return nil
   759  }
   760  
   761  func (r *Repo) jsonMarshal(v interface{}) ([]byte, error) {
   762  	if r.prefix == "" && r.indent == "" {
   763  		return json.Marshal(v)
   764  	}
   765  	return json.MarshalIndent(v, r.prefix, r.indent)
   766  }
   767  
   768  func (r *Repo) dbsForRole(role string) ([]*verify.DB, error) {
   769  	dbs := []*verify.DB{}
   770  
   771  	if roles.IsTopLevelRole(role) {
   772  		db, err := r.topLevelKeysDB()
   773  		if err != nil {
   774  			return nil, err
   775  		}
   776  		dbs = append(dbs, db)
   777  	} else {
   778  		ddbs, err := r.delegatorDBs(role)
   779  		if err != nil {
   780  			return nil, err
   781  		}
   782  
   783  		dbs = append(dbs, ddbs...)
   784  	}
   785  
   786  	return dbs, nil
   787  }
   788  
   789  func (r *Repo) signersForRole(role string) ([]keys.Signer, error) {
   790  	dbs, err := r.dbsForRole(role)
   791  	if err != nil {
   792  		return nil, err
   793  	}
   794  
   795  	signers := []keys.Signer{}
   796  	for _, db := range dbs {
   797  		ss, err := r.getSignersInDB(role, db)
   798  		if err != nil {
   799  			return nil, err
   800  		}
   801  
   802  		signers = append(signers, ss...)
   803  	}
   804  
   805  	return signers, nil
   806  }
   807  
   808  func (r *Repo) setMeta(roleFilename string, meta interface{}) error {
   809  	role := strings.TrimSuffix(roleFilename, ".json")
   810  
   811  	signers, err := r.signersForRole(role)
   812  	if err != nil {
   813  		return err
   814  	}
   815  
   816  	s, err := sign.Marshal(meta, signers...)
   817  	if err != nil {
   818  		return err
   819  	}
   820  	b, err := r.jsonMarshal(s)
   821  	if err != nil {
   822  		return err
   823  	}
   824  	r.meta[roleFilename] = b
   825  	return r.local.SetMeta(roleFilename, b)
   826  }
   827  
   828  // CanonicalizeAndSign canonicalizes the signed portion of signed, then signs it using the key(s) associated with role.
   829  //
   830  // It appends the signature to signed.
   831  //
   832  // It returns the total number of keys used for signing, 0 (along with
   833  // ErrNoKeys) if no keys were found, or -1 (along with an error) in error cases.
   834  func (r *Repo) CanonicalizeAndSign(role string, signed *data.Signed) (int, error) {
   835  	keys, err := r.signersForRole(role)
   836  	if err != nil {
   837  		return -1, err
   838  	}
   839  	if len(keys) == 0 {
   840  		return 0, ErrNoKeys{role}
   841  	}
   842  	for _, k := range keys {
   843  		if err = sign.Sign(signed, k); err != nil {
   844  			return -1, err
   845  		}
   846  	}
   847  	return len(keys), nil
   848  }
   849  
   850  // SignPayload canonicalizes the signed portion of payload, then signs it using the key(s) associated with role.
   851  //
   852  // It returns the total number of keys used for signing, 0 (along with
   853  // ErrNoKeys) if no keys were found, or -1 (along with an error) in error cases.
   854  //
   855  // DEPRECATED: please use CanonicalizeAndSign instead.
   856  func (r *Repo) SignPayload(role string, payload *data.Signed) (int, error) {
   857  	return r.CanonicalizeAndSign(role, payload)
   858  }
   859  
   860  // SignRaw signs the given (pre-canonicalized) payload using the key(s) associated with role.
   861  //
   862  // It returns the new data.Signatures.
   863  func (r *Repo) SignRaw(role string, payload []byte) ([]data.Signature, error) {
   864  	keys, err := r.signersForRole(role)
   865  	if err != nil {
   866  		return nil, err
   867  	}
   868  	if len(keys) == 0 {
   869  		return nil, ErrNoKeys{role}
   870  	}
   871  
   872  	allSigs := make([]data.Signature, 0, len(keys))
   873  	for _, k := range keys {
   874  		sigs, err := sign.MakeSignatures(payload, k)
   875  		if err != nil {
   876  			return nil, err
   877  		}
   878  		allSigs = append(allSigs, sigs...)
   879  	}
   880  	return allSigs, nil
   881  }
   882  
   883  func (r *Repo) Sign(roleFilename string) error {
   884  	signed, err := r.SignedMeta(roleFilename)
   885  	if err != nil {
   886  		return err
   887  	}
   888  
   889  	role := strings.TrimSuffix(roleFilename, ".json")
   890  	numKeys, err := r.SignPayload(role, signed)
   891  	if errors.Is(err, ErrNoKeys{role}) {
   892  		return ErrNoKeys{roleFilename}
   893  	} else if err != nil {
   894  		return err
   895  	}
   896  
   897  	b, err := r.jsonMarshal(signed)
   898  	if err != nil {
   899  		return err
   900  	}
   901  	r.meta[roleFilename] = b
   902  	err = r.local.SetMeta(roleFilename, b)
   903  	if err == nil {
   904  		r.logger.Println("Signed", roleFilename, "with", numKeys, "key(s)")
   905  	}
   906  	return err
   907  }
   908  
   909  // AddOrUpdateSignature allows users to add or update a signature generated with an external tool.
   910  // The name must be a valid metadata file name, like root.json.
   911  func (r *Repo) AddOrUpdateSignature(roleFilename string, signature data.Signature) error {
   912  	role := strings.TrimSuffix(roleFilename, ".json")
   913  
   914  	// Check key ID is in valid for the role.
   915  	dbs, err := r.dbsForRole(role)
   916  	if err != nil {
   917  		return err
   918  	}
   919  
   920  	if len(dbs) == 0 {
   921  		return ErrInvalidRole{role, "no trusted keys for role"}
   922  	}
   923  
   924  	s, err := r.SignedMeta(roleFilename)
   925  	if err != nil {
   926  		return err
   927  	}
   928  
   929  	keyInDB := false
   930  	validSig := false
   931  	for _, db := range dbs {
   932  		roleData := db.GetRole(role)
   933  		if roleData == nil {
   934  			return ErrInvalidRole{role, "role is not in verifier DB"}
   935  		}
   936  		if roleData.ValidKey(signature.KeyID) {
   937  			keyInDB = true
   938  
   939  			verifier, err := db.GetVerifier(signature.KeyID)
   940  			if err != nil {
   941  				continue
   942  			}
   943  
   944  			// Now check if this validly signed the metadata.
   945  			if err := verify.VerifySignature(s.Signed, signature.Signature,
   946  				verifier); err == nil {
   947  				validSig = true
   948  				break
   949  			}
   950  		}
   951  	}
   952  	if !keyInDB {
   953  		// This key was not delegated for the role in any delegatee.
   954  		return verify.ErrInvalidKey
   955  	}
   956  	if !validSig {
   957  		// The signature was invalid.
   958  		return verify.ErrInvalid
   959  	}
   960  
   961  	// Add or update signature.
   962  	signatures := make([]data.Signature, 0, len(s.Signatures)+1)
   963  	for _, sig := range s.Signatures {
   964  		if sig.KeyID != signature.KeyID {
   965  			signatures = append(signatures, sig)
   966  		}
   967  	}
   968  	signatures = append(signatures, signature)
   969  	s.Signatures = signatures
   970  
   971  	b, err := r.jsonMarshal(s)
   972  	if err != nil {
   973  		return err
   974  	}
   975  	r.meta[roleFilename] = b
   976  
   977  	return r.local.SetMeta(roleFilename, b)
   978  }
   979  
   980  // getSignersInDB returns available signing interfaces, sorted by key ID.
   981  //
   982  // Only keys contained in the keys db are returned (i.e. local keys which have
   983  // been revoked are omitted), except for the root role in which case all local
   984  // keys are returned (revoked root keys still need to sign new root metadata so
   985  // clients can verify the new root.json and update their keys db accordingly).
   986  func (r *Repo) getSignersInDB(roleName string, db *verify.DB) ([]keys.Signer, error) {
   987  	signers, err := r.local.GetSigners(roleName)
   988  	if err != nil {
   989  		return nil, err
   990  	}
   991  
   992  	if roleName == "root" {
   993  		sorted := make([]keys.Signer, len(signers))
   994  		copy(sorted, signers)
   995  		sort.Sort(signer.ByIDs(sorted))
   996  		return sorted, nil
   997  	}
   998  
   999  	role := db.GetRole(roleName)
  1000  	if role == nil {
  1001  		return nil, nil
  1002  	}
  1003  	if len(role.KeyIDs) == 0 {
  1004  		return nil, nil
  1005  	}
  1006  
  1007  	signersInDB := []keys.Signer{}
  1008  	for _, s := range signers {
  1009  		for _, id := range s.PublicData().IDs() {
  1010  			if _, ok := role.KeyIDs[id]; ok {
  1011  				signersInDB = append(signersInDB, s)
  1012  			}
  1013  		}
  1014  	}
  1015  
  1016  	sort.Sort(signer.ByIDs(signersInDB))
  1017  
  1018  	return signersInDB, nil
  1019  }
  1020  
  1021  // Used to retrieve the signable portion of the metadata when using an external signing tool.
  1022  func (r *Repo) SignedMeta(roleFilename string) (*data.Signed, error) {
  1023  	b, ok := r.meta[roleFilename]
  1024  	if !ok {
  1025  		return nil, ErrMissingMetadata{roleFilename}
  1026  	}
  1027  	s := &data.Signed{}
  1028  	if err := json.Unmarshal(b, s); err != nil {
  1029  		return nil, err
  1030  	}
  1031  	return s, nil
  1032  }
  1033  
  1034  // delegatorDBs returns a list of key DBs for all incoming delegations.
  1035  func (r *Repo) delegatorDBs(delegateeRole string) ([]*verify.DB, error) {
  1036  	delegatorDBs := []*verify.DB{}
  1037  	for metaName := range r.meta {
  1038  		if roles.IsTopLevelManifest(metaName) && metaName != "targets.json" {
  1039  			continue
  1040  		}
  1041  		roleName := strings.TrimSuffix(metaName, ".json")
  1042  
  1043  		t, err := r.targets(roleName)
  1044  		if err != nil {
  1045  			return nil, err
  1046  		}
  1047  
  1048  		if t.Delegations == nil {
  1049  			continue
  1050  		}
  1051  
  1052  		delegatesToRole := false
  1053  		for _, d := range t.Delegations.Roles {
  1054  			if d.Name == delegateeRole {
  1055  				delegatesToRole = true
  1056  				break
  1057  			}
  1058  		}
  1059  		if !delegatesToRole {
  1060  			continue
  1061  		}
  1062  
  1063  		db, err := verify.NewDBFromDelegations(t.Delegations)
  1064  		if err != nil {
  1065  			return nil, err
  1066  		}
  1067  
  1068  		delegatorDBs = append(delegatorDBs, db)
  1069  	}
  1070  
  1071  	return delegatorDBs, nil
  1072  }
  1073  
  1074  // targetDelegationForPath finds the targets metadata for the role that should
  1075  // sign the given path. The final delegation that led to the returned target
  1076  // metadata is also returned.
  1077  //
  1078  // Since there may be multiple targets roles that are able to sign a specific
  1079  // path, we must choose which roles's metadata to return. If preferredRole is
  1080  // specified (non-empty string) and eligible to sign the given path by way of
  1081  // some delegation chain, targets metadata for that role is returned. If
  1082  // preferredRole is not specified (""), we return targets metadata for the
  1083  // final role visited in the depth-first delegation traversal.
  1084  func (r *Repo) targetDelegationForPath(path string, preferredRole string) (*data.Targets, *targets.Delegation, error) {
  1085  	topLevelKeysDB, err := r.topLevelKeysDB()
  1086  	if err != nil {
  1087  		return nil, nil, err
  1088  	}
  1089  
  1090  	iterator, err := targets.NewDelegationsIterator(path, topLevelKeysDB)
  1091  	if err != nil {
  1092  		return nil, nil, err
  1093  	}
  1094  	d, ok := iterator.Next()
  1095  	if !ok {
  1096  		return nil, nil, ErrNoDelegatedTarget{Path: path}
  1097  	}
  1098  
  1099  	for i := 0; i < defaultMaxDelegations; i++ {
  1100  		targetsMeta, err := r.targets(d.Delegatee.Name)
  1101  		if err != nil {
  1102  			return nil, nil, err
  1103  		}
  1104  
  1105  		if preferredRole != "" && d.Delegatee.Name == preferredRole {
  1106  			// The preferredRole is eligible to sign for the given path, and we've
  1107  			// found its metadata. Return it.
  1108  			return targetsMeta, &d, nil
  1109  		}
  1110  
  1111  		if targetsMeta.Delegations != nil && len(targetsMeta.Delegations.Roles) > 0 {
  1112  			db, err := verify.NewDBFromDelegations(targetsMeta.Delegations)
  1113  			if err != nil {
  1114  				return nil, nil, err
  1115  			}
  1116  
  1117  			// Add delegations to the iterator that are eligible to sign for the
  1118  			// given path (there may be none).
  1119  			iterator.Add(targetsMeta.Delegations.Roles, d.Delegatee.Name, db)
  1120  		}
  1121  
  1122  		next, ok := iterator.Next()
  1123  		if !ok { // No more roles to traverse.
  1124  			if preferredRole == "" {
  1125  				// No preferredRole was given, so return metadata for the final role in the traversal.
  1126  				return targetsMeta, &d, nil
  1127  			} else {
  1128  				// There are no more roles to traverse, so preferredRole is either an
  1129  				// invalid role, or not eligible to sign the given path.
  1130  				return nil, nil, ErrNoDelegatedTarget{Path: path}
  1131  			}
  1132  		}
  1133  
  1134  		d = next
  1135  	}
  1136  
  1137  	return nil, nil, ErrNoDelegatedTarget{Path: path}
  1138  }
  1139  
  1140  func (r *Repo) AddTarget(path string, custom json.RawMessage) error {
  1141  	return r.AddTargets([]string{path}, custom)
  1142  }
  1143  
  1144  func (r *Repo) AddTargetToPreferredRole(path string, custom json.RawMessage, preferredRole string) error {
  1145  	return r.AddTargetsToPreferredRole([]string{path}, custom, preferredRole)
  1146  }
  1147  
  1148  func (r *Repo) AddTargets(paths []string, custom json.RawMessage) error {
  1149  	return r.AddTargetsToPreferredRole(paths, custom, "")
  1150  }
  1151  
  1152  func (r *Repo) AddTargetsToPreferredRole(paths []string, custom json.RawMessage, preferredRole string) error {
  1153  	return r.AddTargetsWithExpiresToPreferredRole(paths, custom, data.DefaultExpires("targets"), preferredRole)
  1154  }
  1155  
  1156  func (r *Repo) AddTargetsWithDigest(digest string, digestAlg string, length int64, path string, custom json.RawMessage) error {
  1157  	// TODO: Rename this to AddTargetWithDigest
  1158  	// https://github.com/theupdateframework/go-tuf/issues/242
  1159  
  1160  	expires := data.DefaultExpires("targets")
  1161  	path = util.NormalizeTarget(path)
  1162  
  1163  	targetsMeta, delegation, err := r.targetDelegationForPath(path, "")
  1164  	if err != nil {
  1165  		return err
  1166  	}
  1167  	// This is the targets role that needs to sign the target file.
  1168  	targetsRoleName := delegation.Delegatee.Name
  1169  
  1170  	meta := data.TargetFileMeta{FileMeta: data.FileMeta{Length: length, Hashes: make(data.Hashes, 1)}}
  1171  	meta.Hashes[digestAlg], err = hex.DecodeString(digest)
  1172  	if err != nil {
  1173  		return err
  1174  	}
  1175  
  1176  	// If custom is provided, set custom, otherwise maintain existing custom
  1177  	// metadata
  1178  	if len(custom) > 0 {
  1179  		meta.Custom = &custom
  1180  	} else if t, ok := targetsMeta.Targets[path]; ok {
  1181  		meta.Custom = t.Custom
  1182  	}
  1183  
  1184  	// What does G2 mean? Copying and pasting this comment from elsewhere in this file.
  1185  	// G2 -> we no longer desire any readers to ever observe non-prefix targets.
  1186  	delete(targetsMeta.Targets, "/"+path)
  1187  	targetsMeta.Targets[path] = meta
  1188  
  1189  	targetsMeta.Expires = expires.Round(time.Second)
  1190  
  1191  	manifestName := targetsRoleName + ".json"
  1192  	if !r.local.FileIsStaged(manifestName) {
  1193  		targetsMeta.Version++
  1194  	}
  1195  
  1196  	err = r.setMeta(manifestName, targetsMeta)
  1197  	if err != nil {
  1198  		return fmt.Errorf("error setting metadata for %q: %w", manifestName, err)
  1199  	}
  1200  
  1201  	return nil
  1202  }
  1203  
  1204  func (r *Repo) AddTargetWithExpires(path string, custom json.RawMessage, expires time.Time) error {
  1205  	return r.AddTargetsWithExpires([]string{path}, custom, expires)
  1206  }
  1207  
  1208  func (r *Repo) AddTargetsWithExpires(paths []string, custom json.RawMessage, expires time.Time) error {
  1209  	return r.AddTargetsWithExpiresToPreferredRole(paths, custom, expires, "")
  1210  }
  1211  
  1212  func (r *Repo) AddTargetWithExpiresToPreferredRole(path string, custom json.RawMessage, expires time.Time, preferredRole string) error {
  1213  	return r.AddTargetsWithExpiresToPreferredRole([]string{path}, custom, expires, preferredRole)
  1214  }
  1215  
  1216  // AddTargetsWithExpiresToPreferredRole signs the staged targets at `paths`.
  1217  //
  1218  // If preferredRole is not the empty string, the target is added to the given
  1219  // role's manifest if delegations allow it. If delegations do not allow the
  1220  // preferredRole to sign the given path, an error is returned.
  1221  func (r *Repo) AddTargetsWithExpiresToPreferredRole(paths []string, custom json.RawMessage, expires time.Time, preferredRole string) error {
  1222  	if !validExpires(expires) {
  1223  		return ErrInvalidExpires{expires}
  1224  	}
  1225  
  1226  	normalizedPaths := make([]string, len(paths))
  1227  	for i, path := range paths {
  1228  		normalizedPaths[i] = util.NormalizeTarget(path)
  1229  	}
  1230  
  1231  	// As we iterate through staged targets files, we accumulate changes to their
  1232  	// corresponding targets metadata.
  1233  	updatedTargetsMeta := map[string]*data.Targets{}
  1234  
  1235  	if err := r.local.WalkStagedTargets(normalizedPaths, func(path string, target io.Reader) (err error) {
  1236  		originalMeta, delegation, err := r.targetDelegationForPath(path, preferredRole)
  1237  		if err != nil {
  1238  			return err
  1239  		}
  1240  
  1241  		// This is the targets role that needs to sign the target file.
  1242  		targetsRoleName := delegation.Delegatee.Name
  1243  
  1244  		targetsMeta := originalMeta
  1245  		if tm, ok := updatedTargetsMeta[targetsRoleName]; ok {
  1246  			// Metadata in updatedTargetsMeta overrides staged/commited metadata.
  1247  			targetsMeta = tm
  1248  		}
  1249  
  1250  		fileMeta, err := util.GenerateTargetFileMeta(target, r.hashAlgorithms...)
  1251  		if err != nil {
  1252  			return err
  1253  		}
  1254  
  1255  		// If we have custom metadata, set it, otherwise maintain
  1256  		// existing metadata if present
  1257  		if len(custom) > 0 {
  1258  			fileMeta.Custom = &custom
  1259  		} else if tf, ok := targetsMeta.Targets[path]; ok {
  1260  			fileMeta.Custom = tf.Custom
  1261  		}
  1262  
  1263  		// G2 -> we no longer desire any readers to ever observe non-prefix targets.
  1264  		delete(targetsMeta.Targets, "/"+path)
  1265  		targetsMeta.Targets[path] = fileMeta
  1266  
  1267  		updatedTargetsMeta[targetsRoleName] = targetsMeta
  1268  
  1269  		return nil
  1270  	}); err != nil {
  1271  		return err
  1272  	}
  1273  
  1274  	if len(updatedTargetsMeta) == 0 {
  1275  		// This is potentially unexpected behavior kept for backwards compatibility.
  1276  		// See https://github.com/theupdateframework/go-tuf/issues/243
  1277  		t, err := r.topLevelTargets()
  1278  		if err != nil {
  1279  			return err
  1280  		}
  1281  
  1282  		updatedTargetsMeta["targets"] = t
  1283  	}
  1284  
  1285  	exp := expires.Round(time.Second)
  1286  	for roleName, targetsMeta := range updatedTargetsMeta {
  1287  		targetsMeta.Expires = exp
  1288  
  1289  		manifestName := roleName + ".json"
  1290  		if !r.local.FileIsStaged(manifestName) {
  1291  			targetsMeta.Version++
  1292  		}
  1293  
  1294  		err := r.setMeta(manifestName, targetsMeta)
  1295  		if err != nil {
  1296  			return fmt.Errorf("error setting metadata for %q: %w", manifestName, err)
  1297  		}
  1298  	}
  1299  
  1300  	return nil
  1301  }
  1302  
  1303  func (r *Repo) RemoveTarget(path string) error {
  1304  	return r.RemoveTargets([]string{path})
  1305  }
  1306  
  1307  func (r *Repo) RemoveTargets(paths []string) error {
  1308  	return r.RemoveTargetsWithExpires(paths, data.DefaultExpires("targets"))
  1309  }
  1310  
  1311  func (r *Repo) RemoveTargetWithExpires(path string, expires time.Time) error {
  1312  	return r.RemoveTargetsWithExpires([]string{path}, expires)
  1313  }
  1314  
  1315  // If paths is empty, all targets will be removed.
  1316  func (r *Repo) RemoveTargetsWithExpires(paths []string, expires time.Time) error {
  1317  	if !validExpires(expires) {
  1318  		return ErrInvalidExpires{expires}
  1319  	}
  1320  
  1321  	for metaName := range r.meta {
  1322  		if metaName != "targets.json" && !roles.IsDelegatedTargetsManifest(metaName) {
  1323  			continue
  1324  		}
  1325  
  1326  		err := r.removeTargetsWithExpiresFromMeta(metaName, paths, expires)
  1327  		if err != nil {
  1328  			return fmt.Errorf("could not remove %v from %v: %w", paths, metaName, err)
  1329  		}
  1330  	}
  1331  
  1332  	return nil
  1333  }
  1334  
  1335  func (r *Repo) removeTargetsWithExpiresFromMeta(metaName string, paths []string, expires time.Time) error {
  1336  	roleName := strings.TrimSuffix(metaName, ".json")
  1337  	t, err := r.targets(roleName)
  1338  	if err != nil {
  1339  		return err
  1340  	}
  1341  	removed_targets := []string{}
  1342  	if len(paths) == 0 {
  1343  		for rt := range t.Targets {
  1344  			removed_targets = append(removed_targets, rt)
  1345  		}
  1346  		t.Targets = make(data.TargetFiles)
  1347  	} else {
  1348  		removed := false
  1349  		for _, path := range paths {
  1350  			path = util.NormalizeTarget(path)
  1351  			if _, ok := t.Targets[path]; !ok {
  1352  				r.logger.Printf("[%v] The following target is not present: %v\n", metaName, path)
  1353  				continue
  1354  			}
  1355  			removed = true
  1356  			// G2 -> we no longer desire any readers to ever observe non-prefix targets.
  1357  			delete(t.Targets, "/"+path)
  1358  			delete(t.Targets, path)
  1359  			removed_targets = append(removed_targets, path)
  1360  		}
  1361  		if !removed {
  1362  			return nil
  1363  		}
  1364  	}
  1365  	t.Expires = expires.Round(time.Second)
  1366  	if !r.local.FileIsStaged(metaName) {
  1367  		t.Version++
  1368  	}
  1369  
  1370  	err = r.setMeta(metaName, t)
  1371  	if err == nil {
  1372  		r.logger.Printf("[%v] Removed targets:\n", metaName)
  1373  		for _, v := range removed_targets {
  1374  			r.logger.Println("*", v)
  1375  		}
  1376  		if len(t.Targets) != 0 {
  1377  			r.logger.Printf("[%v] Added/staged targets:\n", metaName)
  1378  			for k := range t.Targets {
  1379  				r.logger.Println("*", k)
  1380  			}
  1381  		} else {
  1382  			r.logger.Printf("[%v] There are no added/staged targets\n", metaName)
  1383  		}
  1384  	}
  1385  	return err
  1386  }
  1387  
  1388  func (r *Repo) Snapshot() error {
  1389  	return r.SnapshotWithExpires(data.DefaultExpires("snapshot"))
  1390  }
  1391  
  1392  func (r *Repo) snapshotMetadata() []string {
  1393  	ret := []string{"targets.json"}
  1394  
  1395  	for name := range r.meta {
  1396  		if !roles.IsVersionedManifest(name) &&
  1397  			roles.IsDelegatedTargetsManifest(name) {
  1398  			ret = append(ret, name)
  1399  		}
  1400  	}
  1401  
  1402  	return ret
  1403  }
  1404  
  1405  func (r *Repo) SnapshotWithExpires(expires time.Time) error {
  1406  	if !validExpires(expires) {
  1407  		return ErrInvalidExpires{expires}
  1408  	}
  1409  
  1410  	snapshot, err := r.snapshot()
  1411  	if err != nil {
  1412  		return err
  1413  	}
  1414  
  1415  	// Verify root metadata before verifying signatures on role metadata.
  1416  	if err := r.verifySignatures("root.json"); err != nil {
  1417  		return err
  1418  	}
  1419  
  1420  	for _, metaName := range r.snapshotMetadata() {
  1421  		if err := r.verifySignatures(metaName); err != nil {
  1422  			return err
  1423  		}
  1424  		var err error
  1425  		snapshot.Meta[metaName], err = r.snapshotFileMeta(metaName)
  1426  		if err != nil {
  1427  			return err
  1428  		}
  1429  	}
  1430  	snapshot.Expires = expires.Round(time.Second)
  1431  	if !r.local.FileIsStaged("snapshot.json") {
  1432  		snapshot.Version++
  1433  	}
  1434  	err = r.setMeta("snapshot.json", snapshot)
  1435  	if err == nil {
  1436  		r.logger.Println("Staged snapshot.json metadata with expiration date:", snapshot.Expires)
  1437  	}
  1438  	return err
  1439  }
  1440  
  1441  func (r *Repo) Timestamp() error {
  1442  	return r.TimestampWithExpires(data.DefaultExpires("timestamp"))
  1443  }
  1444  
  1445  func (r *Repo) TimestampWithExpires(expires time.Time) error {
  1446  	if !validExpires(expires) {
  1447  		return ErrInvalidExpires{expires}
  1448  	}
  1449  
  1450  	if err := r.verifySignatures("snapshot.json"); err != nil {
  1451  		return err
  1452  	}
  1453  	timestamp, err := r.timestamp()
  1454  	if err != nil {
  1455  		return err
  1456  	}
  1457  	timestamp.Meta["snapshot.json"], err = r.timestampFileMeta("snapshot.json")
  1458  	if err != nil {
  1459  		return err
  1460  	}
  1461  	timestamp.Expires = expires.Round(time.Second)
  1462  	if !r.local.FileIsStaged("timestamp.json") {
  1463  		timestamp.Version++
  1464  	}
  1465  
  1466  	err = r.setMeta("timestamp.json", timestamp)
  1467  	if err == nil {
  1468  		r.logger.Println("Staged timestamp.json metadata with expiration date:", timestamp.Expires)
  1469  	}
  1470  	return err
  1471  }
  1472  
  1473  func (r *Repo) fileVersions() (map[string]int64, error) {
  1474  	versions := make(map[string]int64)
  1475  
  1476  	for fileName := range r.meta {
  1477  		if roles.IsVersionedManifest(fileName) {
  1478  			continue
  1479  		}
  1480  
  1481  		roleName := strings.TrimSuffix(fileName, ".json")
  1482  
  1483  		var version int64
  1484  
  1485  		switch roleName {
  1486  		case "root":
  1487  			root, err := r.root()
  1488  			if err != nil {
  1489  				return nil, err
  1490  			}
  1491  			version = root.Version
  1492  		case "snapshot":
  1493  			snapshot, err := r.snapshot()
  1494  			if err != nil {
  1495  				return nil, err
  1496  			}
  1497  			version = snapshot.Version
  1498  		case "timestamp":
  1499  			continue
  1500  		default:
  1501  			// Targets or delegated targets manifest.
  1502  			targets, err := r.targets(roleName)
  1503  			if err != nil {
  1504  				return nil, err
  1505  			}
  1506  
  1507  			version = targets.Version
  1508  		}
  1509  
  1510  		versions[fileName] = version
  1511  	}
  1512  
  1513  	return versions, nil
  1514  }
  1515  
  1516  func (r *Repo) fileHashes() (map[string]data.Hashes, error) {
  1517  	hashes := make(map[string]data.Hashes)
  1518  
  1519  	for fileName := range r.meta {
  1520  		if roles.IsVersionedManifest(fileName) {
  1521  			continue
  1522  		}
  1523  
  1524  		roleName := strings.TrimSuffix(fileName, ".json")
  1525  
  1526  		switch roleName {
  1527  		case "snapshot":
  1528  			timestamp, err := r.timestamp()
  1529  			if err != nil {
  1530  				return nil, err
  1531  			}
  1532  
  1533  			if m, ok := timestamp.Meta[fileName]; ok {
  1534  				hashes[fileName] = m.Hashes
  1535  			}
  1536  		case "timestamp":
  1537  			continue
  1538  		default:
  1539  			snapshot, err := r.snapshot()
  1540  			if err != nil {
  1541  				return nil, err
  1542  			}
  1543  			if m, ok := snapshot.Meta[fileName]; ok {
  1544  				hashes[fileName] = m.Hashes
  1545  			}
  1546  
  1547  			if roleName != "root" {
  1548  				// Scalability issue: Commit/fileHashes loads all targets metadata into memory
  1549  				// https://github.com/theupdateframework/go-tuf/issues/245
  1550  				t, err := r.targets(roleName)
  1551  				if err != nil {
  1552  					return nil, err
  1553  				}
  1554  				for name, m := range t.Targets {
  1555  					hashes[path.Join("targets", name)] = m.Hashes
  1556  				}
  1557  			}
  1558  
  1559  		}
  1560  
  1561  	}
  1562  
  1563  	return hashes, nil
  1564  }
  1565  
  1566  func (r *Repo) Commit() error {
  1567  	// check we have all the metadata
  1568  	for _, name := range topLevelMetadata {
  1569  		if _, ok := r.meta[name]; !ok {
  1570  			return ErrMissingMetadata{name}
  1571  		}
  1572  	}
  1573  
  1574  	// check roles are valid
  1575  	root, err := r.root()
  1576  	if err != nil {
  1577  		return err
  1578  	}
  1579  	for name, role := range root.Roles {
  1580  		if len(role.KeyIDs) < role.Threshold {
  1581  			return ErrNotEnoughKeys{name, len(role.KeyIDs), role.Threshold}
  1582  		}
  1583  	}
  1584  
  1585  	// verify hashes in snapshot.json are up to date
  1586  	snapshot, err := r.snapshot()
  1587  	if err != nil {
  1588  		return err
  1589  	}
  1590  	for _, name := range r.snapshotMetadata() {
  1591  		expected, ok := snapshot.Meta[name]
  1592  		if !ok {
  1593  			return fmt.Errorf("tuf: snapshot.json missing hash for %s", name)
  1594  		}
  1595  		actual, err := r.snapshotFileMeta(name)
  1596  		if err != nil {
  1597  			return err
  1598  		}
  1599  		if err := util.SnapshotFileMetaEqual(actual, expected); err != nil {
  1600  			return fmt.Errorf("tuf: invalid %s in snapshot.json: %s", name, err)
  1601  		}
  1602  	}
  1603  
  1604  	// verify hashes in timestamp.json are up to date
  1605  	timestamp, err := r.timestamp()
  1606  	if err != nil {
  1607  		return err
  1608  	}
  1609  	snapshotMeta, err := r.timestampFileMeta("snapshot.json")
  1610  	if err != nil {
  1611  		return err
  1612  	}
  1613  	if err := util.TimestampFileMetaEqual(snapshotMeta, timestamp.Meta["snapshot.json"]); err != nil {
  1614  		return fmt.Errorf("tuf: invalid snapshot.json in timestamp.json: %s", err)
  1615  	}
  1616  
  1617  	for _, name := range topLevelMetadata {
  1618  		if err := r.verifySignatures(name); err != nil {
  1619  			return err
  1620  		}
  1621  	}
  1622  
  1623  	versions, err := r.fileVersions()
  1624  	if err != nil {
  1625  		return err
  1626  	}
  1627  	hashes, err := r.fileHashes()
  1628  	if err != nil {
  1629  		return err
  1630  	}
  1631  
  1632  	err = r.local.Commit(root.ConsistentSnapshot, versions, hashes)
  1633  	if err == nil {
  1634  		r.logger.Println("Committed successfully")
  1635  	}
  1636  	return err
  1637  }
  1638  
  1639  func (r *Repo) Clean() error {
  1640  	err := r.local.Clean()
  1641  	if err == nil {
  1642  		r.logger.Println("Removed all staged metadata and target files")
  1643  	}
  1644  	return err
  1645  }
  1646  
  1647  func (r *Repo) verifySignatures(metaFilename string) error {
  1648  	s, err := r.SignedMeta(metaFilename)
  1649  	if err != nil {
  1650  		return err
  1651  	}
  1652  
  1653  	role := strings.TrimSuffix(metaFilename, ".json")
  1654  
  1655  	dbs, err := r.dbsForRole(role)
  1656  	if err != nil {
  1657  		return err
  1658  	}
  1659  
  1660  	for _, db := range dbs {
  1661  		if err := db.Verify(s, role, 0); err != nil {
  1662  			return ErrInsufficientSignatures{metaFilename, err}
  1663  		}
  1664  	}
  1665  
  1666  	return nil
  1667  }
  1668  
  1669  func (r *Repo) snapshotFileMeta(roleFilename string) (data.SnapshotFileMeta, error) {
  1670  	b, ok := r.meta[roleFilename]
  1671  	if !ok {
  1672  		return data.SnapshotFileMeta{}, ErrMissingMetadata{roleFilename}
  1673  	}
  1674  	return util.GenerateSnapshotFileMeta(bytes.NewReader(b), r.hashAlgorithms...)
  1675  }
  1676  
  1677  func (r *Repo) timestampFileMeta(roleFilename string) (data.TimestampFileMeta, error) {
  1678  	b, ok := r.meta[roleFilename]
  1679  	if !ok {
  1680  		return data.TimestampFileMeta{}, ErrMissingMetadata{roleFilename}
  1681  	}
  1682  	return util.GenerateTimestampFileMeta(bytes.NewReader(b), r.hashAlgorithms...)
  1683  }
  1684  
  1685  func (r *Repo) Payload(roleFilename string) ([]byte, error) {
  1686  	s, err := r.SignedMeta(roleFilename)
  1687  	if err != nil {
  1688  		return nil, err
  1689  	}
  1690  
  1691  	p, err := cjson.EncodeCanonical(s.Signed)
  1692  	if err != nil {
  1693  		return nil, err
  1694  	}
  1695  
  1696  	return p, nil
  1697  }
  1698  
  1699  func (r *Repo) CheckRoleUnexpired(role string, validAt time.Time) error {
  1700  	var expires time.Time
  1701  	switch role {
  1702  	case "root":
  1703  		root, err := r.root()
  1704  		if err != nil {
  1705  			return err
  1706  		}
  1707  		expires = root.Expires
  1708  	case "snapshot":
  1709  		snapshot, err := r.snapshot()
  1710  		if err != nil {
  1711  			return err
  1712  		}
  1713  		expires = snapshot.Expires
  1714  	case "timestamp":
  1715  		timestamp, err := r.timestamp()
  1716  		if err != nil {
  1717  			return err
  1718  		}
  1719  		expires = timestamp.Expires
  1720  	case "targets":
  1721  		targets, err := r.topLevelTargets()
  1722  		if err != nil {
  1723  			return err
  1724  		}
  1725  		expires = targets.Expires
  1726  	default:
  1727  		return fmt.Errorf("invalid role: %s", role)
  1728  	}
  1729  	if expires.Before(validAt) || expires.Equal(validAt) {
  1730  		return fmt.Errorf("role expired on: %s", expires)
  1731  	}
  1732  	return nil
  1733  }
  1734  
  1735  // GetMeta returns the underlying meta file map from the store.
  1736  func (r *Repo) GetMeta() (map[string]json.RawMessage, error) {
  1737  	return r.local.GetMeta()
  1738  }
  1739  

View as plain text