wapm-cli icon indicating copy to clipboard operation
wapm-cli copied to clipboard

Package signing/verification tracking issue

Open MarkMcCaskey opened this issue 6 years ago • 21 comments

I'll write down my findings here! I'm going to look around and see what's good 🔥

Please share your knowledge or make suggestions!

Summarized todo list:

TODO:

Managing our own keys

  • [x] Upload and inspect keys (CLI only for now) (UX with minisign tool seems a bit tricky, no tags on keys, have to manually move keys around and regen (TODO: figure out convention or UX for this process))
    • [x] Tagged keys?
    • [x] Private key location stored in DB, given by user on register
  • [x] Key verification chain
    • [x] New key must be signed by previous key
    • [x] Due to multiple keys, associate package/version combination with the corresponding public key
    • [x] Rate limiting on key upload
    • [ ] Allow changing active key (assumption: 1 active key at a time, key list is append only)
  • [x] UX design
    • [ ] Recovery process or warnings about no recovery process

Using keys

  • [x] Manage key database locally (should we prompt the user to accept the key?)
  • [x] Download key if necessary, download signature
    • [x] Update logic to handle edge cases like signature failing to download
  • [x] Signing on publish
    • [x] Verify signature on client
    • [ ] Verify signature on server
  • [ ] UX design
    • [x] Encourage people to sign their packages
    • [ ] Decide if user can decide they don't want to sign anymore and if so, design that process
    • [x] Fail on signature mismatch (possibly have override flag with warning messages)

