1 package tuf
2
3 import (
4 "bytes"
5 "crypto"
6 "crypto/elliptic"
7 "crypto/rand"
8 "encoding/hex"
9 "encoding/json"
10 "errors"
11 "fmt"
12 "log"
13 "os"
14 "path"
15 "path/filepath"
16 "reflect"
17 "sort"
18 "strings"
19 "testing"
20 "time"
21
22 "github.com/secure-systems-lab/go-securesystemslib/cjson"
23 "github.com/secure-systems-lab/go-securesystemslib/encrypted"
24 "github.com/theupdateframework/go-tuf/data"
25 "github.com/theupdateframework/go-tuf/internal/sets"
26 "github.com/theupdateframework/go-tuf/pkg/keys"
27 "github.com/theupdateframework/go-tuf/pkg/targets"
28 "github.com/theupdateframework/go-tuf/util"
29 "github.com/theupdateframework/go-tuf/verify"
30 "golang.org/x/crypto/ed25519"
31 . "gopkg.in/check.v1"
32 )
33
34
35 func Test(t *testing.T) { TestingT(t) }
36
37 type RepoSuite struct{}
38
39 var _ = Suite(&RepoSuite{})
40
41 func (RepoSuite) TestNewRepo(c *C) {
42 testNewRepo(c, NewRepo)
43 }
44
45 func (RepoSuite) TestNewRepoIndent(c *C) {
46 testNewRepo(c, func(local LocalStore, hashAlgorithms ...string) (*Repo, error) {
47 return NewRepoIndent(local, "", "\t")
48 })
49 }
50
51
52
53 func UniqueKeys(r *data.Root) map[string][]*data.PublicKey {
54 keysByRole := make(map[string][]*data.PublicKey)
55 for name, role := range r.Roles {
56 seen := make(map[string]struct{})
57 roleKeys := []*data.PublicKey{}
58 for _, id := range role.KeyIDs {
59
60 if key, ok := r.Keys[id]; ok {
61 verifier, err := keys.GetVerifier(key)
62 if err != nil {
63 continue
64 }
65 val := verifier.Public()
66 if _, ok := seen[val]; ok {
67 continue
68 }
69 seen[val] = struct{}{}
70 roleKeys = append(roleKeys, key)
71 }
72 }
73 keysByRole[name] = roleKeys
74 }
75 return keysByRole
76 }
77
78
79 func (*RepoSuite) assertNumUniqueKeys(c *C, root *data.Root, role string, num int) {
80 c.Assert(UniqueKeys(root)[role], HasLen, num)
81 }
82
83 func testNewRepo(c *C, newRepo func(local LocalStore, hashAlgorithms ...string) (*Repo, error)) {
84 meta := map[string]json.RawMessage{
85 "root.json": []byte(`{
86 "signed": {
87 "_type": "root",
88 "version": 1,
89 "expires": "2015-12-26T03:26:55.821520874Z",
90 "keys": {},
91 "roles": {}
92 },
93 "signatures": []
94 }`),
95 "targets.json": []byte(`{
96 "signed": {
97 "_type": "targets",
98 "version": 1,
99 "expires": "2015-03-26T03:26:55.82155686Z",
100 "targets": {}
101 },
102 "signatures": []
103 }`),
104 "snapshot.json": []byte(`{
105 "signed": {
106 "_type": "snapshot",
107 "version": 1,
108 "expires": "2015-01-02T03:26:55.821585981Z",
109 "meta": {}
110 },
111 "signatures": []
112 }`),
113 "timestamp.json": []byte(`{
114 "signed": {
115 "_type": "timestamp",
116 "version": 1,
117 "expires": "2014-12-27T03:26:55.821599702Z",
118 "meta": {}
119 },
120 "signatures": []
121 }`),
122 }
123 local := MemoryStore(meta, nil)
124 r, err := newRepo(local)
125 c.Assert(err, IsNil)
126
127 root, err := r.root()
128 c.Assert(err, IsNil)
129 c.Assert(root.Type, Equals, "root")
130 c.Assert(root.Version, Equals, int64(1))
131 c.Assert(root.Keys, NotNil)
132 c.Assert(root.Keys, HasLen, 0)
133
134 targets, err := r.topLevelTargets()
135 c.Assert(err, IsNil)
136 c.Assert(targets.Type, Equals, "targets")
137 c.Assert(targets.Version, Equals, int64(1))
138 c.Assert(targets.Targets, NotNil)
139 c.Assert(targets.Targets, HasLen, 0)
140
141 snapshot, err := r.snapshot()
142 c.Assert(err, IsNil)
143 c.Assert(snapshot.Type, Equals, "snapshot")
144 c.Assert(snapshot.Version, Equals, int64(1))
145 c.Assert(snapshot.Meta, NotNil)
146 c.Assert(snapshot.Meta, HasLen, 0)
147
148 timestamp, err := r.timestamp()
149 c.Assert(err, IsNil)
150 c.Assert(timestamp.Type, Equals, "timestamp")
151 c.Assert(timestamp.Version, Equals, int64(1))
152 c.Assert(timestamp.Meta, NotNil)
153 c.Assert(timestamp.Meta, HasLen, 0)
154 }
155
156 func (rs *RepoSuite) TestInit(c *C) {
157 local := MemoryStore(
158 make(map[string]json.RawMessage),
159 map[string][]byte{"foo.txt": []byte("foo")},
160 )
161 r, err := NewRepo(local)
162 c.Assert(err, IsNil)
163
164
165 for _, v := range []bool{true, false} {
166 c.Assert(r.Init(v), IsNil)
167 root, err := r.root()
168 c.Assert(err, IsNil)
169 c.Assert(root.ConsistentSnapshot, Equals, v)
170 }
171
172
173 generateAndAddPrivateKey(c, r, "targets")
174 c.Assert(r.AddTarget("foo.txt", nil), IsNil)
175
176
177 c.Assert(r.Init(true), Equals, ErrInitNotAllowed)
178 }
179
180 func genKey(c *C, r *Repo, role string) []string {
181 keyids, err := r.GenKey(role)
182 c.Assert(err, IsNil)
183 c.Assert(len(keyids) > 0, Equals, true)
184 return keyids
185 }
186
187 func (rs *RepoSuite) TestGenKey(c *C) {
188 local := MemoryStore(make(map[string]json.RawMessage), nil)
189 r, err := NewRepo(local)
190 c.Assert(err, IsNil)
191
192
193 _, err = r.GenKey("foo")
194 c.Assert(err, Equals, ErrInvalidRole{"foo", "only support adding keys for top-level roles"})
195
196
197 ids := genKey(c, r, "root")
198
199
200 root, err := r.root()
201 c.Assert(err, IsNil)
202 c.Assert(root.Roles, NotNil)
203 c.Assert(root.Roles, HasLen, 1)
204 rs.assertNumUniqueKeys(c, root, "root", 1)
205 rootRole, ok := root.Roles["root"]
206 if !ok {
207 c.Fatal("missing root role")
208 }
209 c.Assert(rootRole.KeyIDs, HasLen, 1)
210 c.Assert(rootRole.KeyIDs, DeepEquals, ids)
211 for _, keyID := range ids {
212 k, ok := root.Keys[keyID]
213 if !ok {
214 c.Fatal("missing key")
215 }
216 c.Assert(k.IDs(), DeepEquals, ids)
217 pk, err := keys.GetVerifier(k)
218 c.Assert(err, IsNil)
219 c.Assert(pk.Public(), HasLen, ed25519.PublicKeySize)
220 }
221
222
223 db, err := r.topLevelKeysDB()
224 c.Assert(err, IsNil)
225 for _, keyID := range ids {
226 rootKey, err := db.GetVerifier(keyID)
227 c.Assert(err, IsNil)
228 c.Assert(rootKey.MarshalPublicKey().IDs(), DeepEquals, ids)
229 role := db.GetRole("root")
230 c.Assert(role.KeyIDs, DeepEquals, sets.StringSliceToSet(ids))
231
232
233 localKeys, err := local.GetSigners("root")
234 c.Assert(err, IsNil)
235 c.Assert(localKeys, HasLen, 1)
236 c.Assert(localKeys[0].PublicData().IDs(), DeepEquals, ids)
237
238
239 rootKeys, err := r.RootKeys()
240 c.Assert(err, IsNil)
241 c.Assert(rootKeys, HasLen, 1)
242 c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalPublicKey().IDs())
243 pk, err := keys.GetVerifier(rootKeys[0])
244 c.Assert(err, IsNil)
245 c.Assert(pk.Public(), DeepEquals, rootKey.Public())
246 }
247
248 rootKey, err := db.GetVerifier(ids[0])
249 c.Assert(err, IsNil)
250
251
252 genKey(c, r, "targets")
253 genKey(c, r, "targets")
254
255
256 root, err = r.root()
257 c.Assert(err, IsNil)
258 c.Assert(root.Roles, HasLen, 2)
259 rs.assertNumUniqueKeys(c, root, "root", 1)
260 rs.assertNumUniqueKeys(c, root, "targets", 2)
261 targetsRole, ok := root.Roles["targets"]
262 if !ok {
263 c.Fatal("missing targets role")
264 }
265 c.Assert(targetsRole.KeyIDs, HasLen, 2)
266 targetKeyIDs := make(map[string]struct{}, 2)
267 db, err = r.topLevelKeysDB()
268 c.Assert(err, IsNil)
269 for _, id := range targetsRole.KeyIDs {
270 targetKeyIDs[id] = struct{}{}
271 _, ok = root.Keys[id]
272 if !ok {
273 c.Fatal("missing key")
274 }
275 verifier, err := db.GetVerifier(id)
276 c.Assert(err, IsNil)
277 c.Assert(verifier.MarshalPublicKey().ContainsID(id), Equals, true)
278 }
279 role := db.GetRole("targets")
280 c.Assert(role.KeyIDs, DeepEquals, targetKeyIDs)
281
282
283 rootKeys, err := r.RootKeys()
284 c.Assert(err, IsNil)
285 c.Assert(rootKeys, HasLen, 1)
286 c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalPublicKey().IDs())
287
288
289 localKeys, err := local.GetSigners("targets")
290 c.Assert(err, IsNil)
291 c.Assert(localKeys, HasLen, 2)
292 for _, key := range localKeys {
293 found := false
294 for _, id := range targetsRole.KeyIDs {
295 if key.PublicData().ContainsID(id) {
296 found = true
297 break
298 }
299 }
300 if !found {
301 c.Fatal("missing key")
302 }
303 }
304
305
306 meta, err := local.GetMeta()
307 c.Assert(err, IsNil)
308 rootJSON, ok := meta["root.json"]
309 if !ok {
310 c.Fatal("missing root metadata")
311 }
312 s := &data.Signed{}
313 c.Assert(json.Unmarshal(rootJSON, s), IsNil)
314 stagedRoot := &data.Root{}
315 c.Assert(json.Unmarshal(s.Signed, stagedRoot), IsNil)
316 c.Assert(stagedRoot.Type, Equals, root.Type)
317 c.Assert(stagedRoot.Version, Equals, root.Version)
318 c.Assert(stagedRoot.Expires.UnixNano(), Equals, root.Expires.UnixNano())
319
320
321
322
323 for _, key := range root.Keys {
324 key.IDs()
325 }
326 for _, key := range stagedRoot.Keys {
327 key.IDs()
328 }
329 c.Assert(stagedRoot.Keys, DeepEquals, root.Keys)
330 c.Assert(stagedRoot.Roles, DeepEquals, root.Roles)
331 }
332
333 func addPrivateKey(c *C, r *Repo, role string, key keys.Signer) []string {
334 err := r.AddPrivateKey(role, key)
335 c.Assert(err, IsNil)
336 keyids := key.PublicData().IDs()
337 c.Assert(len(keyids) > 0, Equals, true)
338 return keyids
339 }
340
341 func generateAndAddPrivateKey(c *C, r *Repo, role string) []string {
342 signer, err := keys.GenerateEd25519Key()
343 c.Assert(err, IsNil)
344 return addPrivateKey(c, r, role, signer)
345 }
346
347 func (rs *RepoSuite) TestAddPrivateKey(c *C) {
348 local := MemoryStore(make(map[string]json.RawMessage), nil)
349 r, err := NewRepo(local)
350 c.Assert(err, IsNil)
351
352
353 signer, err := keys.GenerateEd25519Key()
354 c.Assert(err, IsNil)
355 err = r.AddPrivateKey("foo", signer)
356 c.Assert(err, Equals, ErrInvalidRole{"foo", "only support adding keys for top-level roles"})
357
358
359 ids := addPrivateKey(c, r, "root", signer)
360
361
362 root, err := r.root()
363 c.Assert(err, IsNil)
364 c.Assert(root.Version, Equals, int64(1))
365 c.Assert(root.Roles, NotNil)
366 c.Assert(root.Roles, HasLen, 1)
367 rs.assertNumUniqueKeys(c, root, "root", 1)
368 rootRole, ok := root.Roles["root"]
369 if !ok {
370 c.Fatal("missing root role")
371 }
372 c.Assert(rootRole.KeyIDs, HasLen, 1)
373 c.Assert(rootRole.KeyIDs, DeepEquals, ids)
374 for _, keyID := range ids {
375 k, ok := root.Keys[keyID]
376 if !ok {
377 c.Fatalf("missing key %s", keyID)
378 }
379 c.Assert(k.IDs(), DeepEquals, ids)
380 pk, err := keys.GetVerifier(k)
381 c.Assert(err, IsNil)
382 c.Assert(pk.Public(), HasLen, ed25519.PublicKeySize)
383 }
384
385
386 db, err := r.topLevelKeysDB()
387 c.Assert(err, IsNil)
388 for _, keyID := range ids {
389 rootKey, err := db.GetVerifier(keyID)
390 c.Assert(err, IsNil)
391 c.Assert(rootKey.MarshalPublicKey().IDs(), DeepEquals, ids)
392 role := db.GetRole("root")
393 c.Assert(role.KeyIDs, DeepEquals, sets.StringSliceToSet(ids))
394
395
396 localKeys, err := local.GetSigners("root")
397 c.Assert(err, IsNil)
398 c.Assert(localKeys, HasLen, 1)
399 c.Assert(localKeys[0].PublicData().IDs(), DeepEquals, ids)
400
401
402 rootKeys, err := r.RootKeys()
403 c.Assert(err, IsNil)
404 c.Assert(rootKeys, HasLen, 1)
405 c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalPublicKey().IDs())
406 pk, err := keys.GetVerifier(rootKeys[0])
407 c.Assert(err, IsNil)
408 c.Assert(pk.Public(), DeepEquals, rootKey.Public())
409 }
410
411 rootKey, err := db.GetVerifier(ids[0])
412 c.Assert(err, IsNil)
413
414
415 generateAndAddPrivateKey(c, r, "targets")
416 generateAndAddPrivateKey(c, r, "targets")
417
418
419 root, err = r.root()
420 c.Assert(err, IsNil)
421 c.Assert(root.Roles, HasLen, 2)
422 rs.assertNumUniqueKeys(c, root, "root", 1)
423 rs.assertNumUniqueKeys(c, root, "targets", 2)
424 targetsRole, ok := root.Roles["targets"]
425 if !ok {
426 c.Fatal("missing targets role")
427 }
428 c.Assert(targetsRole.KeyIDs, HasLen, 2)
429 targetKeyIDs := make(map[string]struct{}, 2)
430 db, err = r.topLevelKeysDB()
431 c.Assert(err, IsNil)
432 for _, id := range targetsRole.KeyIDs {
433 targetKeyIDs[id] = struct{}{}
434 _, ok = root.Keys[id]
435 if !ok {
436 c.Fatal("missing key")
437 }
438 verifier, err := db.GetVerifier(id)
439 c.Assert(err, IsNil)
440 c.Assert(verifier.MarshalPublicKey().ContainsID(id), Equals, true)
441 }
442 role := db.GetRole("targets")
443 c.Assert(role.KeyIDs, DeepEquals, targetKeyIDs)
444
445
446 rootKeys, err := r.RootKeys()
447 c.Assert(err, IsNil)
448 c.Assert(rootKeys, HasLen, 1)
449 c.Assert(rootKeys[0].IDs(), DeepEquals, rootKey.MarshalPublicKey().IDs())
450
451
452 localKeys, err := local.GetSigners("targets")
453 c.Assert(err, IsNil)
454 c.Assert(localKeys, HasLen, 2)
455 for _, key := range localKeys {
456 found := false
457 for _, id := range targetsRole.KeyIDs {
458 if key.PublicData().ContainsID(id) {
459 found = true
460 break
461 }
462 }
463 if !found {
464 c.Fatal("missing key")
465 }
466 }
467
468
469 meta, err := local.GetMeta()
470 c.Assert(err, IsNil)
471 rootJSON, ok := meta["root.json"]
472 if !ok {
473 c.Fatal("missing root metadata")
474 }
475 s := &data.Signed{}
476 c.Assert(json.Unmarshal(rootJSON, s), IsNil)
477 stagedRoot := &data.Root{}
478 c.Assert(json.Unmarshal(s.Signed, stagedRoot), IsNil)
479 c.Assert(stagedRoot.Type, Equals, root.Type)
480 c.Assert(stagedRoot.Version, Equals, root.Version)
481 c.Assert(stagedRoot.Expires.UnixNano(), Equals, root.Expires.UnixNano())
482
483
484
485
486 for _, key := range root.Keys {
487 key.IDs()
488 }
489 for _, key := range stagedRoot.Keys {
490 key.IDs()
491 }
492 c.Assert(stagedRoot.Keys, DeepEquals, root.Keys)
493 c.Assert(stagedRoot.Roles, DeepEquals, root.Roles)
494
495
496 generateAndAddPrivateKey(c, r, "snapshot")
497 generateAndAddPrivateKey(c, r, "timestamp")
498 c.Assert(r.AddTargets([]string{}, nil), IsNil)
499 c.Assert(r.Snapshot(), IsNil)
500 c.Assert(r.Timestamp(), IsNil)
501 c.Assert(r.Commit(), IsNil)
502
503
504 oldRoot, err := r.root()
505 c.Assert(err, IsNil)
506 addPrivateKey(c, r, "root", signer)
507 newRoot, err := r.root()
508 c.Assert(err, IsNil)
509 c.Assert(oldRoot, DeepEquals, newRoot)
510 if r.local.FileIsStaged("root.json") {
511 c.Fatal("root should not be marked dirty")
512 }
513 }
514
515 func (rs *RepoSuite) TestRevokeKey(c *C) {
516 local := MemoryStore(make(map[string]json.RawMessage), nil)
517 r, err := NewRepo(local)
518 c.Assert(err, IsNil)
519
520
521 c.Assert(r.RevokeKey("foo", ""), DeepEquals, ErrInvalidRole{"foo", "only revocations for top-level roles supported"})
522
523
524 c.Assert(r.RevokeKey("root", "nonexistent"), DeepEquals, ErrKeyNotFound{"root", "nonexistent"})
525
526
527 genKey(c, r, "root")
528 target1IDs := genKey(c, r, "targets")
529 target2IDs := genKey(c, r, "targets")
530 genKey(c, r, "snapshot")
531 genKey(c, r, "timestamp")
532 root, err := r.root()
533 c.Assert(err, IsNil)
534 c.Assert(root.Roles, NotNil)
535 c.Assert(root.Roles, HasLen, 4)
536 c.Assert(root.Keys, NotNil)
537 rs.assertNumUniqueKeys(c, root, "root", 1)
538 rs.assertNumUniqueKeys(c, root, "targets", 2)
539 rs.assertNumUniqueKeys(c, root, "snapshot", 1)
540 rs.assertNumUniqueKeys(c, root, "timestamp", 1)
541
542
543 targetsRole, ok := root.Roles["targets"]
544 if !ok {
545 c.Fatal("missing targets role")
546 }
547 c.Assert(targetsRole.KeyIDs, HasLen, len(target1IDs)+len(target2IDs))
548 id := targetsRole.KeyIDs[0]
549 c.Assert(r.RevokeKey("targets", id), IsNil)
550
551
552 for _, id := range target1IDs {
553 c.Assert(r.RevokeKey("targets", id), DeepEquals, ErrKeyNotFound{"targets", id})
554 }
555
556
557 root, err = r.root()
558 c.Assert(err, IsNil)
559 c.Assert(root.Roles, NotNil)
560 c.Assert(root.Roles, HasLen, 4)
561 c.Assert(root.Keys, NotNil)
562 rs.assertNumUniqueKeys(c, root, "root", 1)
563 rs.assertNumUniqueKeys(c, root, "targets", 1)
564 rs.assertNumUniqueKeys(c, root, "snapshot", 1)
565 rs.assertNumUniqueKeys(c, root, "timestamp", 1)
566 targetsRole, ok = root.Roles["targets"]
567 if !ok {
568 c.Fatal("missing targets role")
569 }
570 c.Assert(targetsRole.KeyIDs, HasLen, 1)
571 c.Assert(targetsRole.KeyIDs, DeepEquals, target2IDs)
572 }
573
574 func (rs *RepoSuite) TestRevokeKeyInMultipleRoles(c *C) {
575 local := MemoryStore(make(map[string]json.RawMessage), nil)
576 r, err := NewRepo(local)
577 c.Assert(err, IsNil)
578
579
580 rootSigner, err := keys.GenerateEd25519Key()
581 c.Assert(err, IsNil)
582 c.Assert(r.AddVerificationKey("root", rootSigner.PublicData()), IsNil)
583 sharedSigner, err := keys.GenerateEd25519Key()
584 c.Assert(err, IsNil)
585 sharedIDs := sharedSigner.PublicData().IDs()
586 c.Assert(r.AddVerificationKey("root", sharedSigner.PublicData()), IsNil)
587 c.Assert(r.AddVerificationKey("targets", sharedSigner.PublicData()), IsNil)
588 targetIDs := genKey(c, r, "targets")
589 genKey(c, r, "snapshot")
590 genKey(c, r, "timestamp")
591 root, err := r.root()
592 c.Assert(err, IsNil)
593 c.Assert(root.Roles, NotNil)
594 c.Assert(root.Roles, HasLen, 4)
595 c.Assert(root.Keys, NotNil)
596 rs.assertNumUniqueKeys(c, root, "root", 2)
597 rs.assertNumUniqueKeys(c, root, "targets", 2)
598 rs.assertNumUniqueKeys(c, root, "snapshot", 1)
599 rs.assertNumUniqueKeys(c, root, "timestamp", 1)
600
601
602 targetsRole, ok := root.Roles["targets"]
603 if !ok {
604 c.Fatal("missing targets role")
605 }
606 c.Assert(targetsRole.KeyIDs, HasLen, len(targetIDs)+len(sharedIDs))
607 id := targetsRole.KeyIDs[0]
608 c.Assert(r.RevokeKey("targets", id), IsNil)
609
610
611 for _, id := range sharedIDs {
612 c.Assert(r.RevokeKey("targets", id), DeepEquals, ErrKeyNotFound{"targets", id})
613 }
614
615
616 root, err = r.root()
617 c.Assert(err, IsNil)
618 c.Assert(root.Roles, NotNil)
619 c.Assert(root.Roles, HasLen, 4)
620 c.Assert(root.Keys, NotNil)
621
622 c.Assert(UniqueKeys(root)["root"], DeepEquals,
623 []*data.PublicKey{rootSigner.PublicData(), sharedSigner.PublicData()})
624 rs.assertNumUniqueKeys(c, root, "root", 2)
625 rs.assertNumUniqueKeys(c, root, "targets", 1)
626 rs.assertNumUniqueKeys(c, root, "snapshot", 1)
627 rs.assertNumUniqueKeys(c, root, "timestamp", 1)
628 targetsRole, ok = root.Roles["targets"]
629 if !ok {
630 c.Fatal("missing targets role")
631 }
632 c.Assert(targetsRole.KeyIDs, HasLen, 1)
633 c.Assert(targetsRole.KeyIDs, DeepEquals, targetIDs)
634 }
635
636 func (rs *RepoSuite) TestSign(c *C) {
637 meta := map[string]json.RawMessage{"root.json": []byte(`{"signed":{},"signatures":[]}`)}
638 local := MemoryStore(meta, nil)
639 r, err := NewRepo(local)
640 c.Assert(err, IsNil)
641
642 c.Assert(r.Sign("foo.json"), Equals, ErrMissingMetadata{"foo.json"})
643
644
645 c.Assert(r.Sign("root.json"), Equals, ErrNoKeys{"root.json"})
646
647 checkSigIDs := func(keyIDs ...string) {
648 meta, err := local.GetMeta()
649 c.Assert(err, IsNil)
650 rootJSON, ok := meta["root.json"]
651 if !ok {
652 c.Fatal("missing root.json")
653 }
654 s := &data.Signed{}
655 c.Assert(json.Unmarshal(rootJSON, s), IsNil)
656 c.Assert(s.Signatures, HasLen, len(keyIDs))
657
658
659 wantKeyIDs := append([]string{}, keyIDs...)
660 sort.Strings(wantKeyIDs)
661
662 gotKeyIDs := []string{}
663 for _, sig := range s.Signatures {
664 gotKeyIDs = append(gotKeyIDs, sig.KeyID)
665 }
666 sort.Strings(gotKeyIDs)
667
668 c.Assert(wantKeyIDs, DeepEquals, gotKeyIDs)
669 }
670
671
672 signer, err := keys.GenerateEd25519Key()
673 c.Assert(err, IsNil)
674 c.Assert(local.SaveSigner("root", signer), IsNil)
675 c.Assert(r.Sign("root.json"), IsNil)
676 checkSigIDs(signer.PublicData().IDs()...)
677
678
679 c.Assert(r.Sign("root.json"), IsNil)
680 checkSigIDs(signer.PublicData().IDs()...)
681
682
683 newKey, err := keys.GenerateEd25519Key()
684 c.Assert(err, IsNil)
685 c.Assert(local.SaveSigner("root", newKey), IsNil)
686 c.Assert(r.Sign("root.json"), IsNil)
687 checkSigIDs(append(signer.PublicData().IDs(), newKey.PublicData().IDs()...)...)
688
689
690 c.Assert(r.Sign("targets.json"), Equals, ErrMissingMetadata{"targets.json"})
691 }
692
693 func (rs *RepoSuite) TestStatus(c *C) {
694 files := map[string][]byte{"foo.txt": []byte("foo")}
695 local := MemoryStore(make(map[string]json.RawMessage), files)
696 r, err := NewRepo(local)
697 c.Assert(err, IsNil)
698
699 genKey(c, r, "root")
700 genKey(c, r, "targets")
701 genKey(c, r, "snapshot")
702 genKey(c, r, "timestamp")
703
704 c.Assert(r.AddTarget("foo.txt", nil), IsNil)
705 c.Assert(r.SnapshotWithExpires(time.Now().Add(24*time.Hour)), IsNil)
706 c.Assert(r.TimestampWithExpires(time.Now().Add(1*time.Hour)), IsNil)
707 c.Assert(r.Commit(), IsNil)
708
709 expires := time.Now().Add(2 * time.Hour)
710 c.Assert(r.CheckRoleUnexpired("timestamp", expires), ErrorMatches, "role expired on.*")
711 c.Assert(r.CheckRoleUnexpired("snapshot", expires), IsNil)
712 c.Assert(r.CheckRoleUnexpired("targets", expires), IsNil)
713 c.Assert(r.CheckRoleUnexpired("root", expires), IsNil)
714 }
715
716 func (rs *RepoSuite) TestCommit(c *C) {
717 files := map[string][]byte{"foo.txt": []byte("foo"), "bar.txt": []byte("bar")}
718 local := MemoryStore(make(map[string]json.RawMessage), files)
719 r, err := NewRepo(local)
720 c.Assert(err, IsNil)
721
722
723 c.Assert(r.Commit(), DeepEquals, ErrMissingMetadata{"root.json"})
724
725
726 r.Init(false)
727 c.Assert(r.Commit(), DeepEquals, ErrMissingMetadata{"snapshot.json"})
728
729 genKey(c, r, "root")
730
731
732 genKey(c, r, "targets")
733 c.Assert(r.Sign("targets.json"), IsNil)
734 c.Assert(r.Commit(), DeepEquals, ErrMissingMetadata{"snapshot.json"})
735
736
737 genKey(c, r, "snapshot")
738 c.Assert(r.Snapshot(), IsNil)
739 c.Assert(r.Commit(), DeepEquals, ErrMissingMetadata{"timestamp.json"})
740
741
742 c.Assert(r.Timestamp(), IsNil)
743 c.Assert(r.Commit(), DeepEquals, ErrInsufficientSignatures{"timestamp.json", verify.ErrNoSignatures})
744
745
746 genKey(c, r, "timestamp")
747 c.Assert(r.Snapshot(), IsNil)
748 c.Assert(r.Timestamp(), IsNil)
749 c.Assert(r.Commit(), IsNil)
750
751
752 genKey(c, r, "targets")
753 c.Assert(r.Sign("targets.json"), IsNil)
754 c.Assert(r.Commit(), DeepEquals, errors.New("tuf: invalid targets.json in snapshot.json: wrong length, expected 338 got 552"))
755
756
757 c.Assert(r.Snapshot(), IsNil)
758 c.Assert(r.AddTarget("bar.txt", nil), IsNil)
759 c.Assert(r.Commit(), DeepEquals, errors.New("tuf: invalid targets.json in snapshot.json: wrong length, expected 552 got 725"))
760
761
762 c.Assert(r.Snapshot(), IsNil)
763 err = r.Commit()
764 c.Assert(err, NotNil)
765 c.Assert(err.Error()[0:44], Equals, "tuf: invalid snapshot.json in timestamp.json")
766
767
768 root, err := r.root()
769 c.Assert(err, IsNil)
770 role, ok := root.Roles["timestamp"]
771 if !ok {
772 c.Fatal("missing timestamp role")
773 }
774 c.Assert(role.KeyIDs, HasLen, 1)
775 c.Assert(role.Threshold, Equals, 1)
776 c.Assert(r.RevokeKey("timestamp", role.KeyIDs[0]), IsNil)
777 c.Assert(r.Snapshot(), IsNil)
778 c.Assert(r.Timestamp(), IsNil)
779 c.Assert(r.Commit(), DeepEquals, ErrNotEnoughKeys{"timestamp", 0, 1})
780 }
781
782 func (rs *RepoSuite) TestCommitVersions(c *C) {
783 files := map[string][]byte{"foo.txt": []byte("foo")}
784 local := MemoryStore(make(map[string]json.RawMessage), files)
785 r, err := NewRepo(local)
786 c.Assert(err, IsNil)
787
788 genKey(c, r, "root")
789 genKey(c, r, "targets")
790 genKey(c, r, "snapshot")
791 genKey(c, r, "timestamp")
792
793 c.Assert(r.AddTarget("foo.txt", nil), IsNil)
794 c.Assert(r.Snapshot(), IsNil)
795 c.Assert(r.Timestamp(), IsNil)
796 c.Assert(r.Commit(), IsNil)
797
798
799 rootVersion, err := r.RootVersion()
800 c.Assert(err, IsNil)
801 c.Assert(rootVersion, Equals, int64(1))
802
803 targetsVersion, err := r.TargetsVersion()
804 c.Assert(err, IsNil)
805 c.Assert(targetsVersion, Equals, int64(1))
806
807 snapshotVersion, err := r.SnapshotVersion()
808 c.Assert(err, IsNil)
809 c.Assert(snapshotVersion, Equals, int64(1))
810
811 timestampVersion, err := r.SnapshotVersion()
812 c.Assert(err, IsNil)
813 c.Assert(timestampVersion, Equals, int64(1))
814
815
816 c.Assert(r.Snapshot(), IsNil)
817 c.Assert(r.Timestamp(), IsNil)
818 c.Assert(r.Commit(), IsNil)
819
820 rootVersion, err = r.RootVersion()
821 c.Assert(err, IsNil)
822 c.Assert(rootVersion, Equals, int64(1))
823
824 targetsVersion, err = r.TargetsVersion()
825 c.Assert(err, IsNil)
826 c.Assert(targetsVersion, Equals, int64(1))
827
828 snapshotVersion, err = r.SnapshotVersion()
829 c.Assert(err, IsNil)
830 c.Assert(snapshotVersion, Equals, int64(2))
831
832 timestampVersion, err = r.SnapshotVersion()
833 c.Assert(err, IsNil)
834 c.Assert(timestampVersion, Equals, int64(2))
835
836
837 genKey(c, r, "targets")
838 genKey(c, r, "snapshot")
839 genKey(c, r, "timestamp")
840 c.Assert(r.Snapshot(), IsNil)
841 c.Assert(r.Timestamp(), IsNil)
842 c.Assert(r.Commit(), IsNil)
843
844 rootVersion, err = r.RootVersion()
845 c.Assert(err, IsNil)
846 c.Assert(rootVersion, Equals, int64(2))
847
848 targetsVersion, err = r.TargetsVersion()
849 c.Assert(err, IsNil)
850 c.Assert(targetsVersion, Equals, int64(1))
851
852 snapshotVersion, err = r.SnapshotVersion()
853 c.Assert(err, IsNil)
854 c.Assert(snapshotVersion, Equals, int64(3))
855
856 timestampVersion, err = r.TimestampVersion()
857 c.Assert(err, IsNil)
858 c.Assert(timestampVersion, Equals, int64(3))
859 }
860
861 type tmpDir struct {
862 path string
863 c *C
864 }
865
866 func newTmpDir(c *C) *tmpDir {
867 return &tmpDir{path: c.MkDir(), c: c}
868 }
869
870 func (t *tmpDir) assertExists(path string) {
871 if _, err := os.Stat(filepath.Join(t.path, path)); os.IsNotExist(err) {
872 t.c.Fatalf("expected path to exist but it doesn't: %s", path)
873 }
874 }
875
876 func (t *tmpDir) assertNotExist(path string) {
877 if _, err := os.Stat(filepath.Join(t.path, path)); !os.IsNotExist(err) {
878 t.c.Fatalf("expected path to not exist but it does: %s", path)
879 }
880 }
881
882 func (t *tmpDir) assertHashedFilesExist(path string, hashes data.Hashes) {
883 t.c.Assert(len(hashes) > 0, Equals, true)
884 for _, path := range util.HashedPaths(path, hashes) {
885 t.assertExists(path)
886 }
887 }
888
889 func (t *tmpDir) assertHashedFilesNotExist(path string, hashes data.Hashes) {
890 for _, path := range util.HashedPaths(path, hashes) {
891 t.assertNotExist(path)
892 }
893 }
894
895 func (t *tmpDir) assertVersionedFileExist(path string, version int64) {
896 t.assertExists(util.VersionedPath(path, version))
897 }
898
899 func (t *tmpDir) assertVersionedFileNotExist(path string, version int64) {
900 t.assertNotExist(util.VersionedPath(path, version))
901 }
902
903 func (t *tmpDir) assertEmpty(dir string) {
904 path := filepath.Join(t.path, dir)
905 f, err := os.Stat(path)
906 if os.IsNotExist(err) {
907 t.c.Fatalf("expected dir to exist but it doesn't: %s", dir)
908 }
909 t.c.Assert(err, IsNil)
910 t.c.Assert(f.IsDir(), Equals, true)
911
912 entries, err := os.ReadDir(path)
913 t.c.Assert(err, IsNil)
914
915 for _, e := range entries {
916 t.assertEmpty(filepath.Join(dir, e.Name()))
917 }
918 }
919
920 func (t *tmpDir) assertFileContent(path, content string) {
921 actual := t.readFile(path)
922 t.c.Assert(string(actual), Equals, content)
923 }
924
925 func (t *tmpDir) stagedTargetPath(path string) string {
926 return filepath.Join(t.path, "staged", "targets", path)
927 }
928
929 func (t *tmpDir) writeStagedTarget(path, data string) {
930 path = t.stagedTargetPath(path)
931 t.c.Assert(os.MkdirAll(filepath.Dir(path), 0755), IsNil)
932 t.c.Assert(os.WriteFile(path, []byte(data), 0644), IsNil)
933 }
934
935 func (t *tmpDir) readFile(path string) []byte {
936 t.assertExists(path)
937 data, err := os.ReadFile(filepath.Join(t.path, path))
938 t.c.Assert(err, IsNil)
939 return data
940 }
941
942 func (rs *RepoSuite) TestCommitFileSystem(c *C) {
943 tmp := newTmpDir(c)
944 local := FileSystemStore(tmp.path, nil)
945 r, err := NewRepo(local)
946 c.Assert(err, IsNil)
947
948
949 c.Assert(r.Init(false), IsNil)
950
951
952 c.Assert(r.Clean(), Equals, ErrNewRepository)
953
954
955 genKey(c, r, "root")
956 genKey(c, r, "targets")
957 genKey(c, r, "snapshot")
958 genKey(c, r, "timestamp")
959 tmp.assertExists("staged/root.json")
960 tmp.assertEmpty("repository")
961 tmp.assertEmpty("staged/targets")
962
963
964 c.Assert(r.Clean(), Equals, ErrNewRepository)
965
966
967 c.Assert(r.AddTarget("foo.txt", nil), Equals, ErrFileNotFound{tmp.stagedTargetPath("foo.txt")})
968 tmp.assertEmpty("repository")
969
970
971 tmp.writeStagedTarget("foo.txt", "foo")
972 c.Assert(r.AddTarget("foo.txt", nil), IsNil)
973 tmp.assertExists("staged/targets.json")
974 tmp.assertEmpty("repository")
975 t, err := r.topLevelTargets()
976 c.Assert(err, IsNil)
977 c.Assert(t.Targets, HasLen, 1)
978 if _, ok := t.Targets["foo.txt"]; !ok {
979 c.Fatal("missing target file: foo.txt")
980 }
981
982
983 c.Assert(r.Snapshot(), IsNil)
984 tmp.assertExists("staged/snapshot.json")
985 tmp.assertEmpty("repository")
986
987
988 c.Assert(r.Timestamp(), IsNil)
989 tmp.assertExists("staged/timestamp.json")
990 tmp.assertEmpty("repository")
991
992
993 c.Assert(r.Commit(), IsNil)
994 tmp.assertExists("repository/root.json")
995 tmp.assertExists("repository/targets.json")
996 tmp.assertExists("repository/snapshot.json")
997 tmp.assertExists("repository/timestamp.json")
998 tmp.assertFileContent("repository/targets/foo.txt", "foo")
999 tmp.assertEmpty("staged/targets")
1000 tmp.assertEmpty("staged")
1001
1002
1003 tmp.writeStagedTarget("path/to/bar.txt", "bar")
1004 c.Assert(r.AddTarget("path/to/bar.txt", nil), IsNil)
1005 tmp.assertExists("staged/targets.json")
1006 c.Assert(r.Snapshot(), IsNil)
1007 c.Assert(r.Timestamp(), IsNil)
1008 c.Assert(r.Commit(), IsNil)
1009 tmp.assertFileContent("repository/targets/foo.txt", "foo")
1010 tmp.assertFileContent("repository/targets/path/to/bar.txt", "bar")
1011 tmp.assertEmpty("staged/targets")
1012 tmp.assertEmpty("staged")
1013
1014
1015 c.Assert(r.RemoveTarget("foo.txt"), IsNil)
1016 tmp.assertExists("staged/targets.json")
1017 c.Assert(r.Snapshot(), IsNil)
1018 c.Assert(r.Timestamp(), IsNil)
1019 c.Assert(r.Commit(), IsNil)
1020 tmp.assertNotExist("repository/targets/foo.txt")
1021 tmp.assertFileContent("repository/targets/path/to/bar.txt", "bar")
1022 tmp.assertEmpty("staged/targets")
1023 tmp.assertEmpty("staged")
1024 }
1025
1026 func (rs *RepoSuite) TestCommitFileSystemWithNewRepositories(c *C) {
1027 tmp := newTmpDir(c)
1028
1029 newRepo := func() *Repo {
1030 local := FileSystemStore(tmp.path, nil)
1031 r, err := NewRepo(local)
1032 c.Assert(err, IsNil)
1033 return r
1034 }
1035
1036 genKey(c, newRepo(), "root")
1037 genKey(c, newRepo(), "targets")
1038 genKey(c, newRepo(), "snapshot")
1039 genKey(c, newRepo(), "timestamp")
1040
1041 tmp.writeStagedTarget("foo.txt", "foo")
1042 c.Assert(newRepo().AddTarget("foo.txt", nil), IsNil)
1043 c.Assert(newRepo().Snapshot(), IsNil)
1044 c.Assert(newRepo().Timestamp(), IsNil)
1045 c.Assert(newRepo().Commit(), IsNil)
1046 }
1047
1048 func (rs *RepoSuite) TestConsistentSnapshot(c *C) {
1049 tmp := newTmpDir(c)
1050 local := FileSystemStore(tmp.path, nil)
1051 r, err := NewRepo(local, "sha512", "sha256")
1052 c.Assert(err, IsNil)
1053
1054 genKey(c, r, "root")
1055 genKey(c, r, "targets")
1056 genKey(c, r, "snapshot")
1057 genKey(c, r, "timestamp")
1058 tmp.writeStagedTarget("foo.txt", "foo")
1059 c.Assert(r.AddTarget("foo.txt", nil), IsNil)
1060 tmp.writeStagedTarget("dir/bar.txt", "bar")
1061 c.Assert(r.AddTarget("dir/bar.txt", nil), IsNil)
1062 c.Assert(r.Snapshot(), IsNil)
1063 c.Assert(r.Timestamp(), IsNil)
1064 c.Assert(r.Commit(), IsNil)
1065
1066 versions, err := r.fileVersions()
1067 c.Assert(err, IsNil)
1068 c.Assert(versions["root.json"], Equals, int64(1))
1069 c.Assert(versions["targets.json"], Equals, int64(1))
1070 c.Assert(versions["snapshot.json"], Equals, int64(1))
1071
1072 hashes, err := r.fileHashes()
1073 c.Assert(err, IsNil)
1074
1075
1076 for _, meta := range []string{"root.json", "targets.json", "snapshot.json"} {
1077 repoPath := path.Join("repository", meta)
1078 if meta != "root.json" {
1079 c.Assert(len(hashes[meta]) > 0, Equals, true)
1080 }
1081 tmp.assertHashedFilesNotExist(repoPath, hashes[meta])
1082 tmp.assertVersionedFileExist(repoPath, versions[meta])
1083 tmp.assertExists(repoPath)
1084 }
1085
1086
1087 for _, target := range []string{"targets/foo.txt", "targets/dir/bar.txt"} {
1088 repoPath := path.Join("repository", target)
1089 tmp.assertHashedFilesExist(repoPath, hashes[target])
1090 tmp.assertNotExist(repoPath)
1091 }
1092
1093
1094 c.Assert(hashes["repository/timestamp.json"], IsNil)
1095 tmp.assertVersionedFileNotExist("repository/timestamp.json", versions["repository/timestamp.json"])
1096 tmp.assertExists("repository/timestamp.json")
1097
1098
1099 c.Assert(r.RemoveTarget("foo.txt"), IsNil)
1100 c.Assert(r.Snapshot(), IsNil)
1101 c.Assert(r.Timestamp(), IsNil)
1102 c.Assert(r.Commit(), IsNil)
1103
1104 versions, err = r.fileVersions()
1105 c.Assert(err, IsNil)
1106 c.Assert(versions["root.json"], Equals, int64(1))
1107 c.Assert(versions["targets.json"], Equals, int64(2))
1108 c.Assert(versions["snapshot.json"], Equals, int64(2))
1109
1110
1111 fooHashes := hashes["targets/foo.txt"]
1112 hashes, err = r.fileHashes()
1113 c.Assert(err, IsNil)
1114
1115
1116 for _, meta := range []string{"root.json", "targets.json", "snapshot.json"} {
1117 repoPath := path.Join("repository", meta)
1118 if meta != "root.json" {
1119 c.Assert(len(hashes[meta]) > 0, Equals, true)
1120 }
1121 tmp.assertHashedFilesNotExist(repoPath, hashes[meta])
1122 tmp.assertVersionedFileExist(repoPath, versions[meta])
1123 tmp.assertExists(repoPath)
1124 }
1125
1126 tmp.assertHashedFilesNotExist("repository/targets/foo.txt", fooHashes)
1127 tmp.assertNotExist("repository/targets/foo.txt")
1128
1129
1130 newRepo, err := NewRepo(local, "sha512", "sha256")
1131 c.Assert(err, IsNil)
1132 t, err := newRepo.topLevelTargets()
1133 c.Assert(err, IsNil)
1134 c.Assert(t.Targets, HasLen, 1)
1135 if _, ok := t.Targets["dir/bar.txt"]; !ok {
1136 c.Fatal("missing targets file: dir/bar.txt")
1137 }
1138 }
1139
1140 func (rs *RepoSuite) TestExpiresAndVersion(c *C) {
1141 files := map[string][]byte{"foo.txt": []byte("foo")}
1142 local := MemoryStore(make(map[string]json.RawMessage), files)
1143 r, err := NewRepo(local)
1144 c.Assert(err, IsNil)
1145
1146 past := time.Now().Add(-1 * time.Second)
1147 _, genKeyErr := r.GenKeyWithExpires("root", past)
1148 for _, err := range []error{
1149 genKeyErr,
1150 r.AddTargetWithExpires("foo.txt", nil, past),
1151 r.RemoveTargetWithExpires("foo.txt", past),
1152 r.SnapshotWithExpires(past),
1153 r.TimestampWithExpires(past),
1154 } {
1155 c.Assert(err, Equals, ErrInvalidExpires{past})
1156 }
1157
1158 genKey(c, r, "root")
1159 genKey(c, r, "targets")
1160 genKey(c, r, "snapshot")
1161 genKey(c, r, "timestamp")
1162
1163 c.Assert(r.AddTargets([]string{}, nil), IsNil)
1164 c.Assert(r.Snapshot(), IsNil)
1165 c.Assert(r.Timestamp(), IsNil)
1166 c.Assert(r.Commit(), IsNil)
1167
1168 root, err := r.root()
1169 c.Assert(err, IsNil)
1170 c.Assert(root.Version, Equals, int64(1))
1171
1172 expires := time.Now().Add(24 * time.Hour)
1173 _, err = r.GenKeyWithExpires("root", expires)
1174 c.Assert(err, IsNil)
1175 c.Assert(r.Snapshot(), IsNil)
1176 c.Assert(r.Timestamp(), IsNil)
1177 c.Assert(r.Commit(), IsNil)
1178 root, err = r.root()
1179 c.Assert(err, IsNil)
1180 c.Assert(root.Expires.Unix(), DeepEquals, expires.Round(time.Second).Unix())
1181 c.Assert(root.Version, Equals, int64(2))
1182
1183 expires = time.Now().Add(12 * time.Hour)
1184 role, ok := root.Roles["root"]
1185 if !ok {
1186 c.Fatal("missing root role")
1187 }
1188 c.Assert(role.KeyIDs, HasLen, 2)
1189 c.Assert(r.RevokeKeyWithExpires("root", role.KeyIDs[0], expires), IsNil)
1190 c.Assert(r.Snapshot(), IsNil)
1191 c.Assert(r.Timestamp(), IsNil)
1192 c.Assert(r.Commit(), IsNil)
1193 root, err = r.root()
1194 c.Assert(err, IsNil)
1195 c.Assert(root.Expires.Unix(), DeepEquals, expires.Round(time.Second).Unix())
1196 c.Assert(root.Version, Equals, int64(3))
1197
1198 expires = time.Now().Add(6 * time.Hour)
1199 c.Assert(r.AddTargetWithExpires("foo.txt", nil, expires), IsNil)
1200 c.Assert(r.Snapshot(), IsNil)
1201 c.Assert(r.Timestamp(), IsNil)
1202 c.Assert(r.Commit(), IsNil)
1203 targets, err := r.topLevelTargets()
1204 c.Assert(err, IsNil)
1205 c.Assert(targets.Expires.Unix(), Equals, expires.Round(time.Second).Unix())
1206 c.Assert(targets.Version, Equals, int64(2))
1207
1208 expires = time.Now().Add(2 * time.Hour)
1209 c.Assert(r.RemoveTargetWithExpires("foo.txt", expires), IsNil)
1210 c.Assert(r.Snapshot(), IsNil)
1211 c.Assert(r.Timestamp(), IsNil)
1212 c.Assert(r.Commit(), IsNil)
1213 targets, err = r.topLevelTargets()
1214 c.Assert(err, IsNil)
1215 c.Assert(targets.Expires.Unix(), Equals, expires.Round(time.Second).Unix())
1216 c.Assert(targets.Version, Equals, int64(3))
1217
1218 expires = time.Now().Add(time.Hour)
1219 c.Assert(r.SnapshotWithExpires(expires), IsNil)
1220 c.Assert(r.Timestamp(), IsNil)
1221 c.Assert(r.Commit(), IsNil)
1222 snapshot, err := r.snapshot()
1223 c.Assert(err, IsNil)
1224 c.Assert(snapshot.Expires.Unix(), Equals, expires.Round(time.Second).Unix())
1225 c.Assert(snapshot.Version, Equals, int64(6))
1226
1227 _, snapshotHasRoot := snapshot.Meta["root.json"]
1228 c.Assert(snapshotHasRoot, Equals, false)
1229 c.Assert(snapshot.Meta["targets.json"].Version, Equals, targets.Version)
1230
1231 c.Assert(r.Snapshot(), IsNil)
1232 c.Assert(r.Timestamp(), IsNil)
1233 c.Assert(r.Commit(), IsNil)
1234 snapshot, err = r.snapshot()
1235 c.Assert(err, IsNil)
1236 c.Assert(snapshot.Version, Equals, int64(7))
1237
1238 expires = time.Now().Add(10 * time.Minute)
1239 c.Assert(r.TimestampWithExpires(expires), IsNil)
1240 c.Assert(r.Commit(), IsNil)
1241 timestamp, err := r.timestamp()
1242 c.Assert(err, IsNil)
1243 c.Assert(timestamp.Expires.Unix(), Equals, expires.Round(time.Second).Unix())
1244 c.Assert(timestamp.Version, Equals, int64(8))
1245
1246 c.Assert(r.Timestamp(), IsNil)
1247 c.Assert(r.Commit(), IsNil)
1248 timestamp, err = r.timestamp()
1249 c.Assert(err, IsNil)
1250 c.Assert(timestamp.Version, Equals, int64(9))
1251 c.Assert(timestamp.Meta["snapshot.json"].Version, Equals, snapshot.Version)
1252 }
1253
1254 func (rs *RepoSuite) TestHashAlgorithm(c *C) {
1255 files := map[string][]byte{"foo.txt": []byte("foo")}
1256 local := MemoryStore(make(map[string]json.RawMessage), files)
1257 type hashTest struct {
1258 args []string
1259 expected []string
1260 }
1261 for _, test := range []hashTest{
1262 {args: []string{}, expected: []string{"sha512"}},
1263 {args: []string{"sha256"}},
1264 {args: []string{"sha512", "sha256"}},
1265 } {
1266
1267 r, err := NewRepo(local, test.args...)
1268 c.Assert(err, IsNil)
1269 genKey(c, r, "root")
1270 genKey(c, r, "targets")
1271 genKey(c, r, "snapshot")
1272 c.Assert(r.AddTarget("foo.txt", nil), IsNil)
1273 c.Assert(r.Snapshot(), IsNil)
1274 c.Assert(r.Timestamp(), IsNil)
1275
1276
1277 if test.expected == nil {
1278 test.expected = test.args
1279 }
1280 targets, err := r.topLevelTargets()
1281 c.Assert(err, IsNil)
1282 snapshot, err := r.snapshot()
1283 c.Assert(err, IsNil)
1284 timestamp, err := r.timestamp()
1285 c.Assert(err, IsNil)
1286 for name, file := range map[string]data.FileMeta{
1287 "foo.txt": targets.Targets["foo.txt"].FileMeta,
1288 "targets.json": {Length: snapshot.Meta["targets.json"].Length, Hashes: snapshot.Meta["targets.json"].Hashes},
1289 "snapshot.json": {Length: timestamp.Meta["snapshot.json"].Length, Hashes: timestamp.Meta["snapshot.json"].Hashes},
1290 } {
1291 for _, hashAlgorithm := range test.expected {
1292 if _, ok := file.Hashes[hashAlgorithm]; !ok {
1293 c.Fatalf("expected %s hash to contain hash func %s, got %s", name, hashAlgorithm, file.Hashes.HashAlgorithms())
1294 }
1295 }
1296 }
1297 }
1298 }
1299
1300 func (rs *RepoSuite) TestKeyPersistence(c *C) {
1301 tmp := newTmpDir(c)
1302 oldPassphrase := []byte("old_s3cr3t")
1303 newPassphrase := []byte("new_s3cr3t")
1304
1305 returnNewPassphrase := false
1306
1307 testPassphraseFunc := func(a string, b, change bool) ([]byte, error) {
1308 if change || returnNewPassphrase {
1309 return newPassphrase, nil
1310 }
1311 return oldPassphrase, nil
1312 }
1313 store := FileSystemStore(tmp.path, testPassphraseFunc)
1314
1315 assertKeys := func(role string, enc bool, expected []*data.PrivateKey) {
1316 keysJSON := tmp.readFile("keys/" + role + ".json")
1317 pk := &persistedKeys{}
1318 c.Assert(json.Unmarshal(keysJSON, pk), IsNil)
1319
1320
1321 var actual []*data.PrivateKey
1322 pass := oldPassphrase
1323 if enc {
1324 c.Assert(pk.Encrypted, Equals, true)
1325 if returnNewPassphrase {
1326 pass = newPassphrase
1327 }
1328 decrypted, err := encrypted.Decrypt(pk.Data, pass)
1329 c.Assert(err, IsNil)
1330 c.Assert(json.Unmarshal(decrypted, &actual), IsNil)
1331 } else {
1332 c.Assert(pk.Encrypted, Equals, false)
1333 c.Assert(json.Unmarshal(pk.Data, &actual), IsNil)
1334 }
1335
1336
1337 c.Assert(actual, HasLen, len(expected))
1338 for _, gotKey := range actual {
1339 expectedNumMatches := 0
1340 for _, x := range actual {
1341 if reflect.DeepEqual(gotKey, x) {
1342 expectedNumMatches++
1343 }
1344 }
1345
1346 numMatches := 0
1347 for _, wantKey := range expected {
1348 wantCanon, err := cjson.EncodeCanonical(wantKey)
1349 c.Assert(err, IsNil)
1350
1351 gotCanon, err := cjson.EncodeCanonical(gotKey)
1352 c.Assert(err, IsNil)
1353
1354 if string(wantCanon) == string(gotCanon) {
1355 numMatches++
1356 }
1357 }
1358
1359 c.Assert(numMatches, Equals, expectedNumMatches, Commentf("actual: %+v, expected: %+v", actual, expected))
1360 }
1361
1362
1363 signers, err := store.GetSigners(role)
1364 c.Assert(err, IsNil)
1365
1366
1367 c.Assert(signers, HasLen, len(expected))
1368 for _, s := range signers {
1369 expectedNumMatches := 0
1370 for _, x := range signers {
1371 if reflect.DeepEqual(s, x) {
1372 expectedNumMatches++
1373 }
1374 }
1375
1376 numMatches := 0
1377 for _, e := range expected {
1378 v, err := keys.GetSigner(e)
1379 c.Assert(err, IsNil)
1380
1381 if reflect.DeepEqual(s.PublicData().IDs(), v.PublicData().IDs()) {
1382 numMatches++
1383 }
1384 }
1385
1386 c.Assert(numMatches, Equals, expectedNumMatches, Commentf("signers: %+v, expected: %+v", signers, expected))
1387 }
1388 }
1389
1390
1391 signer, err := keys.GenerateEd25519Key()
1392 c.Assert(err, IsNil)
1393 privateKey, err := signer.MarshalPrivateKey()
1394 c.Assert(err, IsNil)
1395 c.Assert(store.SaveSigner("root", signer), IsNil)
1396 assertKeys("root", true, []*data.PrivateKey{privateKey})
1397
1398
1399 newKey, err := keys.GenerateEd25519Key()
1400 c.Assert(err, IsNil)
1401 newPrivateKey, err := newKey.MarshalPrivateKey()
1402 c.Assert(err, IsNil)
1403 c.Assert(store.SaveSigner("root", newKey), IsNil)
1404 assertKeys("root", true, []*data.PrivateKey{privateKey, newPrivateKey})
1405
1406
1407 insecureStore := FileSystemStore(tmp.path, nil)
1408 signer, err = keys.GenerateEd25519Key()
1409 c.Assert(err, IsNil)
1410 c.Assert(insecureStore.SaveSigner("root", signer), Equals, ErrPassphraseRequired{"root"})
1411
1412
1413 signer, err = keys.GenerateEd25519Key()
1414 c.Assert(err, IsNil)
1415 privateKey, err = signer.MarshalPrivateKey()
1416 c.Assert(err, IsNil)
1417 c.Assert(insecureStore.SaveSigner("targets", signer), IsNil)
1418 assertKeys("targets", false, []*data.PrivateKey{privateKey})
1419
1420 c.Assert(insecureStore.SaveSigner("foo", signer), IsNil)
1421 assertKeys("foo", false, []*data.PrivateKey{privateKey})
1422
1423
1424
1425 tmp = newTmpDir(c)
1426 var logBytes bytes.Buffer
1427 storeOpts := StoreOpts{
1428 Logger: log.New(&logBytes, "", 0),
1429 PassFunc: testPassphraseFunc,
1430 }
1431 store = FileSystemStoreWithOpts(tmp.path, storeOpts)
1432
1433
1434 r, err := NewRepo(store)
1435 c.Assert(err, IsNil)
1436
1437 c.Assert(r.ChangePassphrase("targets"), NotNil)
1438 c.Assert(r.ChangePassphrase("foo"), NotNil)
1439
1440
1441 c.Assert(store.(PassphraseChanger).ChangePassphrase("root"), NotNil)
1442 c.Assert(strings.Contains(logBytes.String(), "Missing keys file"), Equals, true)
1443
1444
1445 signer, err = keys.GenerateEd25519Key()
1446 c.Assert(err, IsNil)
1447 privateKey, err = signer.MarshalPrivateKey()
1448 c.Assert(err, IsNil)
1449 c.Assert(store.SaveSigner("root", signer), IsNil)
1450
1451
1452 assertKeys("root", true, []*data.PrivateKey{privateKey})
1453
1454
1455 c.Assert(store.(PassphraseChanger).ChangePassphrase("root"), IsNil)
1456
1457
1458 newKey, err = keys.GenerateEd25519Key()
1459 c.Assert(err, IsNil)
1460 _, err = newKey.MarshalPrivateKey()
1461 c.Assert(err, IsNil)
1462 c.Assert(store.SaveSigner("root", newKey), NotNil)
1463
1464
1465 returnNewPassphrase = true
1466 newKey, err = keys.GenerateEd25519Key()
1467 c.Assert(err, IsNil)
1468 newPrivateKey, err = newKey.MarshalPrivateKey()
1469 c.Assert(err, IsNil)
1470 c.Assert(store.SaveSigner("root", newKey), IsNil)
1471
1472
1473 assertKeys("root", true, []*data.PrivateKey{privateKey, newPrivateKey})
1474 }
1475
1476 func (rs *RepoSuite) TestManageMultipleTargets(c *C) {
1477 tmp := newTmpDir(c)
1478 local := FileSystemStore(tmp.path, nil)
1479 r, err := NewRepo(local)
1480 c.Assert(err, IsNil)
1481
1482 c.Assert(r.Init(false), IsNil)
1483 genKey(c, r, "root")
1484 genKey(c, r, "targets")
1485 genKey(c, r, "snapshot")
1486 genKey(c, r, "timestamp")
1487
1488 assertRepoTargets := func(paths ...string) {
1489 t, err := r.topLevelTargets()
1490 c.Assert(err, IsNil)
1491 for _, path := range paths {
1492 if _, ok := t.Targets[path]; !ok {
1493 c.Fatalf("missing target file: %s", path)
1494 }
1495 }
1496 }
1497
1498
1499 tmp.writeStagedTarget("foo.txt", "foo")
1500 tmp.writeStagedTarget("bar.txt", "bar")
1501 c.Assert(r.AddTargets([]string{"foo.txt", "bar.txt"}, nil), IsNil)
1502 c.Assert(r.Snapshot(), IsNil)
1503 c.Assert(r.Timestamp(), IsNil)
1504 c.Assert(r.Commit(), IsNil)
1505 assertRepoTargets("foo.txt", "bar.txt")
1506 tmp.assertExists("repository/targets/foo.txt")
1507 tmp.assertExists("repository/targets/bar.txt")
1508
1509
1510 count := 10
1511 files := make([]string, count)
1512 for i := 0; i < count; i++ {
1513 files[i] = fmt.Sprintf("file%d.txt", i)
1514 tmp.writeStagedTarget(files[i], "data")
1515 }
1516 c.Assert(r.AddTargets(nil, nil), IsNil)
1517 c.Assert(r.Snapshot(), IsNil)
1518 c.Assert(r.Timestamp(), IsNil)
1519 c.Assert(r.Commit(), IsNil)
1520 tmp.assertExists("repository/targets/foo.txt")
1521 tmp.assertExists("repository/targets/bar.txt")
1522 assertRepoTargets(files...)
1523 for _, file := range files {
1524 tmp.assertExists("repository/targets/" + file)
1525 }
1526 tmp.assertEmpty("staged/targets")
1527 tmp.assertEmpty("staged")
1528
1529
1530 c.Assert(r.RemoveTargets(nil), IsNil)
1531 c.Assert(r.Snapshot(), IsNil)
1532 c.Assert(r.Timestamp(), IsNil)
1533 c.Assert(r.Commit(), IsNil)
1534 tmp.assertNotExist("repository/targets")
1535 t, err := r.topLevelTargets()
1536 c.Assert(err, IsNil)
1537 c.Assert(t.Targets, HasLen, 0)
1538 }
1539
1540 func (rs *RepoSuite) TestCustomTargetMetadata(c *C) {
1541 files := map[string][]byte{
1542 "foo.txt": []byte("foo"),
1543 "bar.txt": []byte("bar"),
1544 "baz.txt": []byte("baz"),
1545 }
1546 local := MemoryStore(make(map[string]json.RawMessage), files)
1547 r, err := NewRepo(local)
1548 c.Assert(err, IsNil)
1549
1550 generateAndAddPrivateKey(c, r, "targets")
1551
1552 custom := json.RawMessage(`{"foo":"bar"}`)
1553 assertCustomMeta := func(file string, custom *json.RawMessage) {
1554 t, err := r.topLevelTargets()
1555 c.Assert(err, IsNil)
1556 target, ok := t.Targets[file]
1557 if !ok {
1558 c.Fatalf("missing target file: %s", file)
1559 }
1560 c.Assert(target.Custom, DeepEquals, custom)
1561 }
1562
1563
1564 c.Assert(r.AddTarget("foo.txt", custom), IsNil)
1565 assertCustomMeta("foo.txt", &custom)
1566
1567
1568 c.Assert(r.AddTarget("bar.txt", nil), IsNil)
1569 assertCustomMeta("bar.txt", nil)
1570 assertCustomMeta("foo.txt", &custom)
1571
1572
1573 c.Assert(r.AddTargets(nil, nil), IsNil)
1574 assertCustomMeta("baz.txt", nil)
1575 assertCustomMeta("bar.txt", nil)
1576 assertCustomMeta("foo.txt", &custom)
1577 }
1578
1579 func (rs *RepoSuite) TestUnknownKeyIDs(c *C) {
1580
1581 local := MemoryStore(make(map[string]json.RawMessage), nil)
1582 r, err := NewRepo(local)
1583 c.Assert(err, IsNil)
1584
1585 genKey(c, r, "root")
1586 genKey(c, r, "targets")
1587 genKey(c, r, "snapshot")
1588 genKey(c, r, "timestamp")
1589
1590
1591 signer, err := keys.GenerateEd25519Key()
1592 c.Assert(err, IsNil)
1593
1594 root, err := r.root()
1595 c.Assert(err, IsNil)
1596 c.Assert(root.Version, Equals, int64(1))
1597
1598 root.Keys["unknown-key-id"] = signer.PublicData()
1599 r.setMeta("root.json", root)
1600
1601
1602 c.Assert(r.AddTargets([]string{}, nil), IsNil)
1603 c.Assert(r.Snapshot(), IsNil)
1604 c.Assert(r.Timestamp(), IsNil)
1605 c.Assert(r.Commit(), IsNil)
1606
1607
1608
1609 meta, err := local.GetMeta()
1610 c.Assert(err, IsNil)
1611
1612 rootJSON, ok := meta["root.json"]
1613 c.Assert(ok, Equals, true)
1614
1615 var signedRoot struct {
1616 Signed data.Root `json:"signed"`
1617 Signatures []data.Signature `json:"signatures"`
1618 }
1619 c.Assert(json.Unmarshal(rootJSON, &signedRoot), IsNil)
1620 c.Assert(signedRoot.Signed.Version, Equals, int64(1))
1621
1622 unknownKey, ok := signedRoot.Signed.Keys["unknown-key-id"]
1623 c.Assert(ok, Equals, true)
1624 c.Assert(unknownKey, DeepEquals, signer.PublicData())
1625
1626
1627 root, err = r.root()
1628 c.Assert(root, NotNil)
1629 c.Assert(err, IsNil)
1630
1631 genKey(c, r, "timestamp")
1632 c.Assert(r.Snapshot(), IsNil)
1633 c.Assert(r.Timestamp(), IsNil)
1634 c.Assert(r.Commit(), IsNil)
1635
1636 meta, err = local.GetMeta()
1637 c.Assert(err, IsNil)
1638
1639 rootJSON, ok = meta["root.json"]
1640 c.Assert(ok, Equals, true)
1641
1642 c.Assert(json.Unmarshal(rootJSON, &signedRoot), IsNil)
1643 c.Assert(signedRoot.Signed.Version, Equals, int64(2))
1644
1645 unknownKey, ok = signedRoot.Signed.Keys["unknown-key-id"]
1646 c.Assert(ok, Equals, true)
1647 c.Assert(unknownKey, DeepEquals, signer.PublicData())
1648 }
1649
1650 func (rs *RepoSuite) TestThreshold(c *C) {
1651 local := MemoryStore(make(map[string]json.RawMessage), nil)
1652 r, err := NewRepo(local)
1653 c.Assert(err, IsNil)
1654
1655 _, err = r.GetThreshold("root")
1656 c.Assert(err, DeepEquals, ErrInvalidRole{"root", "role missing from root metadata"})
1657 err = r.SetThreshold("root", 2)
1658 c.Assert(err, DeepEquals, ErrInvalidRole{"root", "role missing from root metadata"})
1659
1660
1661 genKey(c, r, "root")
1662 genKey(c, r, "targets")
1663 genKey(c, r, "snapshot")
1664 genKey(c, r, "timestamp")
1665 t, err := r.GetThreshold("root")
1666 c.Assert(err, IsNil)
1667 c.Assert(t, Equals, 1)
1668
1669 _, err = r.GetThreshold("foo")
1670 c.Assert(err, DeepEquals, ErrInvalidRole{"foo", "only thresholds for top-level roles supported"})
1671 err = r.SetThreshold("foo", 2)
1672 c.Assert(err, DeepEquals, ErrInvalidRole{"foo", "only thresholds for top-level roles supported"})
1673
1674
1675 c.Assert(r.AddTargets([]string{}, nil), IsNil)
1676 c.Assert(r.Snapshot(), IsNil)
1677 c.Assert(r.Timestamp(), IsNil)
1678 c.Assert(r.Commit(), IsNil)
1679
1680
1681 c.Assert(r.SetThreshold("root", 2), IsNil)
1682 t, err = r.GetThreshold("root")
1683 c.Assert(err, IsNil)
1684 c.Assert(t, Equals, 2)
1685 c.Assert(r.Commit(), DeepEquals, ErrNotEnoughKeys{"root", 1, 2})
1686
1687
1688 genKey(c, r, "root")
1689 c.Assert(r.Sign("root.json"), IsNil)
1690 c.Assert(r.Snapshot(), IsNil)
1691 c.Assert(r.Timestamp(), IsNil)
1692 c.Assert(r.Commit(), IsNil)
1693
1694
1695 rootVersion, err := r.RootVersion()
1696 c.Assert(err, IsNil)
1697 c.Assert(rootVersion, Equals, int64(2))
1698
1699 targetsVersion, err := r.TargetsVersion()
1700 c.Assert(err, IsNil)
1701 c.Assert(targetsVersion, Equals, int64(1))
1702
1703 snapshotVersion, err := r.SnapshotVersion()
1704 c.Assert(err, IsNil)
1705 c.Assert(snapshotVersion, Equals, int64(2))
1706
1707 timestampVersion, err := r.TimestampVersion()
1708 c.Assert(err, IsNil)
1709 c.Assert(timestampVersion, Equals, int64(2))
1710 }
1711
1712 func (rs *RepoSuite) TestAddOrUpdateSignatures(c *C) {
1713 files := map[string][]byte{"foo.txt": []byte("foo")}
1714 local := MemoryStore(make(map[string]json.RawMessage), files)
1715 r, err := NewRepo(local)
1716 c.Assert(err, IsNil)
1717
1718
1719 c.Assert(r.Init(false), IsNil)
1720
1721
1722 rootKey, err := keys.GenerateEd25519Key()
1723 c.Assert(err, IsNil)
1724 c.Assert(r.AddVerificationKey("root", rootKey.PublicData()), IsNil)
1725 targetsKey, err := keys.GenerateEd25519Key()
1726 c.Assert(err, IsNil)
1727 c.Assert(r.AddVerificationKey("targets", targetsKey.PublicData()), IsNil)
1728 snapshotKey, err := keys.GenerateEd25519Key()
1729 c.Assert(err, IsNil)
1730 c.Assert(r.AddVerificationKey("snapshot", snapshotKey.PublicData()), IsNil)
1731 timestampKey, err := keys.GenerateEd25519Key()
1732 c.Assert(err, IsNil)
1733 c.Assert(r.AddVerificationKey("timestamp", timestampKey.PublicData()), IsNil)
1734
1735
1736 rootMeta, err := r.SignedMeta("root.json")
1737 c.Assert(err, IsNil)
1738 rootCanonical, err := cjson.EncodeCanonical(rootMeta.Signed)
1739 c.Assert(err, IsNil)
1740 rootSig, err := rootKey.SignMessage(rootCanonical)
1741 c.Assert(err, IsNil)
1742 for _, id := range rootKey.PublicData().IDs() {
1743 c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{
1744 KeyID: id,
1745 Signature: rootSig}), IsNil)
1746 }
1747
1748
1749 c.Assert(r.AddTarget("foo.txt", nil), IsNil)
1750 targetsMeta, err := r.SignedMeta("targets.json")
1751 c.Assert(err, IsNil)
1752 targetsCanonical, err := cjson.EncodeCanonical(targetsMeta.Signed)
1753 c.Assert(err, IsNil)
1754 targetsSig, err := targetsKey.SignMessage(targetsCanonical)
1755 c.Assert(err, IsNil)
1756 for _, id := range targetsKey.PublicData().IDs() {
1757 r.AddOrUpdateSignature("targets.json", data.Signature{
1758 KeyID: id,
1759 Signature: targetsSig})
1760 }
1761
1762
1763 c.Assert(r.Snapshot(), IsNil)
1764 snapshotMeta, err := r.SignedMeta("snapshot.json")
1765 c.Assert(err, IsNil)
1766 snapshotCanonical, err := cjson.EncodeCanonical(snapshotMeta.Signed)
1767 c.Assert(err, IsNil)
1768 snapshotSig, err := snapshotKey.SignMessage(snapshotCanonical)
1769 c.Assert(err, IsNil)
1770 for _, id := range snapshotKey.PublicData().IDs() {
1771 r.AddOrUpdateSignature("snapshot.json", data.Signature{
1772 KeyID: id,
1773 Signature: snapshotSig})
1774 }
1775
1776 c.Assert(r.Timestamp(), IsNil)
1777 timestampMeta, err := r.SignedMeta("timestamp.json")
1778 c.Assert(err, IsNil)
1779 timestampCanonical, err := cjson.EncodeCanonical(timestampMeta.Signed)
1780 c.Assert(err, IsNil)
1781 timestampSig, err := timestampKey.SignMessage(timestampCanonical)
1782 c.Assert(err, IsNil)
1783 for _, id := range timestampKey.PublicData().IDs() {
1784 r.AddOrUpdateSignature("timestamp.json", data.Signature{
1785 KeyID: id,
1786 Signature: timestampSig})
1787 }
1788
1789
1790 c.Assert(r.Commit(), IsNil)
1791 }
1792
1793 func (rs *RepoSuite) TestBadAddOrUpdateSignatures(c *C) {
1794 files := map[string][]byte{"foo.txt": []byte("foo")}
1795 local := MemoryStore(make(map[string]json.RawMessage), files)
1796 r, err := NewRepo(local)
1797 c.Assert(err, IsNil)
1798
1799
1800 c.Assert(r.Init(false), IsNil)
1801
1802 c.Assert(r.AddOrUpdateSignature("targets.json", data.Signature{
1803 KeyID: "foo",
1804 Signature: nil}), Equals, ErrInvalidRole{"targets", "role is not in verifier DB"})
1805
1806
1807 rootKey, err := keys.GenerateEd25519Key()
1808 c.Assert(err, IsNil)
1809 c.Assert(r.AddVerificationKey("root", rootKey.PublicData()), IsNil)
1810 targetsKey, err := keys.GenerateEd25519Key()
1811 c.Assert(err, IsNil)
1812 c.Assert(r.AddVerificationKey("targets", targetsKey.PublicData()), IsNil)
1813 snapshotKey, err := keys.GenerateEd25519Key()
1814 c.Assert(err, IsNil)
1815 c.Assert(r.AddVerificationKey("snapshot", snapshotKey.PublicData()), IsNil)
1816 timestampKey, err := keys.GenerateEd25519Key()
1817 c.Assert(err, IsNil)
1818 c.Assert(r.AddVerificationKey("timestamp", timestampKey.PublicData()), IsNil)
1819
1820
1821 for _, id := range rootKey.PublicData().IDs() {
1822 c.Assert(r.AddOrUpdateSignature("root", data.Signature{
1823 KeyID: id,
1824 Signature: nil}), Equals, ErrMissingMetadata{"root"})
1825 }
1826
1827
1828 rootMeta, err := r.SignedMeta("root.json")
1829 c.Assert(err, IsNil)
1830 rootCanonical, err := cjson.EncodeCanonical(rootMeta.Signed)
1831 c.Assert(err, IsNil)
1832 rootSig, err := rootKey.Sign(rand.Reader, rootCanonical, crypto.Hash(0))
1833 c.Assert(err, IsNil)
1834 for _, id := range rootKey.PublicData().IDs() {
1835 c.Assert(r.AddOrUpdateSignature("invalid_root.json", data.Signature{
1836 KeyID: id,
1837 Signature: rootSig}), Equals, ErrInvalidRole{"invalid_root", "no trusted keys for role"})
1838 }
1839
1840
1841 for _, id := range targetsKey.PublicData().IDs() {
1842 c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{
1843 KeyID: id,
1844 Signature: rootSig}), Equals, verify.ErrInvalidKey)
1845 }
1846
1847
1848 badSig, err := rootKey.Sign(rand.Reader, []byte(""), crypto.Hash(0))
1849 c.Assert(err, IsNil)
1850 for _, id := range rootKey.PublicData().IDs() {
1851 c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{
1852 KeyID: id,
1853 Signature: badSig}), Equals, verify.ErrInvalid)
1854 }
1855
1856
1857 for _, id := range rootKey.PublicData().IDs() {
1858 c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{
1859 KeyID: id,
1860 Signature: rootSig}), IsNil)
1861 }
1862 checkSigIDs := func(role string) {
1863 s, err := r.SignedMeta(role)
1864 c.Assert(err, IsNil)
1865 db, err := r.topLevelKeysDB()
1866 c.Assert(err, IsNil)
1867
1868 keys := db.GetRole(strings.TrimSuffix(role, ".json")).KeyIDs
1869 c.Assert(s.Signatures, HasLen, len(keys))
1870
1871
1872 for _, sig := range s.Signatures {
1873 if _, ok := keys[sig.KeyID]; !ok {
1874 c.Fatal("missing key ID in signatures")
1875 }
1876 }
1877 }
1878 checkSigIDs("root.json")
1879
1880
1881
1882 for _, id := range rootKey.PublicData().IDs() {
1883 c.Assert(r.AddOrUpdateSignature("root.json", data.Signature{
1884 KeyID: id,
1885 Signature: rootSig}), IsNil)
1886 }
1887 checkSigIDs("root.json")
1888 }
1889
1890 func (rs *RepoSuite) TestSignDigest(c *C) {
1891 files := map[string][]byte{"foo.txt": []byte("foo")}
1892 local := MemoryStore(make(map[string]json.RawMessage), files)
1893 r, err := NewRepo(local)
1894 c.Assert(err, IsNil)
1895
1896 genKey(c, r, "root")
1897 genKey(c, r, "targets")
1898 genKey(c, r, "snapshot")
1899 genKey(c, r, "timestamp")
1900
1901 digest := "sha256:bc11b176a293bb341a0f2d0d226f52e7fcebd186a7c4dfca5fc64f305f06b94c"
1902 hash := "bc11b176a293bb341a0f2d0d226f52e7fcebd186a7c4dfca5fc64f305f06b94c"
1903 size := int64(42)
1904
1905 c.Assert(r.AddTargetsWithDigest(hash, "sha256", size, digest, nil), IsNil)
1906 c.Assert(r.Snapshot(), IsNil)
1907 c.Assert(r.Timestamp(), IsNil)
1908 c.Assert(r.Commit(), IsNil)
1909
1910 digest_bytes, err := hex.DecodeString("bc11b176a293bb341a0f2d0d226f52e7fcebd186a7c4dfca5fc64f305f06b94c")
1911 hex_digest_bytes := data.HexBytes(digest_bytes)
1912 c.Assert(err, IsNil)
1913
1914 targets, err := r.topLevelTargets()
1915 c.Assert(err, IsNil)
1916 c.Assert(targets.Targets["sha256:bc11b176a293bb341a0f2d0d226f52e7fcebd186a7c4dfca5fc64f305f06b94c"].FileMeta.Length, Equals, size)
1917 c.Assert(targets.Targets["sha256:bc11b176a293bb341a0f2d0d226f52e7fcebd186a7c4dfca5fc64f305f06b94c"].FileMeta.Hashes["sha256"], DeepEquals, hex_digest_bytes)
1918 }
1919
1920 func concat(ss ...[]string) []string {
1921 ret := []string{}
1922 for _, s := range ss {
1923 ret = append(ret, s...)
1924 }
1925 return ret
1926 }
1927
1928 func checkSigKeyIDs(c *C, local LocalStore, fileToKeyIDs map[string][]string) {
1929 metas, err := local.GetMeta()
1930 c.Assert(err, IsNil)
1931
1932 for f, keyIDs := range fileToKeyIDs {
1933 meta, ok := metas[f]
1934 c.Assert(ok, Equals, true, Commentf("meta file: %v", f))
1935
1936 s := &data.Signed{}
1937 err = json.Unmarshal(meta, s)
1938 c.Assert(err, IsNil)
1939
1940 gotKeyIDs := []string{}
1941 for _, sig := range s.Signatures {
1942 gotKeyIDs = append(gotKeyIDs, sig.KeyID)
1943 }
1944 gotKeyIDs = sets.DeduplicateStrings(gotKeyIDs)
1945 sort.Strings(gotKeyIDs)
1946
1947 sort.Strings(keyIDs)
1948 c.Assert(gotKeyIDs, DeepEquals, keyIDs)
1949 }
1950 }
1951
1952 func (rs *RepoSuite) TestDelegations(c *C) {
1953 tmp := newTmpDir(c)
1954 local := FileSystemStore(tmp.path, nil)
1955 r, err := NewRepo(local)
1956 c.Assert(err, IsNil)
1957
1958
1959 genKey(c, r, "root")
1960 targetsKeyIDs := genKey(c, r, "targets")
1961 genKey(c, r, "snapshot")
1962 genKey(c, r, "timestamp")
1963
1964
1965 c.Assert(r.AddTargets([]string{}, nil), IsNil)
1966 c.Assert(r.Snapshot(), IsNil)
1967 c.Assert(r.Timestamp(), IsNil)
1968 c.Assert(r.Commit(), IsNil)
1969
1970 snapshot, err := r.snapshot()
1971 c.Assert(err, IsNil)
1972 c.Assert(snapshot.Meta, HasLen, 1)
1973 c.Assert(snapshot.Meta["targets.json"].Version, Equals, int64(1))
1974
1975 checkSigKeyIDs(c, local, map[string][]string{
1976 "1.targets.json": targetsKeyIDs,
1977 })
1978
1979 saveNewKey := func(role string) keys.Signer {
1980 key, err := keys.GenerateEd25519Key()
1981 c.Assert(err, IsNil)
1982
1983 err = local.SaveSigner(role, key)
1984 c.Assert(err, IsNil)
1985
1986 return key
1987 }
1988
1989
1990 role1ABKey := saveNewKey("role1")
1991 role1AB := data.DelegatedRole{
1992 Name: "role1",
1993 KeyIDs: role1ABKey.PublicData().IDs(),
1994 Paths: []string{"A/*", "B/*"},
1995 Threshold: 1,
1996 }
1997 err = r.AddDelegatedRole("targets", role1AB, []*data.PublicKey{
1998 role1ABKey.PublicData(),
1999 })
2000 c.Assert(err, IsNil)
2001
2002
2003 err = r.AddDelegatedRole("targets", role1AB, []*data.PublicKey{
2004 role1ABKey.PublicData(),
2005 })
2006 c.Assert(err, NotNil)
2007
2008
2009 role2CDKey1 := saveNewKey("role2")
2010 role2CDKey2 := saveNewKey("role2")
2011 role2CDKey3 := saveNewKey("role2")
2012 role2CD := data.DelegatedRole{
2013 Name: "role2",
2014 KeyIDs: concat(
2015 role2CDKey1.PublicData().IDs(),
2016 role2CDKey2.PublicData().IDs(),
2017 role2CDKey3.PublicData().IDs(),
2018 ),
2019 Paths: []string{"C/*", "D/*"},
2020 Threshold: 2,
2021 }
2022 err = r.AddDelegatedRole("targets", role2CD, []*data.PublicKey{
2023 role2CDKey1.PublicData(),
2024 role2CDKey2.PublicData(),
2025 role2CDKey3.PublicData(),
2026 })
2027 c.Assert(err, IsNil)
2028
2029
2030 role1To2Key := saveNewKey("role2")
2031 role1To2 := data.DelegatedRole{
2032 Name: "role2",
2033 KeyIDs: role1To2Key.PublicData().IDs(),
2034 Paths: []string{"A/allium.txt"},
2035 Threshold: 1,
2036 Terminating: true,
2037 }
2038 err = r.AddDelegatedRole("role1", role1To2, []*data.PublicKey{
2039 role1To2Key.PublicData(),
2040 })
2041 c.Assert(err, IsNil)
2042
2043 checkDelegations := func(delegator string, delegatedRoles ...data.DelegatedRole) {
2044 t, err := r.targets(delegator)
2045 c.Assert(err, IsNil)
2046
2047
2048 if t.Delegations == nil {
2049 if delegatedRoles != nil {
2050 c.Fatal("expected delegated roles on delegator")
2051 }
2052 return
2053 }
2054
2055
2056 c.Assert(t.Delegations.Roles, DeepEquals, delegatedRoles)
2057
2058
2059 expectedKeyIDs := []string{}
2060 for _, dr := range delegatedRoles {
2061 expectedKeyIDs = append(expectedKeyIDs, dr.KeyIDs...)
2062 }
2063 expectedKeyIDs = sets.DeduplicateStrings(expectedKeyIDs)
2064 sort.Strings(expectedKeyIDs)
2065
2066 gotKeyIDs := []string{}
2067 for _, k := range t.Delegations.Keys {
2068 gotKeyIDs = append(gotKeyIDs, k.IDs()...)
2069 }
2070 gotKeyIDs = sets.DeduplicateStrings(gotKeyIDs)
2071 sort.Strings(gotKeyIDs)
2072
2073 c.Assert(gotKeyIDs, DeepEquals, expectedKeyIDs)
2074 }
2075
2076 checkDelegations("targets", role1AB, role2CD)
2077 checkDelegations("role1", role1To2)
2078
2079 c.Assert(r.Snapshot(), IsNil)
2080 c.Assert(r.Timestamp(), IsNil)
2081 c.Assert(r.Commit(), IsNil)
2082
2083 snapshot, err = r.snapshot()
2084 c.Assert(err, IsNil)
2085 c.Assert(snapshot.Meta, HasLen, 3)
2086 c.Assert(snapshot.Meta["targets.json"].Version, Equals, int64(2))
2087 c.Assert(snapshot.Meta["role1.json"].Version, Equals, int64(1))
2088 c.Assert(snapshot.Meta["role2.json"].Version, Equals, int64(1))
2089
2090 checkSigKeyIDs(c, local, map[string][]string{
2091 "2.targets.json": targetsKeyIDs,
2092 "1.role1.json": role1ABKey.PublicData().IDs(),
2093 "1.role2.json": concat(
2094 role2CDKey1.PublicData().IDs(),
2095 role2CDKey2.PublicData().IDs(),
2096 role2CDKey3.PublicData().IDs(),
2097 role1To2Key.PublicData().IDs(),
2098 ),
2099 })
2100
2101
2102 files := map[string]string{
2103
2104 "potato.txt": "potatoes can be starchy or waxy",
2105
2106 "A/apple.txt": "apples are sometimes red",
2107 "B/banana.txt": "bananas are yellow and sometimes brown",
2108
2109 "C/clementine.txt": "clementines are a citrus fruit",
2110 "D/durian.txt": "durians are spiky",
2111 "A/allium.txt": "alliums include garlic and leeks",
2112 }
2113 for name, content := range files {
2114 tmp.writeStagedTarget(name, content)
2115 c.Assert(r.AddTarget(name, nil), IsNil)
2116 }
2117
2118 c.Assert(r.Snapshot(), IsNil)
2119 c.Assert(r.Timestamp(), IsNil)
2120 c.Assert(r.Commit(), IsNil)
2121
2122 snapshot, err = r.snapshot()
2123 c.Assert(err, IsNil)
2124 c.Assert(snapshot.Meta, HasLen, 3)
2125
2126 c.Assert(snapshot.Meta["targets.json"].Version, Equals, int64(3))
2127 c.Assert(snapshot.Meta["role1.json"].Version, Equals, int64(2))
2128 c.Assert(snapshot.Meta["role2.json"].Version, Equals, int64(2))
2129
2130 checkSigKeyIDs(c, local, map[string][]string{
2131 "3.targets.json": targetsKeyIDs,
2132 "2.role1.json": role1ABKey.PublicData().IDs(),
2133 "2.role2.json": concat(
2134 role2CDKey1.PublicData().IDs(),
2135 role2CDKey2.PublicData().IDs(),
2136 role2CDKey3.PublicData().IDs(),
2137 role1To2Key.PublicData().IDs(),
2138 ),
2139 })
2140
2141
2142
2143 checkTargets := func(role string, filenames ...string) {
2144 t, err := r.targets(role)
2145 c.Assert(err, IsNil)
2146 c.Assert(t.Targets, HasLen, len(filenames))
2147
2148 for _, fn := range filenames {
2149 content := files[fn]
2150
2151 fm, err := util.GenerateTargetFileMeta(strings.NewReader(content))
2152 c.Assert(err, IsNil)
2153
2154 c.Assert(util.TargetFileMetaEqual(t.Targets[fn], fm), IsNil)
2155 }
2156 }
2157
2158 checkTargets("targets", "potato.txt")
2159 checkTargets("role1", "A/apple.txt", "B/banana.txt")
2160 checkTargets("role2", "C/clementine.txt", "D/durian.txt", "A/allium.txt")
2161
2162
2163
2164
2165 c.Assert(r.RemoveTarget("A/allium.txt"), IsNil)
2166 tmp.writeStagedTarget("A/allium.txt", files["A/allium.txt"])
2167 c.Assert(r.AddTargetToPreferredRole("A/allium.txt", nil, "role1"), IsNil)
2168
2169 c.Assert(r.Snapshot(), IsNil)
2170 c.Assert(r.Timestamp(), IsNil)
2171 c.Assert(r.Commit(), IsNil)
2172
2173 snapshot, err = r.snapshot()
2174 c.Assert(err, IsNil)
2175 c.Assert(snapshot.Meta, HasLen, 3)
2176
2177 c.Assert(snapshot.Meta["targets.json"].Version, Equals, int64(3))
2178 c.Assert(snapshot.Meta["role1.json"].Version, Equals, int64(3))
2179 c.Assert(snapshot.Meta["role2.json"].Version, Equals, int64(3))
2180
2181 checkSigKeyIDs(c, local, map[string][]string{
2182 "3.targets.json": targetsKeyIDs,
2183 "3.role1.json": role1ABKey.PublicData().IDs(),
2184 "3.role2.json": concat(
2185 role2CDKey1.PublicData().IDs(),
2186 role2CDKey2.PublicData().IDs(),
2187 role2CDKey3.PublicData().IDs(),
2188 role1To2Key.PublicData().IDs(),
2189 ),
2190 })
2191
2192
2193 checkTargets("targets", "potato.txt")
2194 checkTargets("role1", "A/apple.txt", "B/banana.txt", "A/allium.txt")
2195 checkTargets("role2", "C/clementine.txt", "D/durian.txt")
2196
2197
2198 c.Assert(r.ResetTargetsDelegations("role1"), IsNil)
2199 checkDelegations("targets", role1AB, role2CD)
2200 checkDelegations("role1")
2201
2202
2203
2204 c.Assert(r.RemoveTarget("A/allium.txt"), IsNil)
2205 tmp.writeStagedTarget("A/allium.txt", files["A/allium.txt"])
2206 c.Assert(r.AddTargetToPreferredRole("A/allium.txt", nil, "role2"), Equals, ErrNoDelegatedTarget{Path: "A/allium.txt"})
2207
2208
2209 c.Assert(r.AddTarget("A/allium.txt", nil), IsNil)
2210
2211 c.Assert(r.Snapshot(), IsNil)
2212 c.Assert(r.Timestamp(), IsNil)
2213 c.Assert(r.Commit(), IsNil)
2214
2215 snapshot, err = r.snapshot()
2216 c.Assert(err, IsNil)
2217 c.Assert(snapshot.Meta, HasLen, 3)
2218
2219 c.Assert(snapshot.Meta["targets.json"].Version, Equals, int64(3))
2220 c.Assert(snapshot.Meta["role1.json"].Version, Equals, int64(4))
2221 c.Assert(snapshot.Meta["role2.json"].Version, Equals, int64(3))
2222
2223 checkSigKeyIDs(c, local, map[string][]string{
2224 "3.targets.json": targetsKeyIDs,
2225 "4.role1.json": role1ABKey.PublicData().IDs(),
2226 "3.role2.json": concat(
2227
2228
2229
2230
2231 role2CDKey1.PublicData().IDs(),
2232 role2CDKey2.PublicData().IDs(),
2233 role2CDKey3.PublicData().IDs(),
2234 role1To2Key.PublicData().IDs(),
2235 ),
2236 })
2237
2238
2239
2240 c.Assert(r.RemoveTarget("C/clementine.txt"), IsNil)
2241 tmp.writeStagedTarget("C/clementine.txt", files["C/clementine.txt"])
2242 c.Assert(r.AddTarget("C/clementine.txt", nil), IsNil)
2243
2244 c.Assert(r.Snapshot(), IsNil)
2245 c.Assert(r.Timestamp(), IsNil)
2246 c.Assert(r.Commit(), IsNil)
2247
2248 snapshot, err = r.snapshot()
2249 c.Assert(err, IsNil)
2250 c.Assert(snapshot.Meta, HasLen, 3)
2251
2252 c.Assert(snapshot.Meta["targets.json"].Version, Equals, int64(3))
2253 c.Assert(snapshot.Meta["role1.json"].Version, Equals, int64(4))
2254 c.Assert(snapshot.Meta["role2.json"].Version, Equals, int64(4))
2255
2256 checkSigKeyIDs(c, local, map[string][]string{
2257 "3.targets.json": targetsKeyIDs,
2258 "4.role1.json": role1ABKey.PublicData().IDs(),
2259 "4.role2.json": concat(
2260 role2CDKey1.PublicData().IDs(),
2261 role2CDKey2.PublicData().IDs(),
2262 role2CDKey3.PublicData().IDs(),
2263
2264
2265 ),
2266 })
2267
2268
2269 checkTargets("targets", "potato.txt")
2270 checkTargets("role1", "A/apple.txt", "B/banana.txt", "A/allium.txt")
2271 checkTargets("role2", "C/clementine.txt", "D/durian.txt")
2272
2273
2274
2275 err = r.AddDelegatedRole("role1", role1To2, []*data.PublicKey{
2276 role1To2Key.PublicData(),
2277 })
2278 c.Assert(err, IsNil)
2279 c.Assert(r.Snapshot(), IsNil)
2280 c.Assert(r.Timestamp(), IsNil)
2281 c.Assert(r.Commit(), IsNil)
2282
2283 snapshot, err = r.snapshot()
2284 c.Assert(err, IsNil)
2285 c.Assert(snapshot.Meta, HasLen, 3)
2286
2287
2288
2289 c.Assert(snapshot.Meta["targets.json"].Version, Equals, int64(3))
2290 c.Assert(snapshot.Meta["role1.json"].Version, Equals, int64(5))
2291 c.Assert(snapshot.Meta["role2.json"].Version, Equals, int64(5))
2292
2293 checkTargets("targets", "potato.txt")
2294 checkTargets("role1", "A/apple.txt", "B/banana.txt", "A/allium.txt")
2295 checkTargets("role2", "C/clementine.txt", "D/durian.txt")
2296 }
2297
2298 func (rs *RepoSuite) TestHashBinDelegations(c *C) {
2299 tmp := newTmpDir(c)
2300 local := FileSystemStore(tmp.path, nil)
2301 r, err := NewRepo(local)
2302 c.Assert(err, IsNil)
2303
2304
2305 genKey(c, r, "root")
2306 targetsKeyIDs := genKey(c, r, "targets")
2307 genKey(c, r, "snapshot")
2308 genKey(c, r, "timestamp")
2309
2310 hb, err := targets.NewHashBins("bins_", 3)
2311 if err != nil {
2312 c.Assert(err, IsNil)
2313 }
2314
2315
2316 binsKey, err := keys.GenerateEd25519Key()
2317 c.Assert(err, IsNil)
2318 err = local.SaveSigner("bins", binsKey)
2319 c.Assert(err, IsNil)
2320
2321
2322 leafKey, err := keys.GenerateEd25519Key()
2323 c.Assert(err, IsNil)
2324 for i := uint64(0); i < hb.NumBins(); i++ {
2325 b := hb.GetBin(i)
2326 err = local.SaveSigner(b.RoleName(), leafKey)
2327 if err != nil {
2328 c.Assert(err, IsNil)
2329 }
2330 }
2331
2332 err = r.AddDelegatedRole("targets", data.DelegatedRole{
2333 Name: "bins",
2334 KeyIDs: binsKey.PublicData().IDs(),
2335 Paths: []string{"*.txt"},
2336 Threshold: 1,
2337 }, []*data.PublicKey{
2338 binsKey.PublicData(),
2339 })
2340 c.Assert(err, IsNil)
2341
2342 err = r.AddDelegatedRolesForPathHashBins("bins", hb, []*data.PublicKey{leafKey.PublicData()}, 1)
2343 c.Assert(err, IsNil)
2344 targets, err := r.targets("bins")
2345 c.Assert(err, IsNil)
2346 c.Assert(targets.Delegations.Roles, HasLen, 8)
2347
2348 c.Assert(r.Snapshot(), IsNil)
2349 c.Assert(r.Timestamp(), IsNil)
2350 c.Assert(r.Commit(), IsNil)
2351
2352 tmp.writeStagedTarget("foo.txt", "foo")
2353 err = r.AddTarget("foo.txt", nil)
2354 c.Assert(err, IsNil)
2355
2356 c.Assert(r.Snapshot(), IsNil)
2357 c.Assert(r.Timestamp(), IsNil)
2358 c.Assert(r.Commit(), IsNil)
2359
2360 snapshot, err := r.snapshot()
2361 c.Assert(err, IsNil)
2362
2363 c.Assert(snapshot.Meta, HasLen, 10)
2364 c.Assert(snapshot.Meta["targets.json"].Version, Equals, int64(1))
2365 c.Assert(snapshot.Meta["bins.json"].Version, Equals, int64(1))
2366 c.Assert(snapshot.Meta["bins_0-1.json"].Version, Equals, int64(1))
2367 c.Assert(snapshot.Meta["bins_2-3.json"].Version, Equals, int64(1))
2368 c.Assert(snapshot.Meta["bins_4-5.json"].Version, Equals, int64(1))
2369 c.Assert(snapshot.Meta["bins_6-7.json"].Version, Equals, int64(1))
2370 c.Assert(snapshot.Meta["bins_8-9.json"].Version, Equals, int64(1))
2371 c.Assert(snapshot.Meta["bins_a-b.json"].Version, Equals, int64(1))
2372 c.Assert(snapshot.Meta["bins_c-d.json"].Version, Equals, int64(2))
2373 c.Assert(snapshot.Meta["bins_e-f.json"].Version, Equals, int64(1))
2374
2375 targets, err = r.targets("bins_c-d")
2376 c.Assert(err, IsNil)
2377 c.Assert(targets.Targets, HasLen, 1)
2378
2379 checkSigKeyIDs(c, local, map[string][]string{
2380 "targets.json": targetsKeyIDs,
2381 "1.bins.json": binsKey.PublicData().IDs(),
2382 "1.bins_0-1.json": leafKey.PublicData().IDs(),
2383 "1.bins_2-3.json": leafKey.PublicData().IDs(),
2384 "1.bins_4-5.json": leafKey.PublicData().IDs(),
2385 "1.bins_6-7.json": leafKey.PublicData().IDs(),
2386 "1.bins_8-9.json": leafKey.PublicData().IDs(),
2387 "1.bins_a-b.json": leafKey.PublicData().IDs(),
2388 "1.bins_c-d.json": leafKey.PublicData().IDs(),
2389 "2.bins_c-d.json": leafKey.PublicData().IDs(),
2390 "1.bins_e-f.json": leafKey.PublicData().IDs(),
2391 })
2392 }
2393
2394 func (rs *RepoSuite) TestResetTargetsDelegationsWithExpires(c *C) {
2395 tmp := newTmpDir(c)
2396 local := FileSystemStore(tmp.path, nil)
2397 r, err := NewRepo(local)
2398 c.Assert(err, IsNil)
2399
2400
2401 genKey(c, r, "root")
2402 targetsKeyIDs := genKey(c, r, "targets")
2403 genKey(c, r, "snapshot")
2404 genKey(c, r, "timestamp")
2405
2406
2407 c.Assert(r.AddTargets([]string{}, nil), IsNil)
2408 c.Assert(r.Snapshot(), IsNil)
2409 c.Assert(r.Timestamp(), IsNil)
2410 c.Assert(r.Commit(), IsNil)
2411
2412 snapshot, err := r.snapshot()
2413 c.Assert(err, IsNil)
2414 c.Assert(snapshot.Meta, HasLen, 1)
2415 c.Assert(snapshot.Meta["targets.json"].Version, Equals, int64(1))
2416
2417 checkSigKeyIDs(c, local, map[string][]string{
2418 "1.targets.json": targetsKeyIDs,
2419 })
2420
2421 role1Key, err := keys.GenerateEd25519Key()
2422 c.Assert(err, IsNil)
2423
2424 err = local.SaveSigner("role1", role1Key)
2425 c.Assert(err, IsNil)
2426
2427
2428 role1 := data.DelegatedRole{
2429 Name: "role1",
2430 KeyIDs: role1Key.PublicData().IDs(),
2431 Paths: []string{"A/*", "B/*"},
2432 Threshold: 1,
2433 }
2434 err = r.AddDelegatedRole("targets", role1, []*data.PublicKey{
2435 role1Key.PublicData(),
2436 })
2437 c.Assert(err, IsNil)
2438
2439 c.Assert(r.Snapshot(), IsNil)
2440 c.Assert(r.Timestamp(), IsNil)
2441 c.Assert(r.Commit(), IsNil)
2442
2443 snapshot, err = r.snapshot()
2444 c.Assert(err, IsNil)
2445 c.Assert(snapshot.Meta, HasLen, 2)
2446 c.Assert(snapshot.Meta["targets.json"].Version, Equals, int64(2))
2447 c.Assert(snapshot.Meta["role1.json"].Version, Equals, int64(1))
2448
2449 checkSigKeyIDs(c, local, map[string][]string{
2450 "1.targets.json": targetsKeyIDs,
2451 "targets.json": targetsKeyIDs,
2452 "1.role1.json": role1Key.PublicData().IDs(),
2453 "role1.json": role1Key.PublicData().IDs(),
2454 })
2455
2456 c.Assert(r.ResetTargetsDelegations("targets"), IsNil)
2457 c.Assert(r.Snapshot(), IsNil)
2458 c.Assert(r.Timestamp(), IsNil)
2459 c.Assert(r.Commit(), IsNil)
2460
2461 snapshot, err = r.snapshot()
2462 c.Assert(err, IsNil)
2463 c.Assert(snapshot.Meta, HasLen, 2)
2464 c.Assert(snapshot.Meta["targets.json"].Version, Equals, int64(3))
2465 c.Assert(snapshot.Meta["role1.json"].Version, Equals, int64(1))
2466
2467 checkSigKeyIDs(c, local, map[string][]string{
2468 "2.targets.json": targetsKeyIDs,
2469 "targets.json": targetsKeyIDs,
2470 "1.role1.json": role1Key.PublicData().IDs(),
2471 "role1.json": role1Key.PublicData().IDs(),
2472 })
2473 }
2474
2475 func (rs *RepoSuite) TestSignWithDelegations(c *C) {
2476 tmp := newTmpDir(c)
2477 local := FileSystemStore(tmp.path, nil)
2478 r, err := NewRepo(local)
2479 c.Assert(err, IsNil)
2480
2481
2482 genKey(c, r, "root")
2483 genKey(c, r, "targets")
2484 genKey(c, r, "snapshot")
2485 genKey(c, r, "timestamp")
2486
2487 role1Key, err := keys.GenerateEd25519Key()
2488 c.Assert(err, IsNil)
2489
2490 role1 := data.DelegatedRole{
2491 Name: "role1",
2492 KeyIDs: role1Key.PublicData().IDs(),
2493 Paths: []string{"A/*", "B/*"},
2494 Threshold: 1,
2495 }
2496 err = r.AddDelegatedRole("targets", role1, []*data.PublicKey{
2497 role1Key.PublicData(),
2498 })
2499 c.Assert(err, IsNil)
2500
2501
2502
2503 m, err := local.GetMeta()
2504 c.Assert(err, IsNil)
2505 targetsMeta := &data.Signed{}
2506 c.Assert(json.Unmarshal(m["targets.json"], targetsMeta), IsNil)
2507 c.Assert(len(targetsMeta.Signatures), Equals, 1)
2508 role1Meta := &data.Signed{}
2509 c.Assert(json.Unmarshal(m["role1.json"], role1Meta), IsNil)
2510 c.Assert(len(role1Meta.Signatures), Equals, 0)
2511
2512 c.Assert(r.Snapshot(), DeepEquals, ErrInsufficientSignatures{"role1.json", verify.ErrNoSignatures})
2513
2514
2515 c.Assert(local.SaveSigner("role1", role1Key), IsNil)
2516 c.Assert(r.Sign("role1.json"), IsNil)
2517
2518 m, err = local.GetMeta()
2519 c.Assert(err, IsNil)
2520 targetsMeta = &data.Signed{}
2521 c.Assert(json.Unmarshal(m["targets.json"], targetsMeta), IsNil)
2522 c.Assert(len(targetsMeta.Signatures), Equals, 1)
2523 role1Meta = &data.Signed{}
2524 c.Assert(json.Unmarshal(m["role1.json"], role1Meta), IsNil)
2525 c.Assert(len(role1Meta.Signatures), Equals, 1)
2526
2527 c.Assert(r.Snapshot(), IsNil)
2528 c.Assert(r.Timestamp(), IsNil)
2529 c.Assert(r.Commit(), IsNil)
2530 }
2531
2532 func (rs *RepoSuite) TestAddOrUpdateSignatureWithDelegations(c *C) {
2533 tmp := newTmpDir(c)
2534 local := FileSystemStore(tmp.path, nil)
2535 r, err := NewRepo(local)
2536 c.Assert(err, IsNil)
2537
2538
2539 genKey(c, r, "root")
2540 genKey(c, r, "targets")
2541 genKey(c, r, "snapshot")
2542 genKey(c, r, "timestamp")
2543
2544 role1Key, err := keys.GenerateEd25519Key()
2545 c.Assert(err, IsNil)
2546
2547 role1 := data.DelegatedRole{
2548 Name: "role1",
2549 KeyIDs: role1Key.PublicData().IDs(),
2550 Paths: []string{"A/*", "B/*"},
2551 Threshold: 1,
2552 }
2553 err = r.AddDelegatedRole("targets", role1, []*data.PublicKey{
2554 role1Key.PublicData(),
2555 })
2556 c.Assert(err, IsNil)
2557
2558
2559
2560 m, err := local.GetMeta()
2561 c.Assert(err, IsNil)
2562 targetsMeta := &data.Signed{}
2563 c.Assert(json.Unmarshal(m["targets.json"], targetsMeta), IsNil)
2564 c.Assert(len(targetsMeta.Signatures), Equals, 1)
2565 role1Meta := &data.Signed{}
2566 c.Assert(json.Unmarshal(m["role1.json"], role1Meta), IsNil)
2567 c.Assert(len(role1Meta.Signatures), Equals, 0)
2568
2569 c.Assert(r.Snapshot(), DeepEquals, ErrInsufficientSignatures{"role1.json", verify.ErrNoSignatures})
2570
2571
2572 canonical, err := cjson.EncodeCanonical(role1Meta.Signed)
2573 c.Assert(err, IsNil)
2574 sig, err := role1Key.SignMessage(canonical)
2575 c.Assert(err, IsNil)
2576 err = r.AddOrUpdateSignature("role1.json", data.Signature{
2577 KeyID: role1Key.PublicData().IDs()[0],
2578 Signature: sig,
2579 })
2580 c.Assert(err, IsNil)
2581
2582 m, err = local.GetMeta()
2583 c.Assert(err, IsNil)
2584 targetsMeta = &data.Signed{}
2585 c.Assert(json.Unmarshal(m["targets.json"], targetsMeta), IsNil)
2586 c.Assert(len(targetsMeta.Signatures), Equals, 1)
2587 role1Meta = &data.Signed{}
2588 c.Assert(json.Unmarshal(m["role1.json"], role1Meta), IsNil)
2589 c.Assert(len(role1Meta.Signatures), Equals, 1)
2590
2591 c.Assert(r.Snapshot(), IsNil)
2592 c.Assert(r.Timestamp(), IsNil)
2593 c.Assert(r.Commit(), IsNil)
2594 }
2595
2596
2597 func (rs *RepoSuite) TestOfflineFlow(c *C) {
2598
2599 meta := make(map[string]json.RawMessage)
2600 local := MemoryStore(meta, nil)
2601 r, err := NewRepo(local)
2602 c.Assert(err, IsNil)
2603 c.Assert(r.Init(false), IsNil)
2604
2605 _, err = r.GenKeyWithSchemeAndExpires("root", data.DefaultExpires("root"), data.KeySchemeECDSA_SHA2_P256)
2606 c.Assert(err, IsNil)
2607
2608
2609 _, err = r.Payload("badrole.json")
2610 c.Assert(err, Equals, ErrMissingMetadata{"badrole.json"})
2611 _, err = r.Payload("root")
2612 c.Assert(err, Equals, ErrMissingMetadata{"root"})
2613 payload, err := r.Payload("root.json")
2614 c.Assert(err, IsNil)
2615
2616 root, err := r.SignedMeta("root.json")
2617 c.Assert(err, IsNil)
2618 rootCanonical, err := cjson.EncodeCanonical(root.Signed)
2619 c.Assert(err, IsNil)
2620 if !bytes.Equal(payload, rootCanonical) {
2621 c.Fatalf("Payload(): not canonical.\n%s\n%s", string(payload), string(rootCanonical))
2622 }
2623
2624
2625 _, err = r.SignRaw("targets", payload)
2626 c.Assert(err, Equals, ErrNoKeys{"targets"})
2627 signatures, err := r.SignRaw("root", payload)
2628 c.Assert(err, IsNil)
2629 c.Assert(len(signatures), Equals, 1)
2630
2631
2632 for _, sig := range signatures {
2633
2634 err = r.AddOrUpdateSignature("root.json", sig)
2635 c.Assert(err, IsNil)
2636 }
2637 }
2638
2639
2640 func (rs *RepoSuite) TestSnapshotWithInvalidRoot(c *C) {
2641 files := map[string][]byte{"foo.txt": []byte("foo")}
2642 local := MemoryStore(make(map[string]json.RawMessage), files)
2643 r, err := NewRepo(local)
2644 c.Assert(err, IsNil)
2645
2646
2647 r.Init(false)
2648
2649 genKey(c, r, "root")
2650 genKey(c, r, "targets")
2651 genKey(c, r, "snapshot")
2652 genKey(c, r, "timestamp")
2653 c.Assert(r.AddTarget("foo.txt", nil), IsNil)
2654
2655
2656 s, err := r.SignedMeta("root.json")
2657 c.Assert(err, IsNil)
2658 c.Assert(s.Signatures, HasLen, 1)
2659 s.Signatures[0].Signature = data.HexBytes{}
2660 b, err := r.jsonMarshal(s)
2661 c.Assert(err, IsNil)
2662 r.meta["root.json"] = b
2663 local.SetMeta("root.json", b)
2664
2665
2666 c.Assert(r.Snapshot(), Equals, ErrInsufficientSignatures{
2667 "root.json", verify.ErrRoleThreshold{Expected: 1, Actual: 0}})
2668
2669
2670 c.Assert(r.Sign("root.json"), IsNil)
2671 c.Assert(r.Snapshot(), IsNil)
2672 c.Assert(r.Timestamp(), IsNil)
2673 c.Assert(r.Commit(), IsNil)
2674 }
2675
2676
2677 func (rs *RepoSuite) TestTargetMetadataLength(c *C) {
2678 files := map[string][]byte{"foo.txt": []byte("")}
2679 local := MemoryStore(make(map[string]json.RawMessage), files)
2680 r, err := NewRepo(local)
2681 c.Assert(err, IsNil)
2682
2683
2684 r.Init(false)
2685
2686 genKey(c, r, "root")
2687 genKey(c, r, "targets")
2688 genKey(c, r, "snapshot")
2689 genKey(c, r, "timestamp")
2690 c.Assert(r.AddTarget("foo.txt", nil), IsNil)
2691 c.Assert(r.Snapshot(), IsNil)
2692 c.Assert(r.Timestamp(), IsNil)
2693 c.Assert(r.Commit(), IsNil)
2694
2695
2696 meta, err := local.GetMeta()
2697 c.Assert(err, IsNil)
2698 targetsJSON, ok := meta["targets.json"]
2699 if !ok {
2700 c.Fatal("missing targets metadata")
2701 }
2702 s := &data.Signed{}
2703 c.Assert(json.Unmarshal(targetsJSON, s), IsNil)
2704 fmt.Fprint(os.Stderr, s.Signed)
2705 var objMap map[string]json.RawMessage
2706 c.Assert(json.Unmarshal(s.Signed, &objMap), IsNil)
2707 targetsMap, ok := objMap["targets"]
2708 if !ok {
2709 c.Fatal("missing targets field in targets metadata")
2710 }
2711 c.Assert(json.Unmarshal(targetsMap, &objMap), IsNil)
2712 targetsMap, ok = objMap["foo.txt"]
2713 if !ok {
2714 c.Fatal("missing foo.txt in targets")
2715 }
2716 c.Assert(json.Unmarshal(targetsMap, &objMap), IsNil)
2717 lengthMsg, ok := objMap["length"]
2718 if !ok {
2719 c.Fatal("missing length field in foo.txt file meta")
2720 }
2721 var length int64
2722 c.Assert(json.Unmarshal(lengthMsg, &length), IsNil)
2723 c.Assert(length, Equals, int64(0))
2724 }
2725
2726 func (rs *RepoSuite) TestDeprecatedHexEncodedKeysFails(c *C) {
2727 files := map[string][]byte{"foo.txt": []byte("foo")}
2728 local := MemoryStore(make(map[string]json.RawMessage), files)
2729 r, err := NewRepo(local)
2730 c.Assert(err, IsNil)
2731
2732 r.Init(false)
2733
2734 signer, err := keys.GenerateEcdsaKey()
2735 c.Assert(err, IsNil)
2736 type deprecatedP256Verifier struct {
2737 PublicKey data.HexBytes `json:"public"`
2738 }
2739 pub := signer.PublicKey
2740 keyValBytes, err := json.Marshal(&deprecatedP256Verifier{PublicKey: elliptic.Marshal(pub.Curve, pub.X, pub.Y)})
2741 c.Assert(err, IsNil)
2742 publicData := &data.PublicKey{
2743 Type: data.KeyTypeECDSA_SHA2_P256,
2744 Scheme: data.KeySchemeECDSA_SHA2_P256,
2745 Algorithms: data.HashAlgorithms,
2746 Value: keyValBytes,
2747 }
2748 err = r.AddVerificationKey("root", publicData)
2749 c.Assert(err, IsNil)
2750
2751 c.Assert(r.Sign("root.json"), ErrorMatches, "tuf: error unmarshalling key: invalid PEM value")
2752 }
2753
View as plain text