func (m *memoryStore) WalkStagedTargets(paths []string, targetsFn targetsWalkFunc) error { if len(paths) == 0 { for path, dat := range m.files { meta, err := data.NewFileMeta(bytes.NewReader(dat), "sha256") if err != nil { return err } if err = targetsFn(path, meta); err != nil { return err } } return nil } for _, path := range paths { dat, ok := m.files[path] if !ok { return ErrMetaNotFound{Resource: path} } meta, err := data.NewFileMeta(bytes.NewReader(dat), "sha256") if err != nil { return err } if err = targetsFn(path, meta); err != nil { return err } } return nil }
func TestGetSnapshotCurrValid(t *testing.T) { store := storage.NewMemStorage() crypto := signed.NewEd25519() _, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key) newData := []byte{2} currMeta, err := data.NewFileMeta(bytes.NewReader(newData), "sha256") assert.NoError(t, err) snapshot := &data.SignedSnapshot{ Signed: data.Snapshot{ Expires: data.DefaultExpires(data.CanonicalSnapshotRole), Meta: data.Files{ data.CanonicalRootRole: currMeta, }, }, } snapJSON, _ := json.Marshal(snapshot) // test when db is missing the role data store.UpdateCurrent("gun", storage.MetaUpdate{Role: "snapshot", Version: 0, Data: snapJSON}) _, err = GetOrCreateSnapshot("gun", store, crypto) assert.NoError(t, err) // test when db has the role data store.UpdateCurrent("gun", storage.MetaUpdate{Role: "root", Version: 0, Data: newData}) _, err = GetOrCreateSnapshot("gun", store, crypto) assert.NoError(t, err) // test when db role data is expired store.UpdateCurrent("gun", storage.MetaUpdate{Role: "root", Version: 1, Data: []byte{3}}) _, err = GetOrCreateSnapshot("gun", store, crypto) assert.NoError(t, err) }
// Creates metadata in the following manner: // - the snapshot has bad checksums for itself and for timestamp, to show that those aren't checked // - snapshot has valid checksums for root, targets, and targets/other // - snapshot doesn't have a checksum for targets/other/other, but targets/other/other is a valid // delegation role in targets/other and there is metadata for targets/other/other that is correctly // signed func setupSnapshotChecksumming(t *testing.T, gun string) map[string][]byte { repo, _, err := testutils.EmptyRepo(gun, "targets/other", "targets/other/other") require.NoError(t, err) // add invalid checkums for all the other roles to timestamp too, and show that // cached items aren't checksummed against this fakeChecksum, err := data.NewFileMeta(bytes.NewBuffer([]byte("fake")), notary.SHA256, notary.SHA512) require.NoError(t, err) // fake the snapshot and timestamp checksums repo.Snapshot.Signed.Meta[data.CanonicalSnapshotRole] = fakeChecksum repo.Snapshot.Signed.Meta[data.CanonicalTimestampRole] = fakeChecksum meta, err := testutils.SignAndSerialize(repo) require.NoError(t, err) // ensure that the fake metadata for other roles wasn't destroyed by signing require.Len(t, repo.Snapshot.Signed.Meta, 5) // create delegation metadata that should not be in snapshot, but has a valid role and signature _, err = repo.InitTargets("targets/other/other") require.NoError(t, err) s, err := repo.SignTargets("targets/other/other", data.DefaultExpires(data.CanonicalTargetsRole)) require.NoError(t, err) meta["targets/other/other"], err = json.Marshal(s) require.NoError(t, err) return meta }
// No matter what order timestamp and snapshot is loaded, if the snapshot's checksum doesn't match // what's in the timestamp, the builder will error and refuse to load the latest piece of metadata // whether that is snapshot (because it was loaded after timestamp) or timestamp (because builder // retroactive checks the loaded snapshot's checksum). Timestamp ONLY checks the snapshot checksum. func TestTimestampPreAndPostChecksumming(t *testing.T) { gun := "docker.com/notary" repo, _, err := testutils.EmptyRepo(gun, "targets/other", "targets/other/other") require.NoError(t, err) // add invalid checkums for all the other roles to timestamp too, and show that // cached items aren't checksummed against this fakeChecksum, err := data.NewFileMeta(bytes.NewBuffer([]byte("fake")), notary.SHA256, notary.SHA512) require.NoError(t, err) for _, roleName := range append(data.BaseRoles, "targets/other") { // add a wrong checksum for every role, including timestamp itself repo.Timestamp.Signed.Meta[roleName] = fakeChecksum } // this will overwrite the snapshot checksum with the right one meta, err := testutils.SignAndSerialize(repo) require.NoError(t, err) // ensure that the fake meta for other roles weren't destroyed by signing the timestamp require.Len(t, repo.Timestamp.Signed.Meta, 5) snapJSON := append(meta[data.CanonicalSnapshotRole], ' ') // --- load timestamp first 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], 1, false)) // loading the snapshot in fails, because of the checksum the timestamp has 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], 1, false)) } // --- load snapshot first 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, 1, false)) default: 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], 1, false) require.Error(t, err) checksumErr, ok := err.(data.ErrMismatchedChecksum) require.True(t, ok) require.Contains(t, checksumErr.Error(), "checksum for snapshot did not match") require.False(t, builder.IsLoaded(data.CanonicalTimestampRole)) require.True(t, builder.IsLoaded(data.CanonicalSnapshotRole)) }
func snapshotExpired(ts *data.SignedTimestamp, snapshot []byte) bool { meta, err := data.NewFileMeta(bytes.NewReader(snapshot), "sha256") if err != nil { // if we can't generate FileMeta from the current snapshot, we should // continue to serve the old timestamp if it isn't time expired // because we won't be able to generate a new one. return false } hash := meta.Hashes["sha256"] return !bytes.Equal(hash, ts.Signed.Meta["snapshot"].Hashes["sha256"]) }
// UpdateTimestamp updates the snapshot meta in the timestamp based on the Signed object func (tr *Repo) UpdateTimestamp(s *data.Signed) error { jsonData, err := json.Marshal(s) if err != nil { return err } meta, err := data.NewFileMeta(bytes.NewReader(jsonData), data.NotaryDefaultHashes...) if err != nil { return err } tr.Timestamp.Signed.Meta[data.CanonicalSnapshotRole] = meta tr.Timestamp.Dirty = true return nil }
// UpdateSnapshot updates the FileMeta for the given role based on the Signed object func (tr *Repo) UpdateSnapshot(role string, s *data.Signed) error { jsonData, err := json.Marshal(s) if err != nil { return err } meta, err := data.NewFileMeta(bytes.NewReader(jsonData), data.NotaryDefaultHashes...) if err != nil { return err } tr.Snapshot.Signed.Meta[role] = meta tr.Snapshot.Dirty = true return nil }
// NewTarget is a helper method that returns a Target func NewTarget(targetName string, targetPath string) (*Target, error) { b, err := ioutil.ReadFile(targetPath) if err != nil { return nil, err } meta, err := data.NewFileMeta(bytes.NewBuffer(b)) if err != nil { return nil, err } return &Target{Name: targetName, Hashes: meta.Hashes, Length: meta.Length}, nil }
// UpdateTimestamp updates the snapshot meta in the timestamp based on the Signed object func (tr *Repo) UpdateTimestamp(s *data.Signed) error { jsonData, err := json.MarshalCanonical(s) if err != nil { return err } meta, err := data.NewFileMeta(bytes.NewReader(jsonData), "sha256") if err != nil { return err } tr.Timestamp.Signed.Meta["snapshot"] = meta tr.Timestamp.Dirty = true return nil }
func TestBuilderLoadInvalidDelegations(t *testing.T) { gun := "docker.com/notary" tufRepo, _, err := testutils.EmptyRepo(gun, "targets/a", "targets/a/b", "targets/b") require.NoError(t, err) meta, err := testutils.SignAndSerialize(tufRepo) require.NoError(t, err) builder := tuf.NewBuilderFromRepo(gun, tufRepo, trustpinning.TrustPinConfig{}) // modify targets/a to remove the signature and update the snapshot // (we're not going to load the timestamp so no need to modify) targetsAJSON := meta["targets/a"] targetsA := data.Signed{} err = json.Unmarshal(targetsAJSON, &targetsA) require.NoError(t, err) targetsA.Signatures = make([]data.Signature, 0) targetsAJSON, err = json.Marshal(&targetsA) require.NoError(t, err) meta["targets/a"] = targetsAJSON delete(tufRepo.Targets, "targets/a") snap := tufRepo.Snapshot m, err := data.NewFileMeta( bytes.NewReader(targetsAJSON), "sha256", "sha512", ) require.NoError(t, err) snap.AddMeta("targets/a", m) // load snapshot directly into repo to bypass signature check (we've invalidated // the signature by modifying it) tufRepo.Snapshot = snap // load targets/a require.Error( t, builder.Load( "targets/a", meta["targets/a"], 1, false, ), ) _, invalid, err := builder.Finish() require.NoError(t, err) _, ok := invalid.Targets["targets/a"] require.True(t, ok) }
// UpdateSnapshotHashes updates the snapshot to reflect the latest hash changes, to // ensure that failure isn't because the snapshot has the wrong hash. func (m *MetadataSwizzler) UpdateSnapshotHashes(roles ...string) error { var ( metaBytes []byte snapshotSigned *data.Signed err error ) if metaBytes, err = m.MetadataCache.GetSized(data.CanonicalSnapshotRole, store.NoSizeLimit); err != nil { return err } snapshot := data.SignedSnapshot{} if err = json.Unmarshal(metaBytes, &snapshot); err != nil { return err } // just rebuild everything if roles is not specified if len(roles) == 0 { roles = m.Roles } for _, role := range roles { if role != data.CanonicalSnapshotRole && role != data.CanonicalTimestampRole { if metaBytes, err = m.MetadataCache.GetSized(role, store.NoSizeLimit); err != nil { return err } meta, err := data.NewFileMeta(bytes.NewReader(metaBytes), data.NotaryDefaultHashes...) if err != nil { return err } snapshot.Signed.Meta[role] = meta } } if snapshotSigned, err = snapshot.ToSigned(); err != nil { return err } pubKeys, err := getPubKeys(m.CryptoService, snapshotSigned, data.CanonicalSnapshotRole) if err == nil { metaBytes, err = serializeMetadata(m.CryptoService, snapshotSigned, data.CanonicalSnapshotRole, pubKeys...) } if err != nil { return err } return m.MetadataCache.Set(data.CanonicalSnapshotRole, metaBytes) }
// UpdateTimestampHash updates the timestamp to reflect the latest snapshot changes, to // ensure that failure isn't because the timestamp has the wrong hash. func (m *MetadataSwizzler) UpdateTimestampHash() error { var ( metaBytes []byte timestamp = &data.SignedTimestamp{} timestampSigned *data.Signed err error ) if metaBytes, err = m.MetadataCache.GetSized(data.CanonicalTimestampRole, store.NoSizeLimit); err != nil { return err } // we can't just create a new timestamp, because then the expiry would be // different if err = json.Unmarshal(metaBytes, timestamp); err != nil { return err } if metaBytes, err = m.MetadataCache.GetSized(data.CanonicalSnapshotRole, store.NoSizeLimit); err != nil { return err } snapshotMeta, err := data.NewFileMeta(bytes.NewReader(metaBytes), data.NotaryDefaultHashes...) if err != nil { return err } timestamp.Signed.Meta[data.CanonicalSnapshotRole] = snapshotMeta timestampSigned, err = timestamp.ToSigned() if err != nil { return err } pubKeys, err := getPubKeys(m.CryptoService, timestampSigned, data.CanonicalTimestampRole) if err == nil { metaBytes, err = serializeMetadata(m.CryptoService, timestampSigned, data.CanonicalTimestampRole, pubKeys...) } if err != nil { return err } return m.MetadataCache.Set(data.CanonicalTimestampRole, metaBytes) }