Misc

  • [x] ~Integrity check if no key registered (hash it by default) ((Is this necessary if we're serving over HTTPS?))~
  • [ ] Look in to preloading wapm.io HTTPS certificate to wapm

bold means higher priority (will be done on first pass)

MarkMcCaskey avatar Apr 25 '19 00:04 MarkMcCaskey

@jedisct1 let us know if you have any suggestions into how we can integrate wasmsign into wapm.

syrusakbary avatar Apr 25 '19 00:04 syrusakbary

(adding @frehberg to the conversation as well)

syrusakbary avatar Apr 25 '19 00:04 syrusakbary

wasmsign signs the wasm file itself.

Which is great.

However, in the context of a package manager, maybe it would be worth signing the whole package, which includes the documentation, the wapm.toml file and additional files.

From a practical perspective, one way to support signatures is to add a command to import public keys, associated to accounts.

Ex:

wapm keys register jedisct1 RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3

Once a public key has been associated with an account, every package from that account must have a valid signature for that public key (or else, display a big fat warning and require a confirmation).

Supporting multiple keys per account might be good, as it facilitates key rotation.

When a package is downloaded, wapm automatically downloads the signature as well. If a package author has set their secret key in wapm, the signature is uploaded in addition to the package. This implies that what people will download should exactly match what was uploaded.

If you opt for Minisign signatures, these can be easily verified with the minisign-verify crate.

rsign can be used to create them. I haven't used rsign, so I don't know how easy it is to use as a crate and not a CLI. But if it turns out to be an issue, I can certainly release a signing counterpart to minisign-verify.

jedisct1 avatar Apr 25 '19 00:04 jedisct1

@jedisct1 Thanks for all the information!

I just saw

DISCLAIMER: This is a toy. This has not undergone any formal security analysis. I am not a security expert. Use at your own risk

on rsign which is a bit concerning.

Minisign seems like a good fit, I'll give integrating it a try

MarkMcCaskey avatar Apr 25 '19 19:04 MarkMcCaskey

In spite of the warning, and from a quick glance, the rsign code looks fine. It's almost a direct port of the C source code to Rust, and all the crypto implementations come from sodiumoxide/libsodium.

Probably good enough for a PoC. The libsodium dependency be easily replaced with a pure Rust solution later.

jedisct1 avatar Apr 25 '19 21:04 jedisct1

@jedisct1 Thanks!!

We're thinking about hosting the public keys on the wapm server ourselves, do you have any thoughts or advice on that? Syrus mentioned that there might be a public registry that we could use instead.

It'd be nice to integrate with existing services to prevent fragmentation and duplicating work if that exists.

MarkMcCaskey avatar Apr 25 '19 22:04 MarkMcCaskey

If the public keys and the signatures are hosted at the same place, the best you can have is trust on first use.

When a user downloads software from a user they don't have a public key for, wapm downloads that public key, stores a local copy and only trusts that local copy from now on.

That shouldn't replace the ability to manually add and remove keys.

Keybase can be used as a public registry, but it has become a kitchen sink, now with an emphasis on messaging.

jedisct1 avatar Apr 25 '19 22:04 jedisct1

Hi, the use-cases of rsign and wasmsign differ

  • rsign is creating a generic, detached signature file *.rsign.
  • wasmsign is embedding the signature into the wasm-module, similar to embedded signatures of PDF-files or Word-documents, a very specific use case.

Looking at your use case to sign a package/collection of wasm-files, docs, meta etc, the tool "rsign" seems a good choice.

I dont know your concept so far, just a few cents:

  • verifying a package/collection, to prevent any tar-bomb (etc.), the verification of the signature must happen before any unpacking/un-tar-ing occurs
  • signing a collection of files with a single signature is done best by creating a hash-sum file over these files (for example sha256sum) and finally signing this hash-sum file.

EDIT the latter will add two files to your collection, the hash-sum-file and the hash-sum-rsig-file

frehberg avatar Apr 26 '19 06:04 frehberg

When a user downloads software from a user they don't have a public key for, wapm downloads that public key, stores a local copy and only trusts that local copy from now on.

As for this public-key-pinning:

Please consider also a transparent upgrade-path/chain for the public-key, in case the author of the package chooses a new key-pair for signing.

Maybe: the meta-data might contain the new public-key, together with signature being verifiable using the previous public-key.

frehberg avatar Apr 26 '19 06:04 frehberg

I haven't looked at how wabt transfers files, but guessing from the dependencies, they are likely to be packed as a tarball.

So only that tarball has to be signed. Signing hashes of individual files adds complexity and makes the scheme vulnerable to internal collisions.

jedisct1 avatar Apr 26 '19 10:04 jedisct1

Thanks! This has been very helpful.

I created a todo list of what we need to do to get this working. Please let me know if you have any feedback or notice any issues! To get started, we'll implement a vertical slice of features: only allowing a single key and accepting keys by default. I'll feature flag it in case it's not ready to be used when we next release. And we'll go from there.

Thanks again for the advice!

MarkMcCaskey avatar Apr 26 '19 19:04 MarkMcCaskey

While it still works perfectly, the original rsign package doesn't seem to be receiving much maintenance.

I started rsign2 to bring and keep it up to date.

The libsodium/sodiumoxide dependency has been removed.

jedisct1 avatar Apr 27 '19 10:04 jedisct1

Standalone crate with minimal dependencies to create and verify signatures: https://github.com/jedisct1/rust-minisign

jedisct1 avatar Apr 28 '19 11:04 jedisct1

Wow, thanks! You're amazing -- thanks for helping us out! That should make things easier!

MarkMcCaskey avatar Apr 29 '19 16:04 MarkMcCaskey

Please consider also a transparent upgrade-path/chain for the public-key, in case the author of the package chooses a new key-pair for signing.

Hello! I'm working on the implementation now and thinking about this chain of trust. Here are some of my thoughts on it so far, I'd love to hear feedback on this!

If we host the keys on the same server as the packages and we have each new key signed by the previous key:

  • Doesn't this mitigate many of the benefits of key rotation? If a key in the chain gets compromised, then malicious keys could be verified with it. (especially when combined with other security vulnerabilities: if the attacker can modify key and package data on the server, then the only case that's potentially safe is if the user has local copies of the keys that extend past the point of compromise (the new end of the chain) and the client can reject the key chain sent by the server which doesn't match the client's chain. Otherwise they're vulnerable to the signed malicious package which will be implicitly trusted because it's part of a chain of keys that the user trusts)
  • Following up on that, it seems we need some way to revoke keys but also be able to detect which packages were signed by the about-to-be-revoked key and have the user resign them (so we need the ability to resign somehow). And if the user's latest key in the chain is before the revoke point, then they'll have to accept the key from the server again.

To keep things simple, I think we'll start by:

  • only allowing resigning by publishing a new version (we want packages to be immutable)
  • the server will send the user/organization's entire key history on install. The client will fail loudly if it detects changes in the history and otherwise: prompts the user to accept the latest key, or verifies to the latest key starting from the latest key the client has, failing if it can't do so.
  • the server will have a notion of revoked key, but that option won't be exposed until later

MarkMcCaskey avatar May 08 '19 18:05 MarkMcCaskey

It would be nice to offload some of this to Keybase if we can. Wasmer (the company) has a lot going on and I'm a bit worried that the more bespoke security we have, the higher chance that something critically important doesn't get the attention that it needs.

I'll evaluate using Keybase now 🤔

MarkMcCaskey avatar May 08 '19 18:05 MarkMcCaskey

Unless I've misunderstood what Keybase offers, it seems like Keybase provides what we want for PGP keys but not other types of keys. It has the nice benefit of letting users verify their wapm accounts and host their public keys there directly, but there does not seem to be a clear way to implement the verification chain with non-PGP keys without doing stuff on our server or having the user do it manually through Keybase 🤔

MarkMcCaskey avatar May 08 '19 21:05 MarkMcCaskey

I would propose to mange the certificates using DNSSEC-infrastructure, see SD-DNS TXT-record features (service discovery DNS). For example: Fetching a signed Wasm from http://example.org/mod1.wasm, the corresponding DNS-TXT record of example.org would contain the corresponding cert for authentication, realising a chain of trust via DNSSEC from root '.' down to 'example.org'. Finally the wasm can be authenticated verifiying its signature the fetched cert via DNS-TXT record. Benefit: more or less static certificate hierarchy is managed by the directory-service called DNS, where DNSSEC establishing chain-of-trust, and incorporating DNS caching functionalities Drawback: it would be domain-centric, not HTTP-resource-centric. Should I elaborate this further?

frehberg avatar May 08 '19 21:05 frehberg

@frehberg That's an interesting idea -- thanks! I think this won't work for our immediate use case of hosting many packages on a single domain (https://www.wapm.io) because of the limited size of DNS TXT records, but it could be very useful to implement something more distributed! I'll keep it in mind, we've had a number of internal discussions about adding more distributed parts to wapm!

MarkMcCaskey avatar May 08 '19 22:05 MarkMcCaskey

Keep it simple for now. Revocation is hard to get right. It can always be implemented later.

The main concern users will immediately have in order to trust wapm: what happens if the wapm service itself gets compromised?

Even if this is a partial mitigation, the answer to that for a first version can be that the public keys are pinned, and if a new public key is advertised by the wapm service, accepting it requires a user interaction.

And if a key has been added manually, it will always require manual updates. Public keys don't have to be served only by wapm.io. They can be published on official projects websites.

jedisct1 avatar May 08 '19 22:05 jedisct1

@jedisct1, @frehberg:

We just published an article about Signed Packages and how you can use it with wapm: https://medium.com/wasmer/securing-wapm-packages-with-package-signing-3cf0d12f32f3

We really appreciate the time that both of you have taken on mentoring and guiding us through the process. Thanks! ❤️

PS: Let us know if you have more feedback or suggestions :)

syrusakbary avatar Jun 26 '19 07:06 syrusakbary