Skip to content

How do we initialize trust with local metadata, and no access to a remote repository? #108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
erickt opened this issue Aug 28, 2020 · 3 comments

Comments

@erickt
Copy link
Contributor

erickt commented Aug 28, 2020

On Fuchsia, we are using TUF not only to fetch new packages, but also as a file system implementation to launch packages (see this for more details). For a long time, we've been using ephemeral repositories for package resolution, so we've always needed to be online. However we're finally starting to explore how we'll resolve packages when we've rebooted and we're not able to go online.

While scoping out this work, I noticed the spec is actually a little vague as to how we should initialize trust when we have a local cache of TUF metadata, but no way to fetch remote metadata:

  • In section 5.1, I don't actually see where we are supposed to persist any root metadata changes. Presumably we'd write these files as $ROOT_VERISON.root.EXT though.
  • In section 5.2, we write the timestamp metadata as timestamp.EXT. It'd be easy enough to load that file since we expect that file to be unversioned, but...
  • In section 5.3, we write the snapshot to snapshot.EXT. Likewise, 5.4 we write targets and delegates as FILENAME.EXT.

We use consistent snapshots, so just trying to search the local store first will fail, because we'll be looking for $SNAPSHOT_VERSION.snapshot.EXT and $TARGETS_VERSION.snapshot.EXT. Should we initialize trust by disabling consistent snapshots, trying to load all the local metadata, then re-enabling consistent snapshots? I think that ought to work, but the one sticking point is how to handle a partial update (see #69). In that case, presumably the initialization should succeed, just not initialize the TUF database with the inconsistent metadata. To protect against this, presumably we ought to write metadata to the local store in a transaction.

@erickt
Copy link
Contributor Author

erickt commented Aug 28, 2020

note that we don't want to just assume local metadata is trusted, and instead want to validate it's properly signed and not manipulated by a local attacker (see #107)

@joshuagl
Copy link
Member

Thanks for this discussion @erickt.

My interpretation of the spec is that we assume we're only ever bootstrapping from a local trusted root.EXT and can talk to the repository for all other metadata files.

I think your proposed approach to initialising trust with local metadata sounds sensible. Of course, initialising trust from local metadata only weakens some of TUFs security properties. It is hard to provide freshness guarantees and to know whether the currently trusted keys should still be trusted (you can refuse to trust an expired key, but you won't detect a revoked key without fetching newer metadata).

Out of interest, if your Fuchsia client is not able to go online and the expiration timestamp in timestamp.EXT has passed, what will happen?

@erickt
Copy link
Contributor Author

erickt commented Aug 28, 2020

We've partially figured out our offline story. Some of our plans are documented here. Fuchsia packages really are just a listing of a file path to a list of content addressed blobs. A Fuchsia repository is a tree of paths to packages. We have 3 different types of package repositories:

  • Base packages, which are critical packages for the proper functioning of Fuchsia, which must be always available. For example, user space drivers, the packaging system, display services and etc. These are only updated in an OS update.
  • Cache packages, which are pre-installed packages, but can be updated outside of an OS update. For example, important applications like clock and camera apps.
  • Ephemeral packages, which are packages that we download from some external source. For example, third party applications like podcast or games. The packaging system will try to keep these packages up to date according to some policy.

Base and cache packages need to be offline, so these repositories are just files that are trusted through our verified boot process. We use TUF to support Cache and Ephemeral packages. So when we are resolving a package, we:

  • First check if the package is in the base package list, if so return it.
  • Next, check if the package is in our TUF database. If so, resolve it. However, if we can't find the package, or we're unable to update TUF, we finally check if the package is in the cache package list.

There's no expiry on base and cache packages, so we can always resolve them. But we'd love to be able to still use ephemeral packages if we don't have network access. I have ideas so far:

  • The easiest, but weakest, is just to use a large expiration timestamp. That'd solve our problem, but we'd be giving up freeze attack protection.
  • We could change our TUF initialization such that we ignore expiration when loading metadata from the local cache, but check them when we fetch metadata from a remote repository. This would let us catch remote freeze attacks, but could still leave us vulnerable to local freeze attacks. To reduce the scope of this somewhat, maybe we only ignore the expiry on timestamp, but have a large expiry for snapshot and/or targets?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants