Skip to content

Commit 545f98e

Browse files
authored
Add Reason to ErrInvalidKeys (#237)
Leads to better error messages throughout. Also improve repo_test coverage to exercise all of the ErrInvalidKeys paths. Signed-off-by: Zachary Newman <[email protected]>
1 parent 8453bf6 commit 545f98e

File tree

3 files changed

+46
-15
lines changed

3 files changed

+46
-15
lines changed

errors.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,12 @@ func (e ErrInsufficientSignatures) Error() string {
4646
}
4747

4848
type ErrInvalidRole struct {
49-
Role string
49+
Role string
50+
Reason string
5051
}
5152

5253
func (e ErrInvalidRole) Error() string {
53-
return fmt.Sprintf("tuf: invalid role %s", e.Role)
54+
return fmt.Sprintf("tuf: invalid role %s: %s", e.Role, e.Reason)
5455
}
5556

5657
type ErrInvalidExpires struct {

repo.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,18 @@ func (r *Repo) RootVersion() (int, error) {
152152
}
153153

154154
func (r *Repo) GetThreshold(keyRole string) (int, error) {
155+
if !roles.IsTopLevelRole(keyRole) {
156+
// Delegations are not currently supported, so return an error if this is not a
157+
// top-level metadata file.
158+
return -1, ErrInvalidRole{keyRole, "only thresholds for top-level roles supported"}
159+
}
155160
root, err := r.root()
156161
if err != nil {
157162
return -1, err
158163
}
159164
role, ok := root.Roles[keyRole]
160165
if !ok {
161-
return -1, ErrInvalidRole{keyRole}
166+
return -1, ErrInvalidRole{keyRole, "role missing from root metadata"}
162167
}
163168

164169
return role.Threshold, nil
@@ -168,15 +173,15 @@ func (r *Repo) SetThreshold(keyRole string, t int) error {
168173
if !roles.IsTopLevelRole(keyRole) {
169174
// Delegations are not currently supported, so return an error if this is not a
170175
// top-level metadata file.
171-
return ErrInvalidRole{keyRole}
176+
return ErrInvalidRole{keyRole, "only thresholds for top-level roles supported"}
172177
}
173178
root, err := r.root()
174179
if err != nil {
175180
return err
176181
}
177182
role, ok := root.Roles[keyRole]
178183
if !ok {
179-
return ErrInvalidRole{keyRole}
184+
return ErrInvalidRole{keyRole, "role missing from root metadata"}
180185
}
181186
if role.Threshold == t {
182187
// Change was a no-op.
@@ -283,7 +288,7 @@ func (r *Repo) timestamp() (*data.Timestamp, error) {
283288

284289
func (r *Repo) ChangePassphrase(keyRole string) error {
285290
if !roles.IsTopLevelRole(keyRole) {
286-
return ErrInvalidRole{keyRole}
291+
return ErrInvalidRole{keyRole, "only support passphrases for top-level roles"}
287292
}
288293

289294
if p, ok := r.local.(PassphraseChanger); ok {
@@ -316,7 +321,7 @@ func (r *Repo) AddPrivateKey(role string, signer keys.Signer) error {
316321

317322
func (r *Repo) AddPrivateKeyWithExpires(keyRole string, signer keys.Signer, expires time.Time) error {
318323
if !roles.IsTopLevelRole(keyRole) {
319-
return ErrInvalidRole{keyRole}
324+
return ErrInvalidRole{keyRole, "only support adding keys for top-level roles"}
320325
}
321326

322327
if !validExpires(expires) {
@@ -414,7 +419,7 @@ func (r *Repo) RevokeKey(role, id string) error {
414419

415420
func (r *Repo) RevokeKeyWithExpires(keyRole, id string, expires time.Time) error {
416421
if !roles.IsTopLevelRole(keyRole) {
417-
return ErrInvalidRole{keyRole}
422+
return ErrInvalidRole{keyRole, "only revocations for top-level roles supported"}
418423
}
419424

420425
if !validExpires(expires) {
@@ -517,7 +522,7 @@ func (r *Repo) setTopLevelMeta(roleFilename string, meta interface{}) error {
517522
func (r *Repo) Sign(roleFilename string) error {
518523
role := strings.TrimSuffix(roleFilename, ".json")
519524
if !roles.IsTopLevelRole(role) {
520-
return ErrInvalidRole{role}
525+
return ErrInvalidRole{role, "only signing top-level metadata supported"}
521526
}
522527

523528
s, err := r.SignedMeta(roleFilename)
@@ -553,7 +558,7 @@ func (r *Repo) Sign(roleFilename string) error {
553558
func (r *Repo) AddOrUpdateSignature(roleFilename string, signature data.Signature) error {
554559
role := strings.TrimSuffix(roleFilename, ".json")
555560
if !roles.IsTopLevelRole(role) {
556-
return ErrInvalidRole{role}
561+
return ErrInvalidRole{role, "only signing top-level metadata supported"}
557562
}
558563

559564
// Check key ID is in valid for the role.
@@ -563,7 +568,7 @@ func (r *Repo) AddOrUpdateSignature(roleFilename string, signature data.Signatur
563568
}
564569
roleData := db.GetRole(role)
565570
if roleData == nil {
566-
return ErrInvalidRole{role}
571+
return ErrInvalidRole{role, "role missing from top-level keys"}
567572
}
568573
if !roleData.ValidKey(signature.KeyID) {
569574
return verify.ErrInvalidKey

repo_test.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ func (rs *RepoSuite) TestGenKey(c *C) {
184184

185185
// generate a key for an unknown role
186186
_, err = r.GenKey("foo")
187-
c.Assert(err, Equals, ErrInvalidRole{"foo"})
187+
c.Assert(err, Equals, ErrInvalidRole{"foo", "only support adding keys for top-level roles"})
188188

189189
// generate a root key
190190
ids := genKey(c, r, "root")
@@ -346,7 +346,7 @@ func (rs *RepoSuite) TestAddPrivateKey(c *C) {
346346
signer, err := keys.GenerateEd25519Key()
347347
c.Assert(err, IsNil)
348348
err = r.AddPrivateKey("foo", signer)
349-
c.Assert(err, Equals, ErrInvalidRole{"foo"})
349+
c.Assert(err, Equals, ErrInvalidRole{"foo", "only support adding keys for top-level roles"})
350350

351351
// add a root key
352352
ids := addPrivateKey(c, r, "root", signer)
@@ -511,7 +511,7 @@ func (rs *RepoSuite) TestRevokeKey(c *C) {
511511
c.Assert(err, IsNil)
512512

513513
// revoking a key for an unknown role returns ErrInvalidRole
514-
c.Assert(r.RevokeKey("foo", ""), DeepEquals, ErrInvalidRole{"foo"})
514+
c.Assert(r.RevokeKey("foo", ""), DeepEquals, ErrInvalidRole{"foo", "only revocations for top-level roles supported"})
515515

516516
// revoking a key which doesn't exist returns ErrKeyNotFound
517517
c.Assert(r.RevokeKey("root", "nonexistent"), DeepEquals, ErrKeyNotFound{"root", "nonexistent"})
@@ -632,6 +632,8 @@ func (rs *RepoSuite) TestSign(c *C) {
632632
r, err := NewRepo(local)
633633
c.Assert(err, IsNil)
634634

635+
c.Assert(r.Sign("foo.json"), Equals, ErrInvalidRole{"foo", "only signing top-level metadata supported"})
636+
635637
// signing with no keys returns ErrInsufficientKeys
636638
c.Assert(r.Sign("root.json"), Equals, ErrInsufficientKeys{"root.json"})
637639

@@ -676,6 +678,9 @@ func (rs *RepoSuite) TestSign(c *C) {
676678
c.Assert(local.SaveSigner("root", newKey), IsNil)
677679
c.Assert(r.Sign("root.json"), IsNil)
678680
checkSigIDs(append(signer.PublicData().IDs(), newKey.PublicData().IDs()...)...)
681+
682+
// attempt to sign missing metadata
683+
c.Assert(r.Sign("targets.json"), Equals, ErrMissingMetadata{"targets.json"})
679684
}
680685

681686
func (rs *RepoSuite) TestCommit(c *C) {
@@ -1386,6 +1391,12 @@ func (rs *RepoSuite) TestKeyPersistence(c *C) {
13861391
tmp = newTmpDir(c)
13871392
store = FileSystemStore(tmp.path, testPassphraseFunc)
13881393

1394+
// 1.5. Changing passphrase only works for top-level roles.
1395+
r, err := NewRepo(store)
1396+
c.Assert(err, IsNil)
1397+
1398+
c.Assert(r.ChangePassphrase("foo"), DeepEquals, ErrInvalidRole{"foo", "only support passphrases for top-level roles"})
1399+
13891400
// 2. Test changing the passphrase when the keys file does not exist - should FAIL
13901401
c.Assert(store.(PassphraseChanger).ChangePassphrase("root"), NotNil)
13911402

@@ -1598,6 +1609,11 @@ func (rs *RepoSuite) TestThreshold(c *C) {
15981609
r, err := NewRepo(local)
15991610
c.Assert(err, IsNil)
16001611

1612+
_, err = r.GetThreshold("root")
1613+
c.Assert(err, DeepEquals, ErrInvalidRole{"root", "role missing from root metadata"})
1614+
err = r.SetThreshold("root", 2)
1615+
c.Assert(err, DeepEquals, ErrInvalidRole{"root", "role missing from root metadata"})
1616+
16011617
// Add one key to each role
16021618
genKey(c, r, "root")
16031619
genKey(c, r, "targets")
@@ -1607,6 +1623,11 @@ func (rs *RepoSuite) TestThreshold(c *C) {
16071623
c.Assert(err, IsNil)
16081624
c.Assert(t, Equals, 1)
16091625

1626+
_, err = r.GetThreshold("foo")
1627+
c.Assert(err, DeepEquals, ErrInvalidRole{"foo", "only thresholds for top-level roles supported"})
1628+
err = r.SetThreshold("foo", 2)
1629+
c.Assert(err, DeepEquals, ErrInvalidRole{"foo", "only thresholds for top-level roles supported"})
1630+
16101631
// commit the metadata to the store.
16111632
c.Assert(r.AddTargets([]string{}, nil), IsNil)
16121633
c.Assert(r.Snapshot(), IsNil)
@@ -1727,6 +1748,10 @@ func (rs *RepoSuite) TestBadAddOrUpdateSignatures(c *C) {
17271748
// don't use consistent snapshots to make the checks simpler
17281749
c.Assert(r.Init(false), IsNil)
17291750

1751+
c.Assert(r.AddOrUpdateSignature("targets.json", data.Signature{
1752+
KeyID: "foo",
1753+
Signature: nil}), Equals, ErrInvalidRole{"targets", "role missing from top-level keys"})
1754+
17301755
// generate root key offline and add as a verification key
17311756
rootKey, err := keys.GenerateEd25519Key()
17321757
c.Assert(err, IsNil)
@@ -1749,7 +1774,7 @@ func (rs *RepoSuite) TestBadAddOrUpdateSignatures(c *C) {
17491774
for _, id := range rootKey.PublicData().IDs() {
17501775
c.Assert(r.AddOrUpdateSignature("invalid_root.json", data.Signature{
17511776
KeyID: id,
1752-
Signature: rootSig}), Equals, ErrInvalidRole{"invalid_root"})
1777+
Signature: rootSig}), Equals, ErrInvalidRole{"invalid_root", "only signing top-level metadata supported"})
17531778
}
17541779

17551780
// add a root signature with an key ID that is for the targets role

0 commit comments

Comments
 (0)