Skip to content

Commit 344f4ee

Browse files
[Delegations prereq] Use a verify.DB for delegation in client
Splitting up #175
1 parent 314e8de commit 344f4ee

File tree

5 files changed

+102
-80
lines changed

5 files changed

+102
-80
lines changed

client/delegations.go

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ func (c *Client) getTargetFileMeta(target string) (data.TargetFileMeta, error) {
2020
// - filter delegations with paths or path_hash_prefixes matching searched target
2121
// - 5.6.7.1 cycles protection
2222
// - 5.6.7.2 terminations
23-
delegations := targets.NewDelegationsIterator(target)
23+
delegations := targets.NewDelegationsIterator(target, c.db)
2424
for i := 0; i < c.MaxDelegations; i++ {
2525
d, ok := delegations.Next()
2626
if !ok {
2727
return data.TargetFileMeta{}, ErrUnknownTarget{target, snapshot.Version}
2828
}
2929

3030
// covers 5.6.{1,2,3,4,5,6}
31-
targets, err := c.loadDelegatedTargets(snapshot, d.Delegatee.Name, d.Verifier)
31+
targets, err := c.loadDelegatedTargets(snapshot, d.Delegatee.Name, d.DB)
3232
if err != nil {
3333
return data.TargetFileMeta{}, err
3434
}
@@ -39,11 +39,11 @@ func (c *Client) getTargetFileMeta(target string) (data.TargetFileMeta, error) {
3939
}
4040

4141
if targets.Delegations != nil {
42-
delegationsVerifier, err := verify.NewDelegationsVerifier(targets.Delegations)
42+
delegationsDB, err := verify.NewDBFromDelegations(targets.Delegations)
4343
if err != nil {
4444
return data.TargetFileMeta{}, err
4545
}
46-
err = delegations.Add(targets.Delegations.Roles, d.Delegatee.Name, delegationsVerifier)
46+
err = delegations.Add(targets.Delegations.Roles, d.Delegatee.Name, delegationsDB)
4747
if err != nil {
4848
return data.TargetFileMeta{}, err
4949
}
@@ -75,7 +75,7 @@ func (c *Client) loadLocalSnapshot() (*data.Snapshot, error) {
7575
}
7676

7777
// loadDelegatedTargets downloads, decodes, verifies and stores targets
78-
func (c *Client) loadDelegatedTargets(snapshot *data.Snapshot, role string, verifier verify.DelegationsVerifier) (*data.Targets, error) {
78+
func (c *Client) loadDelegatedTargets(snapshot *data.Snapshot, role string, db *verify.DB) (*data.Targets, error) {
7979
var err error
8080
fileName := role + ".json"
8181
fileMeta, ok := snapshot.Meta[fileName]
@@ -98,11 +98,7 @@ func (c *Client) loadDelegatedTargets(snapshot *data.Snapshot, role string, veri
9898
// 5.6.3 verify signature with parent public keys
9999
// 5.6.5 verify that the targets is not expired
100100
// role "targets" is a top role verified by root keys loaded in the client db
101-
if role == "targets" {
102-
err = c.db.Unmarshal(raw, targets, role, fileMeta.Version)
103-
} else {
104-
err = verifier.Unmarshal(raw, targets, role, fileMeta.Version)
105-
}
101+
err = db.Unmarshal(raw, targets, role, fileMeta.Version)
106102
if err != nil {
107103
return nil, ErrDecodeFailed{fileName, err}
108104
}

internal/targets/delegation.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ package targets
22

33
import (
44
"github.com/theupdateframework/go-tuf/data"
5+
"github.com/theupdateframework/go-tuf/internal/sets"
56
"github.com/theupdateframework/go-tuf/verify"
67
)
78

89
type Delegation struct {
910
Delegator string
10-
Verifier verify.DelegationsVerifier
1111
Delegatee data.DelegatedRole
12+
DB *verify.DB
1213
}
1314

1415
type delegationsIterator struct {
@@ -18,13 +19,23 @@ type delegationsIterator struct {
1819
}
1920

2021
// NewDelegationsIterator initialises an iterator with a first step
21-
// on top level targets
22-
func NewDelegationsIterator(target string) *delegationsIterator {
22+
// on top level targets.
23+
func NewDelegationsIterator(target string, topLevelKeysDB *verify.DB) *delegationsIterator {
24+
role := topLevelKeysDB.GetRole("targets")
25+
keyIDs := []string{}
26+
if role != nil {
27+
keyIDs = sets.StringSetToSlice(role.KeyIDs)
28+
}
29+
2330
i := &delegationsIterator{
2431
target: target,
2532
stack: []Delegation{
2633
{
27-
Delegatee: data.DelegatedRole{Name: "targets"},
34+
Delegatee: data.DelegatedRole{
35+
Name: "targets",
36+
KeyIDs: keyIDs,
37+
},
38+
DB: topLevelKeysDB,
2839
},
2940
},
3041
visitedRoles: make(map[string]struct{}),
@@ -57,7 +68,7 @@ func (d *delegationsIterator) Next() (value Delegation, ok bool) {
5768
return delegation, true
5869
}
5970

60-
func (d *delegationsIterator) Add(roles []data.DelegatedRole, delegator string, verifier verify.DelegationsVerifier) error {
71+
func (d *delegationsIterator) Add(roles []data.DelegatedRole, delegator string, db *verify.DB) error {
6172
for i := len(roles) - 1; i >= 0; i-- {
6273
// Push the roles onto the stack in reverse so we get an preorder traversal
6374
// of the delegations graph.
@@ -70,7 +81,7 @@ func (d *delegationsIterator) Add(roles []data.DelegatedRole, delegator string,
7081
delegation := Delegation{
7182
Delegator: delegator,
7283
Delegatee: r,
73-
Verifier: verifier,
84+
DB: db,
7485
}
7586
d.stack = append(d.stack, delegation)
7687
}

internal/targets/delegation_test.go

Lines changed: 66 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ var (
1414
)
1515

1616
func TestDelegationsIterator(t *testing.T) {
17+
defaultKeyIDs := []string{"26b878ad73362774b8b69dd4fdeb2cc6a2688e4133ed5ace9e18a06e9d998a6d"}
1718
var iteratorTests = []struct {
1819
testName string
1920
roles map[string][]data.DelegatedRole
@@ -25,23 +26,23 @@ func TestDelegationsIterator(t *testing.T) {
2526
testName: "no termination",
2627
roles: map[string][]data.DelegatedRole{
2728
"targets": {
28-
{Name: "b", Paths: defaultPathPatterns},
29-
{Name: "e", Paths: defaultPathPatterns},
29+
{Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
30+
{Name: "e", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
3031
},
3132
"b": {
32-
{Name: "c", Paths: defaultPathPatterns},
33+
{Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
3334
},
3435
"c": {
35-
{Name: "d", Paths: defaultPathPatterns},
36+
{Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
3637
},
3738
"e": {
38-
{Name: "f", Paths: defaultPathPatterns},
39-
{Name: "g", Paths: defaultPathPatterns},
39+
{Name: "f", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
40+
{Name: "g", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
4041
},
4142
"g": {
42-
{Name: "h", Paths: defaultPathPatterns},
43-
{Name: "i", Paths: defaultPathPatterns},
44-
{Name: "j", Paths: defaultPathPatterns},
43+
{Name: "h", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
44+
{Name: "i", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
45+
{Name: "j", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
4546
},
4647
},
4748
file: "",
@@ -51,12 +52,12 @@ func TestDelegationsIterator(t *testing.T) {
5152
testName: "terminated in b",
5253
roles: map[string][]data.DelegatedRole{
5354
"targets": {
54-
{Name: "b", Paths: defaultPathPatterns, Terminating: true},
55-
{Name: "e", Paths: defaultPathPatterns},
55+
{Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs, Terminating: true},
56+
{Name: "e", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
5657
},
5758
"b": {
58-
{Name: "c", Paths: defaultPathPatterns},
59-
{Name: "d", Paths: defaultPathPatterns},
59+
{Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
60+
{Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
6061
},
6162
},
6263
file: "",
@@ -66,12 +67,12 @@ func TestDelegationsIterator(t *testing.T) {
6667
testName: "path does not match b",
6768
roles: map[string][]data.DelegatedRole{
6869
"targets": {
69-
{Name: "b", Paths: noMatchPathPatterns},
70-
{Name: "e", Paths: defaultPathPatterns},
70+
{Name: "b", Paths: noMatchPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
71+
{Name: "e", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
7172
},
7273
"b": {
73-
{Name: "c", Paths: defaultPathPatterns},
74-
{Name: "d", Paths: defaultPathPatterns},
74+
{Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
75+
{Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
7576
},
7677
},
7778
file: "",
@@ -81,12 +82,13 @@ func TestDelegationsIterator(t *testing.T) {
8182
testName: "path does not match b - path prefixes",
8283
roles: map[string][]data.DelegatedRole{
8384
"targets": {
84-
{Name: "b", PathHashPrefixes: []string{"33472a4909"}},
85-
{Name: "c", PathHashPrefixes: []string{"34c85d1ee84f61f10d7dc633"}},
85+
{Name: "b", PathHashPrefixes: []string{"33472a4909"}, Threshold: 1, KeyIDs: defaultKeyIDs},
86+
{Name: "c", PathHashPrefixes: []string{"34c85d1ee84f61f10d7dc633"}, Threshold: 1, KeyIDs: defaultKeyIDs},
8687
},
8788
"c": {
88-
{Name: "d", PathHashPrefixes: []string{"8baf"}},
89-
{Name: "e", PathHashPrefixes: []string{"34c85d1ee84f61f10d7dc633472a49096ed87f8f764bd597831eac371f40ac39"}},
89+
90+
{Name: "d", PathHashPrefixes: []string{"8baf"}, Threshold: 1, KeyIDs: defaultKeyIDs},
91+
{Name: "e", PathHashPrefixes: []string{"34c85d1ee84f61f10d7dc633472a49096ed87f8f764bd597831eac371f40ac39"}, Threshold: 1, KeyIDs: defaultKeyIDs},
9092
},
9193
},
9294
file: "/e/f/g.txt",
@@ -96,7 +98,7 @@ func TestDelegationsIterator(t *testing.T) {
9698
testName: "err paths and pathHashPrefixes are set",
9799
roles: map[string][]data.DelegatedRole{
98100
"targets": {
99-
{Name: "b", Paths: defaultPathPatterns, PathHashPrefixes: defaultPathPatterns},
101+
{Name: "b", Paths: defaultPathPatterns, PathHashPrefixes: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
100102
},
101103
"b": {},
102104
},
@@ -108,48 +110,54 @@ func TestDelegationsIterator(t *testing.T) {
108110
testName: "cycle avoided 1",
109111
roles: map[string][]data.DelegatedRole{
110112
"targets": {
111-
{Name: "b", Paths: defaultPathPatterns},
112-
{Name: "e", Paths: defaultPathPatterns},
113+
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
114+
},
115+
"a": {
116+
{Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
117+
{Name: "e", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
113118
},
114119
"b": {
115-
{Name: "targets", Paths: defaultPathPatterns},
116-
{Name: "d", Paths: defaultPathPatterns},
120+
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
121+
{Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
117122
},
118123
},
119124
file: "",
120-
resultOrder: []string{"targets", "b", "d", "e"},
125+
resultOrder: []string{"targets", "a", "b", "d", "e"},
121126
},
122127
{
123128
testName: "cycle avoided 2",
124129
roles: map[string][]data.DelegatedRole{
125130
"targets": {
126-
{Name: "targets", Paths: defaultPathPatterns},
127-
{Name: "b", Paths: defaultPathPatterns},
131+
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
132+
},
133+
"a": {
134+
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
135+
{Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
128136
},
129137
"b": {
130-
{Name: "targets", Paths: defaultPathPatterns},
131-
{Name: "b", Paths: defaultPathPatterns},
132-
{Name: "c", Paths: defaultPathPatterns},
138+
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
139+
{Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
140+
{Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
133141
},
134142
"c": {
135-
{Name: "c", Paths: defaultPathPatterns},
143+
{Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
136144
},
137145
},
138146
file: "",
139-
resultOrder: []string{"targets", "b", "c"},
147+
resultOrder: []string{"targets", "a", "b", "c"},
140148
},
141149
{
142150
testName: "diamond delegation",
143151
roles: map[string][]data.DelegatedRole{
144152
"targets": {
145-
{Name: "b", Paths: defaultPathPatterns},
146-
{Name: "c", Paths: defaultPathPatterns},
153+
{Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
154+
{Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
147155
},
148156
"b": {
149-
{Name: "d", Paths: defaultPathPatterns},
157+
{Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
150158
},
151159
"c": {
152-
{Name: "d", Paths: defaultPathPatterns},
160+
{Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
153161
},
154162
},
155163
file: "",
@@ -159,10 +167,10 @@ func TestDelegationsIterator(t *testing.T) {
159167
testName: "simple cycle",
160168
roles: map[string][]data.DelegatedRole{
161169
"targets": {
162-
{Name: "a", Paths: defaultPathPatterns},
170+
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
163171
},
164172
"a": {
165-
{Name: "a", Paths: defaultPathPatterns},
173+
{Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
166174
},
167175
},
168176
file: "",
@@ -172,7 +180,17 @@ func TestDelegationsIterator(t *testing.T) {
172180

173181
for _, tt := range iteratorTests {
174182
t.Run(tt.testName, func(t *testing.T) {
175-
d := NewDelegationsIterator(tt.file)
183+
flattened := []data.DelegatedRole{}
184+
for _, roles := range tt.roles {
185+
flattened = append(flattened, roles...)
186+
}
187+
db, err := verify.NewDBFromDelegations(&data.Delegations{
188+
Roles: flattened,
189+
})
190+
191+
assert.NoError(t, err)
192+
d := NewDelegationsIterator(tt.file, db)
193+
176194
var iterationOrder []string
177195
for {
178196
r, ok := d.Next()
@@ -184,7 +202,13 @@ func TestDelegationsIterator(t *testing.T) {
184202
if !ok {
185203
continue
186204
}
187-
err := d.Add(delegations, r.Delegatee.Name, verify.DelegationsVerifier{})
205+
206+
db, err := verify.NewDBFromDelegations(&data.Delegations{
207+
Roles: delegations,
208+
})
209+
assert.NoError(t, err)
210+
211+
err = d.Add(delegations, r.Delegatee.Name, db)
188212
assert.Equal(t, tt.err, err)
189213
}
190214
assert.Equal(t, tt.resultOrder, iterationOrder)

verify/db.go

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,37 +28,28 @@ func NewDB() *DB {
2828
}
2929
}
3030

31-
type DelegationsVerifier struct {
32-
DB *DB
33-
}
34-
35-
func (d *DelegationsVerifier) Unmarshal(b []byte, v interface{}, role string, minVersion int) error {
36-
return d.DB.Unmarshal(b, v, role, minVersion)
37-
}
38-
39-
// NewDelegationsVerifier returns a DelegationsVerifier that verifies delegations
40-
// of a given Targets. It reuses the DB struct to leverage verified keys, roles
41-
// unmarshals.
42-
func NewDelegationsVerifier(d *data.Delegations) (DelegationsVerifier, error) {
31+
// NewDBFromDelegations returns a DB that verifies delegations
32+
// of a given Targets.
33+
func NewDBFromDelegations(d *data.Delegations) (*DB, error) {
4334
db := &DB{
4435
roles: make(map[string]*Role, len(d.Roles)),
4536
verifiers: make(map[string]keys.Verifier, len(d.Keys)),
4637
}
4738
for _, r := range d.Roles {
4839
if _, ok := roles.TopLevelRoles[r.Name]; ok {
49-
return DelegationsVerifier{}, ErrInvalidDelegatedRole
40+
return nil, ErrInvalidDelegatedRole
5041
}
5142
role := &data.Role{Threshold: r.Threshold, KeyIDs: r.KeyIDs}
5243
if err := db.addRole(r.Name, role); err != nil {
53-
return DelegationsVerifier{}, err
44+
return nil, err
5445
}
5546
}
5647
for id, k := range d.Keys {
5748
if err := db.AddKey(id, k); err != nil {
58-
return DelegationsVerifier{}, err
49+
return nil, err
5950
}
6051
}
61-
return DelegationsVerifier{db}, nil
52+
return db, nil
6253
}
6354

6455
func (db *DB) AddKey(id string, k *data.PublicKey) error {

0 commit comments

Comments
 (0)