Ejemplo n.º 1
0
// generateSnapshot generates a new snapshot from the previous one in the store - this assumes all
// the other roles except timestamp have already been set on the repo, and will set the generated
// snapshot on the repo as well
func generateSnapshot(gun string, builder tuf.RepoBuilder, store storage.MetaStore) (*storage.MetaUpdate, error) {
	var prev *data.SignedSnapshot
	_, currentJSON, err := store.GetCurrent(gun, data.CanonicalSnapshotRole)
	if err == nil {
		prev = new(data.SignedSnapshot)
		if err = json.Unmarshal(currentJSON, prev); err != nil {
			logrus.Error("Failed to unmarshal existing snapshot for GUN ", gun)
			return nil, err
		}
	}

	if _, ok := err.(storage.ErrNotFound); !ok && err != nil {
		return nil, err
	}

	meta, ver, err := builder.GenerateSnapshot(prev)

	switch err.(type) {
	case nil:
		return &storage.MetaUpdate{
			Role:    data.CanonicalSnapshotRole,
			Version: ver,
			Data:    meta,
		}, nil
	case signed.ErrInsufficientSignatures, signed.ErrNoKeys, signed.ErrRoleThreshold:
		// If we cannot sign the snapshot, then we don't have keys for the snapshot,
		// and the client should have submitted a snapshot
		return nil, validation.ErrBadHierarchy{
			Missing: data.CanonicalSnapshotRole,
			Msg:     "no snapshot was included in update and server does not hold current snapshot key for repository"}
	default:
		return nil, validation.ErrValidation{Msg: err.Error()}
	}
}
Ejemplo n.º 2
0
func checkOnlySnapshotConsistentAfterTimestamp(t *testing.T, repo *tuf.Repo, meta map[string][]byte, extraMeta []string, builder tuf.RepoBuilder) {
	// 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], 1, false))
	for _, checkName := range append(data.BaseRoles, extraMeta...) {
		ci := builder.GetConsistentInfo(checkName)

		switch checkName {
		case data.CanonicalSnapshotRole:
			cName := utils.ConsistentName(data.CanonicalSnapshotRole,
				repo.Timestamp.Signed.Meta[data.CanonicalSnapshotRole].Hashes[notary.SHA256])
			require.Equal(t, cName, ci.ConsistentName())
			require.True(t, ci.ChecksumKnown())
			require.True(t, ci.Length() > -1)
		case data.CanonicalTimestampRole:
			// timestamp's canonical name is always "timestamp" and its size is always the max
			// timestamp size
			require.Equal(t, data.CanonicalTimestampRole, ci.ConsistentName())
			require.True(t, ci.ChecksumKnown())
			require.Equal(t, notary.MaxTimestampSize, ci.Length())
		default:
			require.Equal(t, checkName, ci.ConsistentName())
			require.False(t, ci.ChecksumKnown())
			require.Equal(t, int64(-1), ci.Length())
		}
	}
}
Ejemplo n.º 3
0
func loadFromStore(gun, roleName string, builder tuf.RepoBuilder, store storage.MetaStore) error {
	_, metaJSON, err := store.GetCurrent(gun, roleName)
	if err != nil {
		return err
	}
	if err := builder.Load(roleName, metaJSON, 1, true); err != nil {
		return err
	}
	return nil
}
Ejemplo n.º 4
0
func loadAndValidateTargets(gun string, builder tuf.RepoBuilder, roles map[string]storage.MetaUpdate, store storage.MetaStore) ([]storage.MetaUpdate, error) {
	targetsRoles := make(utils.RoleList, 0)
	for role := range roles {
		if role == data.CanonicalTargetsRole || data.IsDelegation(role) {
			targetsRoles = append(targetsRoles, role)
		}
	}

	// N.B. RoleList sorts paths with fewer segments first.
	// By sorting, we'll always process shallower targets updates before deeper
	// ones (i.e. we'll load and validate targets before targets/foo). This
	// helps ensure we only load from storage when necessary in a cleaner way.
	sort.Sort(targetsRoles)

	updatesToApply := make([]storage.MetaUpdate, 0, len(targetsRoles))
	for _, roleName := range targetsRoles {
		// don't load parent if current role is "targets",
		// we must load all ancestor roles, starting from `targets` and working down,
		// for delegations to validate the full parent chain
		var parentsToLoad []string
		ancestorRole := roleName
		for ancestorRole != data.CanonicalTargetsRole {
			ancestorRole = path.Dir(ancestorRole)
			if !builder.IsLoaded(ancestorRole) {
				parentsToLoad = append(parentsToLoad, ancestorRole)
			}
		}
		for i := len(parentsToLoad) - 1; i >= 0; i-- {
			if err := loadFromStore(gun, parentsToLoad[i], builder, store); err != nil {
				// if the parent doesn't exist, just keep going - loading the role will eventually fail
				// due to it being an invalid role
				if _, ok := err.(storage.ErrNotFound); !ok {
					return nil, err
				}
			}
		}

		if err := builder.Load(roleName, roles[roleName].Data, 1, false); err != nil {
			logrus.Error("ErrBadTargets: ", err.Error())
			return nil, validation.ErrBadTargets{Msg: err.Error()}
		}
		updatesToApply = append(updatesToApply, roles[roleName])
	}

	return updatesToApply, nil
}
Ejemplo n.º 5
0
func checkTimestampSnapshotRequired(t *testing.T, meta map[string][]byte, extraMeta []string, builder tuf.RepoBuilder) {
	// 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], 1, false))
		for _, checkName := range append(data.BaseRoles, extraMeta...) {
			ci := builder.GetConsistentInfo(checkName)
			require.Equal(t, checkName, ci.ConsistentName())

			switch checkName {
			case data.CanonicalTimestampRole:
				// timestamp's size is always the max timestamp size
				require.True(t, ci.ChecksumKnown())
				require.Equal(t, notary.MaxTimestampSize, ci.Length())
			default:
				require.False(t, ci.ChecksumKnown())
				require.Equal(t, int64(-1), ci.Length())
			}
		}
	}
}
Ejemplo n.º 6
0
// generateTimestamp generates a new timestamp from the previous one in the store - this assumes all
// the other roles have already been set on the repo, and will set the generated timestamp on the repo as well
func generateTimestamp(gun string, builder tuf.RepoBuilder, store storage.MetaStore) (*storage.MetaUpdate, error) {
	var prev *data.SignedTimestamp
	_, currentJSON, err := store.GetCurrent(gun, data.CanonicalTimestampRole)

	switch err.(type) {
	case nil:
		prev = new(data.SignedTimestamp)
		if err := json.Unmarshal(currentJSON, prev); err != nil {
			logrus.Error("Failed to unmarshal existing timestamp for GUN ", gun)
			return nil, err
		}
	case storage.ErrNotFound:
		break // this is the first timestamp ever for the repo
	default:
		return nil, err
	}

	meta, ver, err := builder.GenerateTimestamp(prev)

	switch err.(type) {
	case nil:
		return &storage.MetaUpdate{
			Role:    data.CanonicalTimestampRole,
			Version: ver,
			Data:    meta,
		}, nil
	case signed.ErrInsufficientSignatures, signed.ErrNoKeys:
		// If we cannot sign the timestamp, then we don't have keys for the timestamp,
		// and the client screwed up their root
		return nil, validation.ErrBadRoot{
			Msg: fmt.Sprintf("no  timestamp keys exist on the server"),
		}
	default:
		return nil, validation.ErrValidation{Msg: err.Error()}
	}
}
Ejemplo n.º 7
0
func checkOtherRolesConsistentAfterSnapshot(t *testing.T, repo *tuf.Repo, meta map[string][]byte, builder tuf.RepoBuilder) {
	// 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], 1, false))
	for _, checkName := range data.BaseRoles {
		ci := builder.GetConsistentInfo(checkName)
		require.True(t, ci.ChecksumKnown(), "%s's checksum is not known", checkName)

		switch checkName {
		case data.CanonicalTimestampRole:
			// timestamp's canonical name is always "timestamp" and its size is always -1
			require.Equal(t, data.CanonicalTimestampRole, ci.ConsistentName())
			require.Equal(t, notary.MaxTimestampSize, ci.Length())
		default:
			fileInfo := repo.Snapshot.Signed.Meta
			if checkName == data.CanonicalSnapshotRole {
				fileInfo = repo.Timestamp.Signed.Meta
			}

			cName := utils.ConsistentName(checkName, fileInfo[checkName].Hashes[notary.SHA256])
			require.Equal(t, cName, ci.ConsistentName())
			require.True(t, ci.Length() > -1)
		}
	}
}