diff --git a/client/client.go b/client/client.go index fab3ca2667..0920f734a9 100644 --- a/client/client.go +++ b/client/client.go @@ -660,7 +660,7 @@ func (r *NotaryRepository) bootstrapRepo() error { } return err } - if err := b.Load(role, jsonBytes, 0, true); err != nil { + if err := b.Load(role, jsonBytes, 1, true); err != nil { return err } } @@ -769,7 +769,7 @@ func (r *NotaryRepository) Update(forWrite bool) error { // Returns a tufclient.Client for the remote server, which may not be actually // operational (if the URL is invalid but a root.json is cached). func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*tufclient.Client, error) { - minVersion := 0 + minVersion := 1 oldBuilder := tuf.NewRepoBuilder(r.gun, r.CryptoService, r.trustPinning) var newBuilder tuf.RepoBuilder diff --git a/server/handlers/validation.go b/server/handlers/validation.go index 3d4c71a6b3..4affe3ae6a 100644 --- a/server/handlers/validation.go +++ b/server/handlers/validation.go @@ -44,7 +44,7 @@ func validateUpdate(cs signed.CryptoService, gun string, updates []storage.MetaU if rootUpdate, ok := roles[data.CanonicalRootRole]; ok { builder = builder.BootstrapNewBuilder() - if err := builder.Load(data.CanonicalRootRole, rootUpdate.Data, 0, false); err != nil { + if err := builder.Load(data.CanonicalRootRole, rootUpdate.Data, 1, false); err != nil { return nil, validation.ErrBadRoot{Msg: err.Error()} } @@ -67,7 +67,7 @@ func validateUpdate(cs signed.CryptoService, gun string, updates []storage.MetaU // At this point, root and targets must have been loaded into the repo if snapshotUpdate, ok := roles[data.CanonicalSnapshotRole]; ok { - if err := builder.Load(data.CanonicalSnapshotRole, snapshotUpdate.Data, 0, false); err != nil { + if err := builder.Load(data.CanonicalSnapshotRole, snapshotUpdate.Data, 1, false); err != nil { return nil, validation.ErrBadSnapshot{Msg: err.Error()} } logrus.Debug("Successfully validated snapshot") @@ -131,7 +131,7 @@ func loadAndValidateTargets(gun string, builder tuf.RepoBuilder, roles map[strin } } - if err := builder.Load(roleName, roles[roleName].Data, 0, false); err != nil { + if err := builder.Load(roleName, roles[roleName].Data, 1, false); err != nil { logrus.Error("ErrBadTargets: ", err.Error()) return nil, validation.ErrBadTargets{Msg: err.Error()} } @@ -223,7 +223,7 @@ func loadFromStore(gun, roleName string, builder tuf.RepoBuilder, store storage. if err != nil { return err } - if err := builder.Load(roleName, metaJSON, 0, true); err != nil { + if err := builder.Load(roleName, metaJSON, 1, true); err != nil { return err } return nil diff --git a/server/snapshot/snapshot.go b/server/snapshot/snapshot.go index 80649de4d1..aff5858224 100644 --- a/server/snapshot/snapshot.go +++ b/server/snapshot/snapshot.go @@ -76,7 +76,7 @@ func GetOrCreateSnapshot(gun, checksum string, store storage.MetaStore, cryptoSe logrus.Debug("Previous snapshot, but no root for GUN ", gun) return nil, nil, err } - if err := builder.Load(data.CanonicalRootRole, rootJSON, 0, false); err != nil { + if err := builder.Load(data.CanonicalRootRole, rootJSON, 1, false); err != nil { logrus.Debug("Could not load valid previous root for GUN ", gun) return nil, nil, err } diff --git a/server/timestamp/timestamp.go b/server/timestamp/timestamp.go index dd4d846dfd..183e2c7f89 100644 --- a/server/timestamp/timestamp.go +++ b/server/timestamp/timestamp.go @@ -144,13 +144,13 @@ func createTimestamp(gun string, prev *data.SignedTimestamp, snapshot []byte, st logrus.Debug("Previous timestamp, but no root for GUN ", gun) return nil, err } - if err := builder.Load(data.CanonicalRootRole, root, 0, false); err != nil { + if err := builder.Load(data.CanonicalRootRole, root, 1, false); err != nil { logrus.Debug("Could not load valid previous root for GUN ", gun) return nil, err } // load snapshot so we can include it in timestamp - if err := builder.Load(data.CanonicalSnapshotRole, snapshot, 0, false); err != nil { + if err := builder.Load(data.CanonicalSnapshotRole, snapshot, 1, false); err != nil { logrus.Debug("Could not load valid previous snapshot for GUN ", gun) return nil, err } diff --git a/trustpinning/certs_test.go b/trustpinning/certs_test.go index 4cbf9567e2..ab9c05d544 100644 --- a/trustpinning/certs_test.go +++ b/trustpinning/certs_test.go @@ -467,6 +467,7 @@ func TestValidateRootWithPinnedCA(t *testing.T) { data.CanonicalSnapshotRole: &rootRole.RootRole}, false, ) + testRoot.Signed.Version = 1 require.NoError(t, err, "Failed to create new root") keyReader, err := os.Open("../fixtures/notary-signer.key") @@ -581,6 +582,7 @@ func testValidateSuccessfulRootRotation(t *testing.T, keyAlg, rootKeyType string }, false, ) + origTestRoot.Signed.Version = 1 require.NoError(t, err, "Failed to create new root") signedOrigTestRoot, err := origTestRoot.ToSigned() @@ -607,6 +609,7 @@ func testValidateSuccessfulRootRotation(t *testing.T, keyAlg, rootKeyType string data.CanonicalSnapshotRole: &rootRole.RootRole}, false, ) + testRoot.Signed.Version = 1 require.NoError(t, err, "Failed to create new root") signedTestRoot, err := testRoot.ToSigned() @@ -659,6 +662,7 @@ func testValidateRootRotationMissingOrigSig(t *testing.T, keyAlg, rootKeyType st }, false, ) + origTestRoot.Signed.Version = 1 require.NoError(t, err, "Failed to create new root") signedOrigTestRoot, err := origTestRoot.ToSigned() @@ -734,6 +738,7 @@ func testValidateRootRotationMissingNewSig(t *testing.T, keyAlg, rootKeyType str }, false, ) + origTestRoot.Signed.Version = 1 require.NoError(t, err, "Failed to create new root") signedOrigTestRoot, err := origTestRoot.ToSigned() diff --git a/tuf/builder.go b/tuf/builder.go index 111223a276..050619a46a 100644 --- a/tuf/builder.go +++ b/tuf/builder.go @@ -166,7 +166,8 @@ func (rb *repoBuilder) IsLoaded(roleName string) bool { } } -// GetLoadedVersion returns the metadata version, if it is loaded, or 0 otherwise +// GetLoadedVersion returns the metadata version, if it is loaded, or 1 (the +// minimum valid version number) otherwise func (rb *repoBuilder) GetLoadedVersion(roleName string) int { switch { case roleName == data.CanonicalRootRole && rb.repo.Root != nil: @@ -181,7 +182,7 @@ func (rb *repoBuilder) GetLoadedVersion(roleName string) int { } } - return 0 + return 1 } // GetConsistentInfo returns the consistent name and size of a role, if it is known, diff --git a/tuf/builder_test.go b/tuf/builder_test.go index 01bfe623fb..28bee42962 100644 --- a/tuf/builder_test.go +++ b/tuf/builder_test.go @@ -40,7 +40,7 @@ func getSampleMeta(t *testing.T) (map[string][]byte, string) { func TestBuilderLoadsValidRolesOnly(t *testing.T) { meta, gun := getSampleMeta(t) builder := tuf.NewRepoBuilder(gun, nil, trustpinning.TrustPinConfig{}) - err := builder.Load("NotRoot", meta[data.CanonicalRootRole], 0, false) + err := builder.Load("NotRoot", meta[data.CanonicalRootRole], 1, false) require.Error(t, err) require.IsType(t, tuf.ErrInvalidBuilderInput{}, err) require.Contains(t, err.Error(), "is an invalid role") @@ -52,17 +52,17 @@ func TestBuilderOnlyAcceptsRootFirstWhenLoading(t *testing.T) { for roleName, content := range meta { if roleName != data.CanonicalRootRole { - err := builder.Load(roleName, content, 0, true) + err := builder.Load(roleName, content, 1, true) require.Error(t, err) require.IsType(t, tuf.ErrInvalidBuilderInput{}, err) require.Contains(t, err.Error(), "root must be loaded first") require.False(t, builder.IsLoaded(roleName)) - require.Equal(t, 0, builder.GetLoadedVersion(roleName)) + require.Equal(t, 1, builder.GetLoadedVersion(roleName)) } } // we can load the root - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) require.True(t, builder.IsLoaded(data.CanonicalRootRole)) } @@ -71,31 +71,31 @@ func TestBuilderOnlyAcceptsDelegationsAfterParent(t *testing.T) { builder := tuf.NewRepoBuilder(gun, nil, trustpinning.TrustPinConfig{}) // load the root - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) // delegations can't be loaded without target for _, delgName := range []string{"targets/a", "targets/a/b"} { - err := builder.Load(delgName, meta[delgName], 0, false) + err := builder.Load(delgName, meta[delgName], 1, false) require.Error(t, err) require.IsType(t, tuf.ErrInvalidBuilderInput{}, err) require.Contains(t, err.Error(), "targets must be loaded first") require.False(t, builder.IsLoaded(delgName)) - require.Equal(t, 0, builder.GetLoadedVersion(delgName)) + require.Equal(t, 1, builder.GetLoadedVersion(delgName)) } // load the targets - require.NoError(t, builder.Load(data.CanonicalTargetsRole, meta[data.CanonicalTargetsRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalTargetsRole, meta[data.CanonicalTargetsRole], 1, false)) // targets/a/b can't be loaded because targets/a isn't loaded - err := builder.Load("targets/a/b", meta["targets/a/b"], 0, false) + err := builder.Load("targets/a/b", meta["targets/a/b"], 1, false) require.Error(t, err) require.IsType(t, data.ErrInvalidRole{}, err) // targets/a can be loaded now though because targets is loaded - require.NoError(t, builder.Load("targets/a", meta["targets/a"], 0, false)) + require.NoError(t, builder.Load("targets/a", meta["targets/a"], 1, false)) // and now targets/a/b can be loaded because targets/a is loaded - require.NoError(t, builder.Load("targets/a/b", meta["targets/a/b"], 0, false)) + require.NoError(t, builder.Load("targets/a/b", meta["targets/a/b"], 1, false)) } func TestBuilderAcceptRoleOnce(t *testing.T) { @@ -104,12 +104,12 @@ func TestBuilderAcceptRoleOnce(t *testing.T) { for _, roleName := range append(data.BaseRoles, "targets/a", "targets/a/b") { // first time loading is ok - require.NoError(t, builder.Load(roleName, meta[roleName], 0, false)) + require.NoError(t, builder.Load(roleName, meta[roleName], 1, false)) require.True(t, builder.IsLoaded(roleName)) require.Equal(t, 1, builder.GetLoadedVersion(roleName)) // second time loading is not - err := builder.Load(roleName, meta[roleName], 0, false) + err := builder.Load(roleName, meta[roleName], 1, false) require.Error(t, err) require.IsType(t, tuf.ErrInvalidBuilderInput{}, err) require.Contains(t, err.Error(), "has already been loaded") @@ -124,14 +124,14 @@ func TestBuilderStopsAcceptingOrProducingDataOnceDone(t *testing.T) { builder := tuf.NewRepoBuilder(gun, nil, trustpinning.TrustPinConfig{}) for _, roleName := range data.BaseRoles { - require.NoError(t, builder.Load(roleName, meta[roleName], 0, false)) + require.NoError(t, builder.Load(roleName, meta[roleName], 1, false)) require.True(t, builder.IsLoaded(roleName)) } _, err := builder.Finish() require.NoError(t, err) - err = builder.Load("targets/a", meta["targets/a"], 0, false) + err = builder.Load("targets/a", meta["targets/a"], 1, false) require.Error(t, err) require.Equal(t, tuf.ErrBuildDone, err) @@ -200,7 +200,7 @@ func TestGenerateSnapshotInvalidOperations(t *testing.T) { // --- we can't generate a snapshot if the targets isn't loaded and we have no previous snapshot, // --- but if we have a previous snapshot with a valid targets, we're good even if no snapshot // --- is loaded - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) _, _, err = builder.GenerateSnapshot(prevSnapshot) if prevSnapshot == nil { require.IsType(t, tuf.ErrInvalidBuilderInput{}, err) @@ -212,11 +212,11 @@ func TestGenerateSnapshotInvalidOperations(t *testing.T) { // --- we can't generate a snapshot if we've loaded the timestamp already builder = tuf.NewRepoBuilder(gun, newCS, trustpinning.TrustPinConfig{}) - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) if prevSnapshot == nil { - require.NoError(t, builder.Load(data.CanonicalTargetsRole, meta[data.CanonicalTargetsRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalTargetsRole, meta[data.CanonicalTargetsRole], 1, false)) } - require.NoError(t, builder.Load(data.CanonicalTimestampRole, meta[data.CanonicalTimestampRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalTimestampRole, meta[data.CanonicalTimestampRole], 1, false)) _, _, err = builder.GenerateSnapshot(prevSnapshot) require.IsType(t, tuf.ErrInvalidBuilderInput{}, err) @@ -225,11 +225,11 @@ func TestGenerateSnapshotInvalidOperations(t *testing.T) { // --- we cannot generate a snapshot if we've already loaded a snapshot builder = tuf.NewRepoBuilder(gun, newCS, trustpinning.TrustPinConfig{}) - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) if prevSnapshot == nil { - require.NoError(t, builder.Load(data.CanonicalTargetsRole, meta[data.CanonicalTargetsRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalTargetsRole, meta[data.CanonicalTargetsRole], 1, false)) } - require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 1, false)) _, _, err = builder.GenerateSnapshot(prevSnapshot) require.IsType(t, tuf.ErrInvalidBuilderInput{}, err) @@ -239,9 +239,9 @@ func TestGenerateSnapshotInvalidOperations(t *testing.T) { for i := 0; i < len(snapKeys); i++ { require.NoError(t, newCS.RemoveKey(snapKeys[i].ID())) builder = tuf.NewRepoBuilder(gun, newCS, trustpinning.TrustPinConfig{}) - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) if prevSnapshot == nil { - require.NoError(t, builder.Load(data.CanonicalTargetsRole, meta[data.CanonicalTargetsRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalTargetsRole, meta[data.CanonicalTargetsRole], 1, false)) } _, _, err = builder.GenerateSnapshot(prevSnapshot) @@ -251,9 +251,9 @@ func TestGenerateSnapshotInvalidOperations(t *testing.T) { // --- we cannot generate a snapshot if we don't have a cryptoservice builder = tuf.NewRepoBuilder(gun, nil, trustpinning.TrustPinConfig{}) - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) if prevSnapshot == nil { - require.NoError(t, builder.Load(data.CanonicalTargetsRole, meta[data.CanonicalTargetsRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalTargetsRole, meta[data.CanonicalTargetsRole], 1, false)) } _, _, err = builder.GenerateSnapshot(prevSnapshot) @@ -265,8 +265,8 @@ func TestGenerateSnapshotInvalidOperations(t *testing.T) { // --- we can't generate a snapshot if we're given an invalid previous snapshot (for instance, an empty one), // --- even if we have a targets loaded builder := tuf.NewRepoBuilder(gun, cs, trustpinning.TrustPinConfig{}) - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) - require.NoError(t, builder.Load(data.CanonicalTargetsRole, meta[data.CanonicalTargetsRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) + require.NoError(t, builder.Load(data.CanonicalTargetsRole, meta[data.CanonicalTargetsRole], 1, false)) _, _, err = builder.GenerateSnapshot(&data.SignedSnapshot{}) require.IsType(t, data.ErrInvalidMetadata{}, err) @@ -302,7 +302,7 @@ func TestGenerateTimestampInvalidOperations(t *testing.T) { // --- we can't generate a timestamp if the snapshot isn't loaded, no matter if we have a previous // --- timestamp or not - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) _, _, err = builder.GenerateTimestamp(prevTimestamp) require.IsType(t, tuf.ErrInvalidBuilderInput{}, err) require.Contains(t, err.Error(), "snapshot must be loaded first") @@ -310,9 +310,9 @@ func TestGenerateTimestampInvalidOperations(t *testing.T) { // --- we can't generate a timestamp if we've loaded the timestamp already builder = tuf.NewRepoBuilder(gun, cs, trustpinning.TrustPinConfig{}) - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) - require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 0, false)) - require.NoError(t, builder.Load(data.CanonicalTimestampRole, meta[data.CanonicalTimestampRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) + require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 1, false)) + require.NoError(t, builder.Load(data.CanonicalTimestampRole, meta[data.CanonicalTimestampRole], 1, false)) _, _, err = builder.GenerateTimestamp(prevTimestamp) require.IsType(t, tuf.ErrInvalidBuilderInput{}, err) @@ -322,8 +322,8 @@ func TestGenerateTimestampInvalidOperations(t *testing.T) { for i := 0; i < len(tsKeys); i++ { require.NoError(t, cs.RemoveKey(tsKeys[i].ID())) builder = tuf.NewRepoBuilder(gun, cs, trustpinning.TrustPinConfig{}) - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) - require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) + require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 1, false)) _, _, err = builder.GenerateTimestamp(prevTimestamp) require.IsType(t, signed.ErrInsufficientSignatures{}, err) @@ -332,8 +332,8 @@ func TestGenerateTimestampInvalidOperations(t *testing.T) { // --- we cannot generate a timestamp if we don't have a cryptoservice builder = tuf.NewRepoBuilder(gun, nil, trustpinning.TrustPinConfig{}) - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) - require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) + require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 1, false)) _, _, err = builder.GenerateTimestamp(prevTimestamp) require.IsType(t, tuf.ErrInvalidBuilderInput{}, err) @@ -344,8 +344,8 @@ func TestGenerateTimestampInvalidOperations(t *testing.T) { // --- we can't generate a timsetamp if we're given an invalid previous timestamp (for instance, an empty one), // --- even if we have a snapshot loaded builder := tuf.NewRepoBuilder(gun, cs, trustpinning.TrustPinConfig{}) - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) - require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) + require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 1, false)) _, _, err = builder.GenerateTimestamp(&data.SignedTimestamp{}) require.IsType(t, data.ErrInvalidMetadata{}, err) @@ -369,11 +369,11 @@ func TestGetConsistentInfo(t *testing.T) { meta, err := testutils.SignAndSerialize(repo) require.NoError(t, err) - builder := tuf.NewRepoBuilder(nil, gun, nil, trustpinning.TrustPinConfig{}) + builder := tuf.NewRepoBuilder(gun, nil, trustpinning.TrustPinConfig{}) // if neither snapshot nor timestamp are loaded, no matter how much other data is loaded, consistent info // is empty except for timestamp: timestamps have no checksums, and the length is always -1 for _, roleToLoad := range []string{data.CanonicalRootRole, data.CanonicalTargetsRole} { - require.NoError(t, builder.Load(roleToLoad, meta[roleToLoad], 0, false)) + require.NoError(t, builder.Load(roleToLoad, meta[roleToLoad], 1, false)) for _, checkName := range append(data.BaseRoles, extraMeta...) { ci := builder.GetConsistentInfo(checkName) require.Equal(t, checkName, ci.ConsistentName()) @@ -391,7 +391,7 @@ func TestGetConsistentInfo(t *testing.T) { } // once timestamp is loaded, we can get the consistent info for snapshot but nothing else - require.NoError(t, builder.Load(data.CanonicalTimestampRole, meta[data.CanonicalTimestampRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalTimestampRole, meta[data.CanonicalTimestampRole], 1, false)) for _, checkName := range append(data.BaseRoles, extraMeta...) { ci := builder.GetConsistentInfo(checkName) @@ -416,7 +416,7 @@ func TestGetConsistentInfo(t *testing.T) { } // once the snapshot is loaded, we can get real consistent info for all loaded roles - require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 1, false)) for _, checkName := range data.BaseRoles { ci := builder.GetConsistentInfo(checkName) require.True(t, ci.ChecksumKnown(), "%s's checksum is not known", checkName) @@ -508,35 +508,35 @@ func TestTimestampPreAndPostChecksumming(t *testing.T) { snapJSON := append(meta[data.CanonicalSnapshotRole], ' ') // --- load timestamp first - builder := tuf.NewRepoBuilder(nil, gun, nil, trustpinning.TrustPinConfig{}) - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) + builder := tuf.NewRepoBuilder(gun, nil, trustpinning.TrustPinConfig{}) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) // timestamp doesn't fail, even though its checksum for root is wrong according to timestamp - require.NoError(t, builder.Load(data.CanonicalTimestampRole, meta[data.CanonicalTimestampRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalTimestampRole, meta[data.CanonicalTimestampRole], 1, false)) // loading the snapshot in fails, because of the checksum the timestamp has - err = builder.Load(data.CanonicalSnapshotRole, snapJSON, 0, false) + err = builder.Load(data.CanonicalSnapshotRole, snapJSON, 1, false) require.Error(t, err) require.IsType(t, data.ErrMismatchedChecksum{}, err) require.True(t, builder.IsLoaded(data.CanonicalTimestampRole)) require.False(t, builder.IsLoaded(data.CanonicalSnapshotRole)) // all the other metadata can be loaded in, even though the checksums are wrong according to timestamp for _, roleName := range []string{data.CanonicalTargetsRole, "targets/other"} { - require.NoError(t, builder.Load(roleName, meta[roleName], 0, false)) + require.NoError(t, builder.Load(roleName, meta[roleName], 1, false)) } // --- load snapshot first - builder = tuf.NewRepoBuilder(nil, gun, nil, trustpinning.TrustPinConfig{}) + builder = tuf.NewRepoBuilder(gun, nil, trustpinning.TrustPinConfig{}) for _, roleName := range append(data.BaseRoles, "targets/other") { switch roleName { case data.CanonicalTimestampRole: continue case data.CanonicalSnapshotRole: - require.NoError(t, builder.Load(roleName, snapJSON, 0, false)) + require.NoError(t, builder.Load(roleName, snapJSON, 1, false)) default: - require.NoError(t, builder.Load(roleName, meta[roleName], 0, false)) + require.NoError(t, builder.Load(roleName, meta[roleName], 1, false)) } } // timestamp fails because the snapshot checksum is wrong - err = builder.Load(data.CanonicalTimestampRole, meta[data.CanonicalTimestampRole], 0, false) + err = builder.Load(data.CanonicalTimestampRole, meta[data.CanonicalTimestampRole], 1, false) require.Error(t, err) checksumErr, ok := err.(data.ErrMismatchedChecksum) require.True(t, ok) @@ -587,13 +587,13 @@ func TestSnapshotLoadedFirstChecksumsOthers(t *testing.T) { gun := "docker.com/notary" meta := setupSnapshotChecksumming(t, gun) // --- load root then snapshot - builder := tuf.NewRepoBuilder(nil, gun, nil, trustpinning.TrustPinConfig{}) - require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 0, false)) - require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 0, false)) + builder := tuf.NewRepoBuilder(gun, nil, trustpinning.TrustPinConfig{}) + require.NoError(t, builder.Load(data.CanonicalRootRole, meta[data.CanonicalRootRole], 1, false)) + require.NoError(t, builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 1, false)) // loading timestamp is fine, even though the timestamp metadata has the wrong checksum because // we don't check timestamp checksums - require.NoError(t, builder.Load(data.CanonicalTimestampRole, meta[data.CanonicalTimestampRole], 0, false)) + require.NoError(t, builder.Load(data.CanonicalTimestampRole, meta[data.CanonicalTimestampRole], 1, false)) // loading the other roles' metadata with a space will fail because of a checksum failure (builder // checks right away if the snapshot is loaded) - in the case of targets/other/other, which should @@ -608,10 +608,10 @@ func TestSnapshotLoadedFirstChecksumsOthers(t *testing.T) { require.False(t, builder.IsLoaded(roleNameToLoad)) // now load it for real (since we need targets loaded before trying to load "targets/other") - require.NoError(t, builder.Load(roleNameToLoad, meta[roleNameToLoad], 0, false)) + require.NoError(t, builder.Load(roleNameToLoad, meta[roleNameToLoad], 1, false)) } // loading the non-existent role wil fail - err := builder.Load("targets/other/other", meta["targets/other/other"], 0, false) + err := builder.Load("targets/other/other", meta["targets/other/other"], 1, false) require.Error(t, err) require.IsType(t, data.ErrMissingMeta{}, err) require.False(t, builder.IsLoaded("targets/other/other")) @@ -627,7 +627,7 @@ func TestSnapshotLoadedAfterChecksumsOthersRetroactively(t *testing.T) { // --- load all the other metadata first, but with an extra space at the end which should // --- validate fine, except for the checksum. for _, roleNameToPermute := range append(data.BaseRoles, "targets/other") { - builder := tuf.NewRepoBuilder(nil, gun, nil, trustpinning.TrustPinConfig{}) + builder := tuf.NewRepoBuilder(gun, nil, trustpinning.TrustPinConfig{}) if roleNameToPermute == data.CanonicalSnapshotRole { continue } @@ -641,12 +641,12 @@ func TestSnapshotLoadedAfterChecksumsOthersRetroactively(t *testing.T) { // having a space added at the end should not affect any validity check except checksum require.NoError(t, builder.Load(roleNameToLoad, append(meta[roleNameToLoad], ' '), 0, false)) default: - require.NoError(t, builder.Load(roleNameToLoad, meta[roleNameToLoad], 0, false)) + require.NoError(t, builder.Load(roleNameToLoad, meta[roleNameToLoad], 1, false)) } require.True(t, builder.IsLoaded(roleNameToLoad)) } // now load the snapshot - it should fail with the checksum failure for the permuted role - err := builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 0, false) + err := builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 1, false) switch roleNameToPermute { case data.CanonicalTimestampRole: require.NoError(t, err) // we don't check the timestamp's checksum @@ -662,14 +662,14 @@ func TestSnapshotLoadedAfterChecksumsOthersRetroactively(t *testing.T) { // load all the metadata as is without alteration (so they should validate all checksums) // but also load the metadata that is not contained in the snapshot. Then when the snapshot // is loaded it will fail validation, because it doesn't have target/other/other's checksum - builder := tuf.NewRepoBuilder(nil, gun, nil, trustpinning.TrustPinConfig{}) + builder := tuf.NewRepoBuilder(gun, nil, trustpinning.TrustPinConfig{}) for _, roleNameToLoad := range append(data.BaseRoles, "targets/other", "targets/other/other") { if roleNameToLoad == data.CanonicalSnapshotRole { continue } - require.NoError(t, builder.Load(roleNameToLoad, meta[roleNameToLoad], 0, false)) + require.NoError(t, builder.Load(roleNameToLoad, meta[roleNameToLoad], 1, false)) } - err := builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 0, false) + err := builder.Load(data.CanonicalSnapshotRole, meta[data.CanonicalSnapshotRole], 1, false) require.Error(t, err) require.IsType(t, data.ErrMissingMeta{}, err) } diff --git a/tuf/client/client.go b/tuf/client/client.go index 2012e56315..90ab698f43 100644 --- a/tuf/client/client.go +++ b/tuf/client/client.go @@ -118,7 +118,7 @@ func (c *Client) downloadTimestamp() error { logrus.Debug(remoteErr.Error()) logrus.Warn("Error while downloading remote metadata, using cached timestamp - this might not be the latest version available remotely") - err := c.newBuilder.Load(role, cachedTS, 0, false) + err := c.newBuilder.Load(role, cachedTS, 1, false) if err == nil { logrus.Debug("successfully verified cached timestamp") } @@ -194,7 +194,7 @@ func (c *Client) tryLoadCacheThenRemote(consistentInfo tuf.ConsistentInfo) ([]by return c.tryLoadRemote(consistentInfo, nil) } - if err = c.newBuilder.Load(consistentInfo.RoleName, cachedTS, 0, false); err == nil { + if err = c.newBuilder.Load(consistentInfo.RoleName, cachedTS, 1, false); err == nil { logrus.Debugf("successfully verified cached %s", consistentInfo.RoleName) return cachedTS, nil } @@ -213,8 +213,8 @@ func (c *Client) tryLoadRemote(consistentInfo tuf.ConsistentInfo, old []byte) ([ // try to load the old data into the old builder - only use it to validate // versions if it loads successfully. If it errors, then the loaded version - // will be 0 - c.oldBuilder.Load(consistentInfo.RoleName, old, 0, true) + // will be 1 + c.oldBuilder.Load(consistentInfo.RoleName, old, 1, true) minVersion := c.oldBuilder.GetLoadedVersion(consistentInfo.RoleName) if err := c.newBuilder.Load(consistentInfo.RoleName, raw, minVersion, false); err != nil { diff --git a/tuf/data/root.go b/tuf/data/root.go index 75f0c1c9c6..cfadbdbfb1 100644 --- a/tuf/data/root.go +++ b/tuf/data/root.go @@ -31,9 +31,9 @@ func isValidRootStructure(r Root) error { role: CanonicalRootRole, msg: fmt.Sprintf("expected type %s, not %s", expectedType, r.Type)} } - if r.Version < 0 { + if r.Version < 1 { return ErrInvalidMetadata{ - role: CanonicalRootRole, msg: "version cannot be negative"} + role: CanonicalRootRole, msg: "version cannot be less than 1"} } // all the base roles MUST appear in the root.json - other roles are allowed, diff --git a/tuf/data/root_test.go b/tuf/data/root_test.go index d00f1dd255..59a58b6d49 100644 --- a/tuf/data/root_test.go +++ b/tuf/data/root_test.go @@ -225,4 +225,12 @@ func TestRootFromSignedValidatesVersion(t *testing.T) { root.Signed.Version = -1 _, err := rootToSignedAndBack(t, root) require.IsType(t, ErrInvalidMetadata{}, err) + + root.Signed.Version = 0 + _, err = rootToSignedAndBack(t, root) + require.IsType(t, ErrInvalidMetadata{}, err) + + root.Signed.Version = 1 + _, err = rootToSignedAndBack(t, root) + require.NoError(t, err) } diff --git a/tuf/data/snapshot.go b/tuf/data/snapshot.go index 682eed2903..1d1178e4a8 100644 --- a/tuf/data/snapshot.go +++ b/tuf/data/snapshot.go @@ -32,9 +32,9 @@ func IsValidSnapshotStructure(s Snapshot) error { role: CanonicalSnapshotRole, msg: fmt.Sprintf("expected type %s, not %s", expectedType, s.Type)} } - if s.Version < 0 { + if s.Version < 1 { return ErrInvalidMetadata{ - role: CanonicalSnapshotRole, msg: "version cannot be negative"} + role: CanonicalSnapshotRole, msg: "version cannot be less than one"} } for _, role := range []string{CanonicalRootRole, CanonicalTargetsRole} { diff --git a/tuf/data/snapshot_test.go b/tuf/data/snapshot_test.go index 2b2b23e2a3..5dbbe26c62 100644 --- a/tuf/data/snapshot_test.go +++ b/tuf/data/snapshot_test.go @@ -200,6 +200,14 @@ func TestSnapshotFromSignedValidatesVersion(t *testing.T) { sn.Signed.Version = -1 _, err := snapshotToSignedAndBack(t, sn) require.IsType(t, ErrInvalidMetadata{}, err) + + sn.Signed.Version = 0 + _, err = snapshotToSignedAndBack(t, sn) + require.IsType(t, ErrInvalidMetadata{}, err) + + sn.Signed.Version = 1 + _, err = snapshotToSignedAndBack(t, sn) + require.NoError(t, err) } // GetMeta returns the checksum, or an error if it is missing. diff --git a/tuf/data/targets.go b/tuf/data/targets.go index a73c8b6283..336e46c161 100644 --- a/tuf/data/targets.go +++ b/tuf/data/targets.go @@ -38,8 +38,8 @@ func isValidTargetsStructure(t Targets, roleName string) error { role: roleName, msg: fmt.Sprintf("expected type %s, not %s", expectedType, t.Type)} } - if t.Version < 0 { - return ErrInvalidMetadata{role: roleName, msg: "version cannot be negative"} + if t.Version < 1 { + return ErrInvalidMetadata{role: roleName, msg: "version cannot be less than one"} } for _, roleObj := range t.Delegations.Roles { diff --git a/tuf/data/targets_test.go b/tuf/data/targets_test.go index 868089a203..edddb84aeb 100644 --- a/tuf/data/targets_test.go +++ b/tuf/data/targets_test.go @@ -236,4 +236,16 @@ func TestTargetsFromSignedValidatesVersion(t *testing.T) { require.NoError(t, err) _, err = TargetsFromSigned(s, "targets/a") require.IsType(t, ErrInvalidMetadata{}, err) + + tg.Signed.Version = 0 + s, err = tg.ToSigned() + require.NoError(t, err) + _, err = TargetsFromSigned(s, "targets/a") + require.IsType(t, ErrInvalidMetadata{}, err) + + tg.Signed.Version = 1 + s, err = tg.ToSigned() + require.NoError(t, err) + _, err = TargetsFromSigned(s, "targets/a") + require.NoError(t, err) } diff --git a/tuf/data/timestamp.go b/tuf/data/timestamp.go index cb7b0daef4..1a64241561 100644 --- a/tuf/data/timestamp.go +++ b/tuf/data/timestamp.go @@ -31,9 +31,9 @@ func IsValidTimestampStructure(t Timestamp) error { role: CanonicalTimestampRole, msg: fmt.Sprintf("expected type %s, not %s", expectedType, t.Type)} } - if t.Version < 0 { + if t.Version < 1 { return ErrInvalidMetadata{ - role: CanonicalTimestampRole, msg: "version cannot be negative"} + role: CanonicalTimestampRole, msg: "version cannot be less than one"} } // Meta is a map of FileMeta, so if the role isn't in the map it returns diff --git a/tuf/data/timestamp_test.go b/tuf/data/timestamp_test.go index 207f2a74a7..5bb1f69eda 100644 --- a/tuf/data/timestamp_test.go +++ b/tuf/data/timestamp_test.go @@ -200,6 +200,14 @@ func TestTimestampFromSignedValidatesVersion(t *testing.T) { ts.Signed.Version = -1 _, err := timestampToSignedAndBack(t, ts) require.IsType(t, ErrInvalidMetadata{}, err) + + ts.Signed.Version = 0 + _, err = timestampToSignedAndBack(t, ts) + require.IsType(t, ErrInvalidMetadata{}, err) + + ts.Signed.Version = 1 + _, err = timestampToSignedAndBack(t, ts) + require.NoError(t, err) } // GetSnapshot returns the snapshot checksum, or an error if it is missing.