coreos / fedora-coreos-tracker

Issue tracker for Fedora CoreOS
https://fedoraproject.org/coreos/
262 stars 59 forks source link

stream metadata GPG validation #774

Open cgwalters opened 3 years ago

cgwalters commented 3 years ago

In stream metadata today we have signatures on the individual artifacts. I'd like to have a model where the whole stream metadata is signed too - this greatly mitigates things like MITM downgrade attacks, etc. It would also cover e.g. the AMIs, which are not signed today.

For signing the JSON...having a detached stable.json.asc is an obvious approach but external signatures on unversioned URLs lead to race conditions around fetches: http://www.chiark.greenend.org.uk/~cjwatson/blog/no-more-hash-sum-mismatch-errors.html (Fun side fact: Colin Watson and I worked together sometimes in Debian, and people got us confused quite frequently)

For inline signatures I found https://jwt.io/introduction - not sure if there's a better standard, and probably that one's a nonstarter because it breaks the format.

If we go with the detached model, one thing that would help is if e.g. the stable URL was actually a HTTP redirect to something like https://builds.coreos.fedoraproject.org/streams/stable-${sha256}.json - then a client could detect the redirect and then reliably fetch the detached signature from https://builds.coreos.fedoraproject.org/streams/stable-${sha256}.json.asc for example.

bgilbert commented 3 years ago

It wouldn't prevent downgrade attacks by itself, since the entire stream metadata could be downgraded. But the client could check that the last-modified date doesn't go backwards.

Intercepting redirects feels like it would require the client to have too much knowledge of the network protocol. Maybe we could have a new stable-signed.json which just contains URLs for the current stable-${sha256}.json and stable-${sha256}.json.asc.

cgwalters commented 3 years ago

It wouldn't prevent downgrade attacks by itself, since the entire stream metadata could be downgraded. But the client could check that the last-modified date doesn't go backwards.

Right.

Maybe we could have a new stable-signed.json which just contains URLs for the current stable-${sha256}.json and stable-${sha256}.json.asc.

Yeah. I found various bits on this:

And the JWT is also an approach.

I think what you're suggesting is quite simple and straightforward - easy to implement, but would be custom to us and also require 3 distinct HTTP round trips.

We also have the broader problem that validating GPG signatures in general sucks, but it's particularly painful with Go projects that want to statically link everything. It's may be worth opening up the conversation around moving away from GPG for this.

I dunno.

bgilbert commented 3 years ago

See also #826, which is the same issue for a different set of metadata.

rugk commented 3 years ago

It wouldn't prevent downgrade attacks by itself, since the entire stream metadata could be downgraded. But the client could check that the last-modified date doesn't go backwards.

I guess you know https://theupdateframework.io/ for a way how to prevent downgrade attacks. It also describes all the problems and other attacks (threat models) associated to the whole thing of “updating” software. :wink:

lucab commented 3 years ago

A bunch of assorted self-notes that we may or may not want to dig deeper:

  1. to avoid both "inline signatures embedded in JSON" and "racing on detached signature files", we may look into generating a detached signature and sending it to the clients as a custom HTTP response header.
  2. minisign sports small keys and signatures, and it has native libraries for verification for all the languages we use (Rust, Go, Python).
jlebon commented 3 years ago

The signature-in-header approach sounds interesting.

Another more low-tech approach is to have the detached signature not have a stable name and point to it from the metadata itself in e.g. metadata.signature_path. On the signing side, we would: choose a name, add it to the metadata, sign the metadata, upload the signature, and then upload the new metadata, and finally GC old signatures.