diff --git a/repo.go b/repo.go index e4992fe3..7064782a 100644 --- a/repo.go +++ b/repo.go @@ -1280,6 +1280,11 @@ func (r *Repo) SnapshotWithExpires(expires time.Time) error { return err } + // Verify root metadata before verifying signatures on role metadata. + if err := r.verifySignatures("root.json"); err != nil { + return err + } + for _, metaName := range r.snapshotMetadata() { if err := r.verifySignatures(metaName); err != nil { return err diff --git a/repo_test.go b/repo_test.go index 089cf8f6..4f27b368 100644 --- a/repo_test.go +++ b/repo_test.go @@ -2595,3 +2595,39 @@ func (rs *RepoSuite) TestOfflineFlow(c *C) { c.Assert(err, IsNil) } } + +// Regression test: Snapshotting an invalid root should fail. +func (rs *RepoSuite) TestSnapshotWithInvalidRoot(c *C) { + files := map[string][]byte{"foo.txt": []byte("foo")} + local := MemoryStore(make(map[string]json.RawMessage), files) + r, err := NewRepo(local) + c.Assert(err, IsNil) + + // Init should create targets.json, but not signed yet + r.Init(false) + + genKey(c, r, "root") + genKey(c, r, "targets") + genKey(c, r, "snapshot") + genKey(c, r, "timestamp") + c.Assert(r.AddTarget("foo.txt", nil), IsNil) + + // Clear the root signature so that signature verification fails. + s, err := r.SignedMeta("root.json") + c.Assert(err, IsNil) + c.Assert(s.Signatures, HasLen, 1) + s.Signatures[0].Signature = data.HexBytes{} + b, err := r.jsonMarshal(s) + c.Assert(err, IsNil) + r.meta["root.json"] = b + local.SetMeta("root.json", b) + + // Snapshotting should fail. + c.Assert(r.Snapshot(), Equals, ErrInsufficientSignatures{"root.json", verify.ErrInvalid}) + + // Correctly sign root + c.Assert(r.Sign("root.json"), IsNil) + c.Assert(r.Snapshot(), IsNil) + c.Assert(r.Timestamp(), IsNil) + c.Assert(r.Commit(), IsNil) +}