Skip to content
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

Support for artifact signature verification #4

Open
djspiewak opened this issue Jul 26, 2018 · 3 comments
Open

Support for artifact signature verification #4

djspiewak opened this issue Jul 26, 2018 · 3 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@djspiewak
Copy link
Collaborator

Almost no one uses this feature in sbt-pgp anyway, so I could be convinced that it's out of scope, but it would be nice to have. In a more pie-in-the-sky sense, it would be extremely nice if there were some way we could culturally encourage the Scala community (via this tooling) to verify signatures more frequently, since a large chunk of the software development trust model is dependent on this link in the chain that no one checks.

@jodersky
Copy link
Owner

jodersky commented Jul 26, 2018

I would love to see better security for the maven publishing model. IMO the gpg web-of-trust model just requires too much effort from too many participants for it to become a viable way to authenticate binaries. Do you know of keybase.io? Maybe we could somehow leverage that as part of the verification process?

In the longer term, I'd like to see better support from repositories too (check out this thread for some inspiration on Rust's Crates.io rust-lang/cargo#1281) and most importantly, reproducible builds becoming mainstream in the JVM world!

In the short term, I think wrapping around gpg's verify command is the way to go.

@djspiewak
Copy link
Collaborator Author

I would love to see better security for the maven publishing model. IMO the gpg web-of-trust model just requires too much effort from too many participants for it to become a viable way to authenticate binaries. Do you know of keybase.io? Maybe we could somehow leverage that as part of the verification process?

I'm a huge keybase fan. Or at least a huge fan of their core database; I'm less keen on their Slack/Dropbox/whatever-killer product. Either way, I think that would be outstanding. The web-of-trust model doesn't work very well. Some authors do have their keys signed into the strong set, and it's certainly worth respecting that in the verification process, but rejecting a signature just because it fails GPG's user hostile trust model is not the right approach.

Fundamentally, the goal is to assert that the people we think published something, did in fact publish something. I can think of a couple things we can leverage for this…

  • Key Pinning. Technically, this is what GPG's trust model does, so not too much of an improvement. At the very least, we should probably hard-code the signature of the signing key used to publish Scala builds, since that's one we're guaranteed to hit in every build. Providing a setting key which contains a set of trusted keys (with an optional set of groupIds which those keys are trusted to publish, rejecting all others) would be a step up from GPG's model since it would give us build reproducibility and allow people to fail builds based on verification status. I'm thinking lazy val trustedKeys = settingKey[Seq[(String, Option[Set[String]])]], probably with some nicer syntax built around it.
    • This idea can be extended by allowing the trustedKeys to be fetched from some external server. This corrupts build reproducibility, but it's almost guaranteed to be the option that organizations such as Verizon and similar would want to use. Imagine organizations enabling mandatory signing checks based on a standardized and revocable trust source, centrally controlled by the org.
  • Tag Signature Checks. Common best-practice in the Scala community seems to be to sign the git tag which represents the release (this is good!) as well as the release itself (also good!). For projects where those signing keys are the same (unfortunately, not scala-library/compiler), one check can be to pull the SCM information from the pom attributes and find the git tag which represents the release, checking its signing key matches the artifact's signing key. See here for verification instructions based on this idea. This would produce an extremely high-confidence trust result on essentially arbitrary artifacts, but unfortunately it is project-dependent and dependent on git.
  • Keybase Verification. This is a fun idea. The vast majority of all projects are hosted on github. Pull the SCM info from the POM and get the name of the repository owner. Feed that into keybase's search (which has an excellent API, btw) and check the signature against the result. This is extremely robust from a security standpoint, but it does have some problems.
    • Reproducibility because of external database. Probably not a big deal in practice since keybase's database is very stable in practice.
    • Many artifacts are signed by a CI key, not by an individual. Keybase doesn't work for that.
    • The majority of large Scala projects are owned by an organization (e.g. typelevel/cats) not by an individual. Keybase doesn't work for this either.
  • Transitive Trust. We could magnify the applicability of all of these ideas by allowing the GPG WoT to come back into play. Any key which is signed by some other key which itself passes muster by one of the other criteria (or transitively) could presumably trusted. For example, we hard-code the Scala signing key, and if that key is used to sign my key, then people would be able to trust my key as well. Of course, WoT worked out so well the first time…
  • Fetching a KEYS File. Get the SCM info, pull the current state, look in the repo root for a KEYS file. This used to be standard for Apache projects. It's not a terrible way to go, since anyone who wants to publish a fraudulent artifact would need to make a very public assertion of such. Unfortunately, it also can make builds unreproducible (if a project deletes or removes from their KEYS file). Additionally, it's opt-in (on the project side).
  • Transitive Dependency Trust. If you depend on a trusted artifact and it transitively depends on some other artifact, then you should be able to trust the key which signed that transitive artifact. This should greatly reduce the number of keys which need to be explicitly trusted.

Oh, and all of these ideas that involve "pulling the SCM information" run into the problem that we're getting that information… from the very POM that we're trying to verify for authenticity. So we're kind of stuck between a rock and a hard-place, here. I'm not sure it completely invalidates those ideas on all levels, but it does kick them out as means of verification without other changes.

Practically, our best bet is probably to start with gpg verify. If that accepts the signature, then leave it at that. If it doesn't, then check trustedKeys as described in the pinning section. Pre-populate the plugin with some reasonable trustedKeys. Off the top of my head:

  • Scala's
  • Spark's
  • Akka's
  • Scalaz's
  • Cats'
  • etc etc

This has the potential to create winners and losers though due to incumbancy, so I'm somewhat tempted to only pin Scala's key.

@jodersky jodersky added enhancement New feature or request help wanted Extra attention is needed labels Dec 26, 2018
@wiktor-k
Copy link

wiktor-k commented Jan 3, 2019

I'll drop here some random notes that may be relevant, I hope you don't mind:

  • Key pinning - Remember to pin not the signature key but rather the master/primary key. OpenPGP relies on primary's key being constant and that key is used to rotate other keys for example signature keys. It's not that uncommon to rotate signature keys (for example due to vulnerabilities) and GPG properly handles that case.

  • Keybase Verification - it's possible to avoid third party service and still have social proofs. Keybase proofs are conceptually just two links: from key to profile and from the profile to the key, it's possible to embed profile info in the GPG key and the GPG fingerprint in a file controlled by the account holder. (proof of concepts: Linked Identities, Distributed IDs).

  • Fetching a KEYS File - I think it's important to refresh keys from keyservers or otherwise after fetching them from KEYS. Some GPG keys can be revoked or expired and updated on keyservers, without that there is a risk of accepting a signature made by a revoked key.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants