Ejemplo n.º 1
0
// check the snapshot is present. If it is, the hierarchy
// of the update is OK. This seems like a simplistic check
// but is completely sufficient for all possible use cases:
// 1. the user is updating only the snapshot.
// 2. the user is updating a targets (incl. delegations) or
//    root metadata. This requires they also provide a new
//    snapshot.
// N.B. users should never be updating timestamps. The server
//      always handles timestamping. If the user does send a
//      timestamp, the server will replace it on next
//      GET timestamp.jsonshould it detect the current
//      snapshot has a different hash to the one in the timestamp.
func hierarchyOK(roles map[string]storage.MetaUpdate) error {
	snapshotRole := data.RoleName(data.CanonicalSnapshotRole)
	if _, ok := roles[snapshotRole]; !ok {
		return errors.New("snapshot missing from update")
	}
	return nil
}
Ejemplo n.º 2
0
// checkRoot determines if the hash, and size are still those reported
// in the snapshot file. It will also check the expiry, however, if the
// hash and size in snapshot are unchanged but the root file has expired,
// there is little expectation that the situation can be remedied.
func (c Client) checkRoot() error {
	role := data.RoleName("root")
	size := c.local.Snapshot.Signed.Meta[role].Length
	hashSha256 := c.local.Snapshot.Signed.Meta[role].Hashes["sha256"]

	raw, err := c.cache.GetMeta("root", size)
	if err != nil {
		return err
	}

	hash := sha256.Sum256(raw)
	if !bytes.Equal(hash[:], hashSha256) {
		return fmt.Errorf("Cached root sha256 did not match snapshot root sha256")
	}

	if int64(len(raw)) != size {
		return fmt.Errorf("Cached root size did not match snapshot size")
	}

	root := &data.SignedRoot{}
	err = json.Unmarshal(raw, root)
	if err != nil {
		return ErrCorruptedCache{file: "root.json"}
	}

	if signed.IsExpired(root.Signed.Expires) {
		return tuf.ErrLocalRootExpired{}
	}
	return nil
}
Ejemplo n.º 3
0
// downloadTargets is responsible for downloading any targets file
// including delegates roles. It will download the whole tree of
// delegated roles below the given one
func (c *Client) downloadTargets(role string) error {
	role = data.RoleName(role) // this will really only do something for base targets role
	snap := c.local.Snapshot.Signed
	root := c.local.Root.Signed
	r := c.keysDB.GetRole(role)
	if r == nil {
		return fmt.Errorf("Invalid role: %s", role)
	}
	keyIDs := r.KeyIDs
	s, err := c.GetTargetsFile(role, keyIDs, snap.Meta, root.ConsistentSnapshot, r.Threshold)
	if err != nil {
		logrus.Error("Error getting targets file:", err)
		return err
	}
	err = c.local.SetTargets(role, s)
	if err != nil {
		return err
	}
	t := c.local.Targets[role].Signed
	for _, r := range t.Delegations.Roles {
		err := c.downloadTargets(r.Name)
		if err != nil {
			logrus.Error("Failed to download ", role, err)
			return err
		}
	}
	return nil
}
Ejemplo n.º 4
0
// downloadTargets is responsible for downloading any targets file
// including delegates roles.
func (c *Client) downloadTargets(role string) error {
	role = data.RoleName(role) // this will really only do something for base targets role
	if c.local.Snapshot == nil {
		return ErrMissingMeta{role: role}
	}
	snap := c.local.Snapshot.Signed
	root := c.local.Root.Signed
	r := c.keysDB.GetRole(role)
	if r == nil {
		return fmt.Errorf("Invalid role: %s", role)
	}
	keyIDs := r.KeyIDs
	s, err := c.getTargetsFile(role, keyIDs, snap.Meta, root.ConsistentSnapshot, r.Threshold)
	if err != nil {
		logrus.Error("Error getting targets file:", err)
		return err
	}
	t, err := data.TargetsFromSigned(s)
	if err != nil {
		return err
	}
	err = c.local.SetTargets(role, t)
	if err != nil {
		return err
	}

	return nil
}
Ejemplo n.º 5
0
// downloadTimestamp is responsible for downloading the timestamp.json
func (c *Client) downloadTimestamp() error {
	logrus.Debug("downloadTimestamp")
	role := data.RoleName("timestamp")

	// We may not have a cached timestamp if this is the first time
	// we're interacting with the repo. This will result in the
	// version being 0
	var download bool
	old := &data.Signed{}
	version := 0
	cachedTS, err := c.cache.GetMeta(role, maxSize)
	if err == nil {
		err := json.Unmarshal(cachedTS, old)
		if err == nil {
			ts, err := data.TimestampFromSigned(old)
			if err == nil {
				version = ts.Signed.Version
			}
		} else {
			old = nil
		}
	}
	// unlike root, targets and snapshot, always try and download timestamps
	// from remote, only using the cache one if we couldn't reach remote.
	logrus.Debug("Downloading timestamp")
	raw, err := c.remote.GetMeta(role, maxSize)
	var s *data.Signed
	if err != nil || len(raw) == 0 {
		if err, ok := err.(store.ErrMetaNotFound); ok {
			return err
		}
		if old == nil {
			if err == nil {
				// couldn't retrieve data from server and don't have valid
				// data in cache.
				return store.ErrMetaNotFound{}
			}
			return err
		}
		s = old
	} else {
		download = true
		s = &data.Signed{}
		err = json.Unmarshal(raw, s)
		if err != nil {
			return err
		}
	}
	err = signed.Verify(s, role, version, c.keysDB)
	if err != nil {
		return err
	}
	logrus.Debug("successfully verified timestamp")
	if download {
		c.cache.SetMeta(role, raw)
	}
	c.local.SetTimestamp(s)
	return nil
}
Ejemplo n.º 6
0
func checkSnapshotEntries(role string, oldSnap, snap *data.SignedSnapshot, roles map[string]storage.MetaUpdate) error {
	snapshotRole := data.RoleName(data.CanonicalSnapshotRole)
	timestampRole := data.RoleName(data.CanonicalTimestampRole) // just in case
	for r, update := range roles {
		if r == snapshotRole || r == timestampRole {
			continue
		}
		m, ok := snap.Signed.Meta[r]
		if !ok {
			return fmt.Errorf("snapshot missing metadata for %s", r)
		}
		if int64(len(update.Data)) != m.Length {
			return fmt.Errorf("snapshot has incorrect length for %s", r)
		}

		if !checkHashes(m, update.Data) {
			return fmt.Errorf("snapshot has incorrect hashes for %s", r)
		}
	}
	return nil
}
Ejemplo n.º 7
0
// checkRoot determines if the hash, and size are still those reported
// in the snapshot file. It will also check the expiry, however, if the
// hash and size in snapshot are unchanged but the root file has expired,
// there is little expectation that the situation can be remedied.
func (c Client) checkRoot() error {
	role := data.RoleName("root")
	size := c.local.Snapshot.Signed.Meta[role].Length
	hashSha256 := c.local.Snapshot.Signed.Meta[role].Hashes["sha256"]

	raw, err := c.cache.GetMeta("root", size)
	if err != nil {
		return err
	}

	hash := sha256.Sum256(raw)
	if !bytes.Equal(hash[:], hashSha256) {
		return fmt.Errorf("Cached root sha256 did not match snapshot root sha256")
	}
	return nil
}
Ejemplo n.º 8
0
// downloadTimestamp is responsible for downloading the timestamp.json
func (c *Client) downloadTimestamp() error {
	role := data.RoleName("timestamp")
	raw, err := c.remote.GetMeta(role, 5<<20)
	if err != nil {
		return err
	}
	s := &data.Signed{}
	err = json.Unmarshal(raw, s)
	if err != nil {
		return err
	}
	err = signed.Verify(s, role, 0, c.keysDB)
	if err != nil {
		return err
	}
	c.local.SetTimestamp(s)
	return nil
}
Ejemplo n.º 9
0
// downloadSnapshot is responsible for downloading the snapshot.json
func (c *Client) downloadSnapshot() error {
	role := data.RoleName("snapshot")
	size := c.local.Timestamp.Signed.Meta[role].Length
	raw, err := c.remote.GetMeta(role, size)
	if err != nil {
		return err
	}
	s := &data.Signed{}
	err = json.Unmarshal(raw, s)
	if err != nil {
		return err
	}
	err = signed.Verify(s, role, 0, c.keysDB)
	if err != nil {
		return err
	}
	c.local.SetSnapshot(s)
	return nil
}
Ejemplo n.º 10
0
// validateUpload checks that the updates being pushed
// are semantically correct and the signatures are correct
func validateUpdate(gun string, updates []storage.MetaUpdate, store storage.MetaStore) error {
	kdb := keys.NewDB()
	repo := tuf.NewRepo(kdb, nil)
	rootRole := data.RoleName(data.CanonicalRootRole)
	targetsRole := data.RoleName(data.CanonicalTargetsRole)
	snapshotRole := data.RoleName(data.CanonicalSnapshotRole)

	// check that the necessary roles are present:
	roles := make(map[string]storage.MetaUpdate)
	for _, v := range updates {
		roles[v.Role] = v
	}
	if err := hierarchyOK(roles); err != nil {
		logrus.Error("ErrBadHierarchy: ", err.Error())
		return ErrBadHierarchy{msg: err.Error()}
	}
	logrus.Debug("Successfully validated hierarchy")

	var root *data.SignedRoot
	oldRootJSON, err := store.GetCurrent(gun, rootRole)
	if _, ok := err.(*storage.ErrNotFound); err != nil && !ok {
		// problem with storage. No expectation we can
		// write if we can't read so bail.
		logrus.Error("error reading previous root: ", err.Error())
		return err
	}
	if rootUpdate, ok := roles[rootRole]; ok {
		// if root is present, validate its integrity, possibly
		// against a previous root
		if root, err = validateRoot(gun, oldRootJSON, rootUpdate.Data); err != nil {
			logrus.Error("ErrBadRoot: ", err.Error())
			return ErrBadRoot{msg: err.Error()}
		}
		// setting root will update keys db
		if err = repo.SetRoot(root); err != nil {
			logrus.Error("ErrValidation: ", err.Error())
			return ErrValidation{msg: err.Error()}
		}
		logrus.Debug("Successfully validated root")
	} else {
		if oldRootJSON == nil {
			return ErrValidation{msg: "no pre-existing root and no root provided in update."}
		}
		parsedOldRoot := &data.SignedRoot{}
		if err := json.Unmarshal(oldRootJSON, parsedOldRoot); err != nil {
			return ErrValidation{msg: "pre-existing root is corrupted and no root provided in update."}
		}
		if err = repo.SetRoot(parsedOldRoot); err != nil {
			logrus.Error("ErrValidation: ", err.Error())
			return ErrValidation{msg: err.Error()}
		}
	}

	// TODO: validate delegated targets roles.
	var t *data.SignedTargets
	if _, ok := roles[targetsRole]; ok {
		if t, err = validateTargets(targetsRole, roles, kdb); err != nil {
			logrus.Error("ErrBadTargets: ", err.Error())
			return ErrBadTargets{msg: err.Error()}
		}
		repo.SetTargets(targetsRole, t)
	}
	logrus.Debug("Successfully validated targets")

	var oldSnap *data.SignedSnapshot
	oldSnapJSON, err := store.GetCurrent(gun, snapshotRole)
	if _, ok := err.(*storage.ErrNotFound); err != nil && !ok {
		// problem with storage. No expectation we can
		// write if we can't read so bail.
		logrus.Error("error reading previous snapshot: ", err.Error())
		return err
	} else if err == nil {
		oldSnap = &data.SignedSnapshot{}
		if err := json.Unmarshal(oldSnapJSON, oldSnap); err != nil {
			oldSnap = nil
		}
	}

	if err := validateSnapshot(snapshotRole, oldSnap, roles[snapshotRole], roles, kdb); err != nil {
		logrus.Error("ErrBadSnapshot: ", err.Error())
		return ErrBadSnapshot{msg: err.Error()}
	}
	logrus.Debug("Successfully validated snapshot")
	return nil
}
Ejemplo n.º 11
0
// checkRoot returns true if no rotation, or a valid
// rotation has taken place, and the threshold number of signatures
// are valid.
func checkRoot(oldRoot, newRoot *data.SignedRoot) error {
	rootRole := data.RoleName(data.CanonicalRootRole)
	targetsRole := data.RoleName(data.CanonicalTargetsRole)
	snapshotRole := data.RoleName(data.CanonicalSnapshotRole)
	timestampRole := data.RoleName(data.CanonicalTimestampRole)

	var oldRootRole *data.RootRole
	newRootRole, ok := newRoot.Signed.Roles[rootRole]
	if !ok {
		return errors.New("new root is missing role entry for root role")
	}

	oldThreshold := 1
	rotation := false
	oldKeys := map[string]data.PublicKey{}
	newKeys := map[string]data.PublicKey{}
	if oldRoot != nil {
		// check for matching root key IDs
		oldRootRole = oldRoot.Signed.Roles[rootRole]
		oldThreshold = oldRootRole.Threshold

		for _, kid := range oldRootRole.KeyIDs {
			k, ok := oldRoot.Signed.Keys[kid]
			if !ok {
				// if the key itself wasn't contained in the root
				// we're skipping it because it could never have
				// been used to validate this root.
				continue
			}
			oldKeys[kid] = data.NewPublicKey(k.Algorithm(), k.Public())
		}

		// super simple check for possible rotation
		rotation = len(oldKeys) != len(newRootRole.KeyIDs)
	}
	// if old and new had the same number of keys, iterate
	// to see if there's a difference.
	for _, kid := range newRootRole.KeyIDs {
		k, ok := newRoot.Signed.Keys[kid]
		if !ok {
			// if the key itself wasn't contained in the root
			// we're skipping it because it could never have
			// been used to validate this root.
			continue
		}
		newKeys[kid] = data.NewPublicKey(k.Algorithm(), k.Public())

		if oldRoot != nil {
			if _, ok := oldKeys[kid]; !ok {
				// if there is any difference in keys, a key rotation may have
				// occurred.
				rotation = true
			}
		}
	}
	newSigned, err := newRoot.ToSigned()
	if err != nil {
		return err
	}
	if rotation {
		err = signed.VerifyRoot(newSigned, oldThreshold, oldKeys)
		if err != nil {
			return fmt.Errorf("rotation detected and new root was not signed with at least %d old keys", oldThreshold)
		}
	}
	err = signed.VerifyRoot(newSigned, newRootRole.Threshold, newKeys)
	if err != nil {
		return err
	}
	root, err := data.RootFromSigned(newSigned)
	if err != nil {
		return err
	}
	// at a minimum, check the 4 required roles are present
	for _, r := range []string{rootRole, targetsRole, snapshotRole, timestampRole} {
		role, ok := root.Signed.Roles[r]
		if !ok {
			return fmt.Errorf("missing required %s role from root", r)
		}
		if role.Threshold < 1 {
			return fmt.Errorf("%s role has invalid threshold", r)
		}
		if len(role.KeyIDs) < role.Threshold {
			return fmt.Errorf("%s role has insufficient number of keys", r)
		}
	}
	return nil
}
Ejemplo n.º 12
0
// downloadSnapshot is responsible for downloading the snapshot.json
func (c *Client) downloadSnapshot() error {
	logrus.Debug("downloadSnapshot")
	role := data.RoleName("snapshot")
	if c.local.Timestamp == nil {
		return ErrMissingMeta{role: "snapshot"}
	}
	size := c.local.Timestamp.Signed.Meta[role].Length
	expectedSha256, ok := c.local.Timestamp.Signed.Meta[role].Hashes["sha256"]
	if !ok {
		return ErrMissingMeta{role: "snapshot"}
	}

	var download bool
	old := &data.Signed{}
	version := 0
	raw, err := c.cache.GetMeta(role, size)
	if raw == nil || err != nil {
		logrus.Debug("no snapshot in cache, must download")
		download = true
	} else {
		// file may have been tampered with on disk. Always check the hash!
		genHash := sha256.Sum256(raw)
		if !bytes.Equal(genHash[:], expectedSha256) {
			logrus.Debug("hash of snapshot in cache did not match expected hash, must download")
			download = true
		}
		err := json.Unmarshal(raw, old)
		if err == nil {
			snap, err := data.TimestampFromSigned(old)
			if err == nil {
				version = snap.Signed.Version
			} else {
				logrus.Debug("Could not parse Signed part of snapshot, must download")
				download = true
			}
		} else {
			logrus.Debug("Could not parse snapshot, must download")
			download = true
		}
	}
	var s *data.Signed
	if download {
		raw, s, err = c.downloadSigned(role, size, expectedSha256)
		if err != nil {
			return err
		}
	} else {
		logrus.Debug("using cached snapshot")
		s = old
	}

	err = signed.Verify(s, role, version, c.keysDB)
	if err != nil {
		return err
	}
	logrus.Debug("successfully verified snapshot")
	snap, err := data.SnapshotFromSigned(s)
	if err != nil {
		return err
	}
	c.local.SetSnapshot(snap)
	if download {
		err = c.cache.SetMeta(role, raw)
		if err != nil {
			logrus.Errorf("Failed to write snapshot to local cache: %s", err.Error())
		}
	}
	return nil
}
Ejemplo n.º 13
0
// downloadRoot is responsible for downloading the root.json
func (c *Client) downloadRoot() error {
	role := data.RoleName("root")
	size := maxSize
	var expectedSha256 []byte
	if c.local.Snapshot != nil {
		size = c.local.Snapshot.Signed.Meta[role].Length
		expectedSha256 = c.local.Snapshot.Signed.Meta[role].Hashes["sha256"]
	}

	// if we're bootstrapping we may not have a cached root, an
	// error will result in the "previous root version" being
	// interpreted as 0.
	var download bool
	var err error
	var cachedRoot []byte
	old := &data.Signed{}
	version := 0

	if expectedSha256 != nil {
		// can only trust cache if we have an expected sha256 to trust
		cachedRoot, err = c.cache.GetMeta(role, size)
	}

	if cachedRoot == nil || err != nil {
		logrus.Debug("didn't find a cached root, must download")
		download = true
	} else {
		hash := sha256.Sum256(cachedRoot)
		if !bytes.Equal(hash[:], expectedSha256) {
			logrus.Debug("cached root's hash didn't match expected, must download")
			download = true
		}
		err := json.Unmarshal(cachedRoot, old)
		if err == nil {
			root, err := data.RootFromSigned(old)
			if err == nil {
				version = root.Signed.Version
			} else {
				logrus.Debug("couldn't parse Signed part of cached root, must download")
				download = true
			}
		} else {
			logrus.Debug("couldn't parse cached root, must download")
			download = true
		}
	}
	var s *data.Signed
	var raw []byte
	if download {
		raw, s, err = c.downloadSigned(role, size, expectedSha256)
		if err != nil {
			return err
		}
	} else {
		logrus.Debug("using cached root")
		s = old
	}
	if err := c.verifyRoot(role, s, version); err != nil {
		return err
	}
	if download {
		logrus.Debug("caching downloaded root")
		// Now that we have accepted new root, write it to cache
		if err = c.cache.SetMeta(role, raw); err != nil {
			logrus.Errorf("Failed to write root to local cache: %s", err.Error())
		}
	}
	return nil
}
Ejemplo n.º 14
0
// downloadSnapshot is responsible for downloading the snapshot.json
func (c *Client) downloadSnapshot() error {
	logrus.Debug("downloadSnapshot")
	role := data.RoleName("snapshot")
	size := c.local.Timestamp.Signed.Meta[role].Length
	expectedSha256, ok := c.local.Timestamp.Signed.Meta[role].Hashes["sha256"]
	if !ok {
		return fmt.Errorf("Sha256 is currently the only hash supported by this client. No Sha256 found for snapshot")
	}

	var download bool
	old := &data.Signed{}
	version := 0
	raw, err := c.cache.GetMeta(role, size)
	if raw == nil || err != nil {
		logrus.Debug("no snapshot in cache, must download")
		download = true
	} else {
		// file may have been tampered with on disk. Always check the hash!
		genHash := sha256.Sum256(raw)
		if !bytes.Equal(genHash[:], expectedSha256) {
			logrus.Debug("hash of snapshot in cache did not match expected hash, must download")
			download = true
		}
		err := json.Unmarshal(raw, old)
		if err == nil {
			snap, err := data.TimestampFromSigned(old)
			if err == nil {
				version = snap.Signed.Version
			} else {
				logrus.Debug("Could not parse Signed part of snapshot, must download")
				download = true
			}
		} else {
			logrus.Debug("Could not parse snapshot, must download")
			download = true
		}
	}
	var s *data.Signed
	if download {
		logrus.Debug("downloading new snapshot")
		raw, err = c.remote.GetMeta(role, size)
		if err != nil {
			return err
		}
		genHash := sha256.Sum256(raw)
		if !bytes.Equal(genHash[:], expectedSha256) {
			return fmt.Errorf("Retrieved snapshot did not verify against hash in timestamp.")
		}
		s = &data.Signed{}
		err = json.Unmarshal(raw, s)
		if err != nil {
			return err
		}
	} else {
		logrus.Debug("using cached snapshot")
		s = old
	}

	err = signed.Verify(s, role, version, c.keysDB)
	if err != nil {
		return err
	}
	logrus.Debug("successfully verified snapshot")
	c.local.SetSnapshot(s)
	if download {
		err = c.cache.SetMeta(role, raw)
		if err != nil {
			logrus.Errorf("Failed to write snapshot to local cache: %s", err.Error())
		}
	}
	return nil
}