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
30 defaultMaxDelegations = 32
31 )
32
33
34 var topLevelMetadata = []string{
35 "root.json",
36 "targets.json",
37 "snapshot.json",
38 "timestamp.json",
39 }
40
41
42
43
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
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
201
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
219
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
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
347
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
374
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
418
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
427
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
434
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
445
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
459
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
466
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
525
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
550
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
557
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
583 filteredKeyIDs := make([]string, 0, len(role.KeyIDs))
584
585
586
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
599
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
626
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
632
633
634
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
696
697
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
703
704
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
730
731 func (r *Repo) ResetTargetsDelegations(delegator string) error {
732 return r.ResetTargetsDelegationsWithExpires(delegator, data.DefaultExpires("targets"))
733 }
734
735
736
737
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
829
830
831
832
833
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
851
852
853
854
855
856 func (r *Repo) SignPayload(role string, payload *data.Signed) (int, error) {
857 return r.CanonicalizeAndSign(role, payload)
858 }
859
860
861
862
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
910
911 func (r *Repo) AddOrUpdateSignature(roleFilename string, signature data.Signature) error {
912 role := strings.TrimSuffix(roleFilename, ".json")
913
914
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
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
954 return verify.ErrInvalidKey
955 }
956 if !validSig {
957
958 return verify.ErrInvalid
959 }
960
961
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
981
982
983
984
985
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
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
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
1075
1076
1077
1078
1079
1080
1081
1082
1083
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
1107
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
1118
1119 iterator.Add(targetsMeta.Delegations.Roles, d.Delegatee.Name, db)
1120 }
1121
1122 next, ok := iterator.Next()
1123 if !ok {
1124 if preferredRole == "" {
1125
1126 return targetsMeta, &d, nil
1127 } else {
1128
1129
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
1158
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
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
1177
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
1185
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
1217
1218
1219
1220
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
1232
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
1242 targetsRoleName := delegation.Delegatee.Name
1243
1244 targetsMeta := originalMeta
1245 if tm, ok := updatedTargetsMeta[targetsRoleName]; ok {
1246
1247 targetsMeta = tm
1248 }
1249
1250 fileMeta, err := util.GenerateTargetFileMeta(target, r.hashAlgorithms...)
1251 if err != nil {
1252 return err
1253 }
1254
1255
1256
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
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
1276
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
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
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
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
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
1549
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
1568 for _, name := range topLevelMetadata {
1569 if _, ok := r.meta[name]; !ok {
1570 return ErrMissingMetadata{name}
1571 }
1572 }
1573
1574
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
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
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
1736 func (r *Repo) GetMeta() (map[string]json.RawMessage, error) {
1737 return r.local.GetMeta()
1738 }
1739
View as plain text