@@ -12,39 +12,71 @@ import (
12
12
13
13
"github.com/theupdateframework/go-tuf/data"
14
14
"github.com/theupdateframework/go-tuf/encrypted"
15
+ "github.com/theupdateframework/go-tuf/internal/sets"
15
16
"github.com/theupdateframework/go-tuf/pkg/keys"
16
17
"github.com/theupdateframework/go-tuf/util"
17
18
)
18
19
19
- func signers (privateKeys []* data.PrivateKey ) []keys.Signer {
20
- res := make ([]keys.Signer , 0 , len (privateKeys ))
21
- for _ , k := range privateKeys {
22
- signer , err := keys .GetSigner (k )
23
- if err != nil {
24
- continue
25
- }
26
- res = append (res , signer )
27
- }
28
- return res
20
+ type LocalStore interface {
21
+ // GetMeta returns a map from metadata file names (e.g. root.json) to their raw JSON payload or an error.
22
+ GetMeta () (map [string ]json.RawMessage , error )
23
+
24
+ // SetMeta is used to update a metadata file name with a JSON payload.
25
+ SetMeta (name string , meta json.RawMessage ) error
26
+
27
+ // WalkStagedTargets calls targetsFn for each staged target file in paths.
28
+ // If paths is empty, all staged target files will be walked.
29
+ WalkStagedTargets (paths []string , targetsFn TargetsWalkFunc ) error
30
+
31
+ // FileIsStaged determines if a metadata file is currently staged, to avoid incrementing
32
+ // version numbers repeatedly while staged.
33
+ FileIsStaged (filename string ) bool
34
+
35
+ // Commit is used to publish staged files to the repository
36
+ //
37
+ // This will also reset the staged meta to signal incrementing version numbers.
38
+ // TUF 1.0 requires that the root metadata version numbers in the repository does not
39
+ // gaps. To avoid this, we will only increment the number once until we commit.
40
+ Commit (bool , map [string ]int , map [string ]data.Hashes ) error
41
+
42
+ // GetSigners return a list of signers for a role.
43
+ GetSigners (role string ) ([]keys.Signer , error )
44
+
45
+ // SaveSigner adds a signer to a role.
46
+ SaveSigner (role string , signer keys.Signer ) error
47
+
48
+ // SignersForRole return a list of signing keys for a role.
49
+ SignersForKeyIDs (keyIDs []string ) []keys.Signer
50
+
51
+ // Clean is used to remove all staged manifests.
52
+ Clean () error
53
+ }
54
+
55
+ type PassphraseChanger interface {
56
+ // ChangePassphrase changes the passphrase for a role keys file.
57
+ ChangePassphrase (string ) error
29
58
}
30
59
31
60
func MemoryStore (meta map [string ]json.RawMessage , files map [string ][]byte ) LocalStore {
32
61
if meta == nil {
33
62
meta = make (map [string ]json.RawMessage )
34
63
}
35
64
return & memoryStore {
36
- meta : meta ,
37
- stagedMeta : make (map [string ]json.RawMessage ),
38
- files : files ,
39
- signers : make (map [string ][]keys.Signer ),
65
+ meta : meta ,
66
+ stagedMeta : make (map [string ]json.RawMessage ),
67
+ files : files ,
68
+ signerForKeyID : make (map [string ]keys.Signer ),
69
+ keyIDsForRole : make (map [string ][]string ),
40
70
}
41
71
}
42
72
43
73
type memoryStore struct {
44
74
meta map [string ]json.RawMessage
45
75
stagedMeta map [string ]json.RawMessage
46
76
files map [string ][]byte
47
- signers map [string ][]keys.Signer
77
+
78
+ signerForKeyID map [string ]keys.Signer
79
+ keyIDsForRole map [string ][]string
48
80
}
49
81
50
82
func (m * memoryStore ) GetMeta () (map [string ]json.RawMessage , error ) {
@@ -105,14 +137,53 @@ func (m *memoryStore) Commit(consistentSnapshot bool, versions map[string]int, h
105
137
}
106
138
107
139
func (m * memoryStore ) GetSigners (role string ) ([]keys.Signer , error ) {
108
- return m .signers [role ], nil
140
+ keyIDs , ok := m .keyIDsForRole [role ]
141
+ if ok {
142
+ return m .SignersForKeyIDs (keyIDs ), nil
143
+ }
144
+
145
+ return nil , nil
109
146
}
110
147
111
148
func (m * memoryStore ) SaveSigner (role string , signer keys.Signer ) error {
112
- m .signers [role ] = append (m .signers [role ], signer )
149
+ keyIDs := signer .PublicData ().IDs ()
150
+
151
+ for _ , keyID := range keyIDs {
152
+ m .signerForKeyID [keyID ] = signer
153
+ }
154
+
155
+ mergedKeyIDs := sets .DeduplicateStrings (append (m .keyIDsForRole [role ], keyIDs ... ))
156
+ m .keyIDsForRole [role ] = mergedKeyIDs
113
157
return nil
114
158
}
115
159
160
+ func (m * memoryStore ) SignersForKeyIDs (keyIDs []string ) []keys.Signer {
161
+ signers := []keys.Signer {}
162
+ keyIDsSeen := map [string ]struct {}{}
163
+
164
+ for _ , keyID := range keyIDs {
165
+ signer , ok := m .signerForKeyID [keyID ]
166
+ if ! ok {
167
+ continue
168
+ }
169
+ addSigner := false
170
+
171
+ for _ , skid := range signer .PublicData ().IDs () {
172
+ if _ , seen := keyIDsSeen [skid ]; ! seen {
173
+ addSigner = true
174
+ }
175
+
176
+ keyIDsSeen [skid ] = struct {}{}
177
+ }
178
+
179
+ if addSigner {
180
+ signers = append (signers , signer )
181
+ }
182
+ }
183
+
184
+ return signers
185
+ }
186
+
116
187
func (m * memoryStore ) Clean () error {
117
188
return nil
118
189
}
@@ -126,16 +197,17 @@ func FileSystemStore(dir string, p util.PassphraseFunc) LocalStore {
126
197
return & fileSystemStore {
127
198
dir : dir ,
128
199
passphraseFunc : p ,
129
- signers : make (map [string ][]keys.Signer ),
200
+ signerForKeyID : make (map [string ]keys.Signer ),
201
+ keyIDsForRole : make (map [string ][]string ),
130
202
}
131
203
}
132
204
133
205
type fileSystemStore struct {
134
206
dir string
135
207
passphraseFunc util.PassphraseFunc
136
208
137
- // signers is a cache of persisted keys to avoid decrypting multiple times
138
- signers map [string ][]keys. Signer
209
+ signerForKeyID map [ string ] keys. Signer
210
+ keyIDsForRole map [string ][]string
139
211
}
140
212
141
213
func (f * fileSystemStore ) repoDir () string {
@@ -333,18 +405,63 @@ func (f *fileSystemStore) Commit(consistentSnapshot bool, versions map[string]in
333
405
}
334
406
335
407
func (f * fileSystemStore ) GetSigners (role string ) ([]keys.Signer , error ) {
336
- if keys , ok := f .signers [role ]; ok {
337
- return keys , nil
408
+ keyIDs , ok := f .keyIDsForRole [role ]
409
+ if ok {
410
+ return f .SignersForKeyIDs (keyIDs ), nil
338
411
}
339
- keys , _ , err := f .loadPrivateKeys (role )
412
+
413
+ privKeys , _ , err := f .loadPrivateKeys (role )
340
414
if err != nil {
341
415
if os .IsNotExist (err ) {
342
416
return nil , nil
343
417
}
344
418
return nil , err
345
419
}
346
- f .signers [role ] = signers (keys )
347
- return f .signers [role ], nil
420
+
421
+ signers := []keys.Signer {}
422
+ for _ , key := range privKeys {
423
+ signer , err := keys .GetSigner (key )
424
+ if err != nil {
425
+ return nil , err
426
+ }
427
+
428
+ // Cache the signers.
429
+ for _ , keyID := range signer .PublicData ().IDs () {
430
+ f .keyIDsForRole [role ] = append (f .keyIDsForRole [role ], keyID )
431
+ f .signerForKeyID [keyID ] = signer
432
+ }
433
+ signers = append (signers , signer )
434
+ }
435
+
436
+ return signers , nil
437
+ }
438
+
439
+ func (f * fileSystemStore ) SignersForKeyIDs (keyIDs []string ) []keys.Signer {
440
+ signers := []keys.Signer {}
441
+ keyIDsSeen := map [string ]struct {}{}
442
+
443
+ for _ , keyID := range keyIDs {
444
+ signer , ok := f .signerForKeyID [keyID ]
445
+ if ! ok {
446
+ continue
447
+ }
448
+
449
+ addSigner := false
450
+
451
+ for _ , skid := range signer .PublicData ().IDs () {
452
+ if _ , seen := keyIDsSeen [skid ]; ! seen {
453
+ addSigner = true
454
+ }
455
+
456
+ keyIDsSeen [skid ] = struct {}{}
457
+ }
458
+
459
+ if addSigner {
460
+ signers = append (signers , signer )
461
+ }
462
+ }
463
+
464
+ return signers
348
465
}
349
466
350
467
// ChangePassphrase changes the passphrase for a role keys file. Implements
@@ -391,15 +508,15 @@ func (f *fileSystemStore) SaveSigner(role string, signer keys.Signer) error {
391
508
}
392
509
393
510
// add the key to the existing keys (if any)
394
- keys , pass , err := f .loadPrivateKeys (role )
511
+ privKeys , pass , err := f .loadPrivateKeys (role )
395
512
if err != nil && ! os .IsNotExist (err ) {
396
513
return err
397
514
}
398
515
key , err := signer .MarshalPrivateKey ()
399
516
if err != nil {
400
517
return err
401
518
}
402
- keys = append (keys , key )
519
+ privKeys = append (privKeys , key )
403
520
404
521
// if loadPrivateKeys didn't return a passphrase (because no keys yet exist)
405
522
// and passphraseFunc is set, get the passphrase so the keys file can
@@ -414,13 +531,13 @@ func (f *fileSystemStore) SaveSigner(role string, signer keys.Signer) error {
414
531
415
532
pk := & persistedKeys {}
416
533
if pass != nil {
417
- pk .Data , err = encrypted .Marshal (keys , pass )
534
+ pk .Data , err = encrypted .Marshal (privKeys , pass )
418
535
if err != nil {
419
536
return err
420
537
}
421
538
pk .Encrypted = true
422
539
} else {
423
- pk .Data , err = json .MarshalIndent (keys , "" , "\t " )
540
+ pk .Data , err = json .MarshalIndent (privKeys , "" , "\t " )
424
541
if err != nil {
425
542
return err
426
543
}
@@ -432,7 +549,26 @@ func (f *fileSystemStore) SaveSigner(role string, signer keys.Signer) error {
432
549
if err := util .AtomicallyWriteFile (f .keysPath (role ), append (data , '\n' ), 0600 ); err != nil {
433
550
return err
434
551
}
435
- f .signers [role ] = append (f .signers [role ], signer )
552
+
553
+ innerKeyIdsForRole := f .keyIDsForRole [role ]
554
+
555
+ for _ , key := range privKeys {
556
+ signer , err := keys .GetSigner (key )
557
+ if err != nil {
558
+ return err
559
+ }
560
+
561
+ keyIDs := signer .PublicData ().IDs ()
562
+
563
+ for _ , keyID := range keyIDs {
564
+ f .signerForKeyID [keyID ] = signer
565
+ }
566
+
567
+ innerKeyIdsForRole = append (innerKeyIdsForRole , keyIDs ... )
568
+ }
569
+
570
+ f .keyIDsForRole [role ] = sets .DeduplicateStrings (innerKeyIdsForRole )
571
+
436
572
return nil
437
573
}
438
574
0 commit comments