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

Package signing #52

Closed
jcspencer opened this Issue Aug 22, 2014 · 23 comments

Comments

Projects
None yet
5 participants
@jcspencer
Contributor

jcspencer commented Aug 22, 2014

As discussed on IRC (initially by laut). This is currently just a place for discussion, thoughts and ultimately a solution to the issue of signed packages.

@patrickdet

This comment has been minimized.

patrickdet commented Aug 22, 2014

@jcspencer

This comment has been minimized.

Contributor

jcspencer commented Aug 22, 2014

I think project-specific certificates are the way to go. I don’t think it would be particularly hard to create a CA-like system that issues certificates to individual projects or users who maintain these packages, but a certificate that signs the name (identity) of the package, and is in turn signed by a trusted root.

If I were really to try to run a CA for Hex, I would probably try to run it at the project level, and try to have a nontrivial burden of proof that you are the actual owner of a project, including things like OAuth to your Github account and confirming your identity over multiple channels.

reference

@ericmj

This comment has been minimized.

Member

ericmj commented Aug 22, 2014

First off, I think it would be particularly hard create a CA system ;). It would probably as hard, if not harder, than creating a package manager.

What does "run it at the project level" mean?

Running a CA under the same project as Hex would lose its purpose I think. A CA is used as a third-party to verify the ownership of a public key. It would also significantly add burden to me for sysadmin tasks as the CA would need to run independently of Hex.pm.

@jcspencer

This comment has been minimized.

Contributor

jcspencer commented Aug 22, 2014

I think a good reference implementation to look at in this case would be secureapt.

Key points:

  • Release file (contains checksums + bytesizes of every file except itself)
    • These two checksums allow apt to verify that it has downloaded a correct copy of the Packages file, with a checksum that matches the one in the Release file. And when it downloads an individual package, it can also check its checksum against the content of the Packages file. If apt fails at either of these steps, it will abort.
  • To plug the hole, secure apt adds a gpg signature for the Release file. This is put in a file named Release.gpg that's shipped alongside the Release file.
  • Secure apt always downloads Release.gpg files when it's downloading Release files, and if it cannot download the Release.gpg, or if the signature is bad, it will complain, and will make note that the Packages files that the Release file points to, and all the packages listed therein, are from an untrusted source.
  • So the security of the whole system depends on there being a Release.gpg file, which signs a Release file, and of apt checking that signature using gpg. To check the signature, it has to know the public key of the person who signed the file. These keys are kept in apt's own keyring (/etc/apt/trusted.gpg), and managing the keys is where secure apt comes in.
  • Note: that this key is only valid for a limited period. Debian occasionally rotates these keys as a last line of defense against some sort of security breach breaking a key.
  • One not so obvious gotcha is that if your clock is very far off, secure apt will not work. If it's set to a date in the past, such as 1999, apt will fail.

I think the main point here is that the users are required to have the correct private keys for each user, and that is external to APT.

Just some food for thought.

Also, just noting, this isn't necessarily something we need to add in a given time. This is simply a place to discuss some ideas 😄

@jcspencer

This comment has been minimized.

Contributor

jcspencer commented Aug 27, 2014

After doing some further research, we virtually need that following to sign and verify packages:

Signing

  1. Hash the tarball with a decent hashing algorithm
  2. Encrypt hash using signer's private key (in this case, the package uploader)
  3. Attach the Signature (signed hash) and Certificate to the tarball, thus forming our signed package.

Verifying

  1. Extract the data tarball, certificate and the signature from the package
  2. Hash the data tarball with the same algorithm as the server side
  3. Decrypt the signature using signer's public key
  4. If the hashes are equal and the certificate is valid, the signature is valid, thus the package is valid.

Conclusion

This would be entirely backward compatible, as well as optional, due to the fact that we're only adding files to the current packages. The fetching of the public keys of package maintainers is up to the users, and is not something Hex would or should be responsible for. This responsibility would be held externally, in a service such as Keybase.

This is the result of a little bit of brainstorming, so it is a little rough around the edges.

What are your thoughts on this? //cc @ericmj @josevalim

@jcspencer

This comment has been minimized.

Contributor

jcspencer commented Aug 27, 2014

Another point would be to consider also signing each package with a global certificate.

@jcspencer

This comment has been minimized.

Contributor

jcspencer commented Aug 27, 2014

In the example I expressed above, package maintainers (for example, @ericmj for hex) have the option to add public keys to their Mix.exs file, allowing users to enable public key/package integrity verification without having to manually traverse the dependency tree and find all required public keys.

@ericmj

This comment has been minimized.

Member

ericmj commented Aug 27, 2014

We do checksum packages and provide checksums for verification via the registry file. We just need to figure out how to fetch the registry file via HTTPS. This would verify the integrity of the package, but would not verify authorship.

A global certificate would not help to verify authorship.

We cannot provide public keys in the mix.exs file, public keys need to be provided outside the package. Otherwise I could just publish my own package with a new public key.

@jcspencer

This comment has been minimized.

Contributor

jcspencer commented Aug 28, 2014

If authors sign the checksum with their own private key (as described in my original comment), we can verify they published the package if the signature matches their public key (which is kept externally to hex).

A global certificate would not help to verify authorship, that's what the private key signature is for. The global certificate is simply another layer of security, to (again) not ensure authorship, but integrity.

I also think it's important we move the CDN to HTTPS to ensure registry integrity and prevent MITM attacks forging checksums.

The checksum signed with the users private key is used to verify authorship, and can be tested with the authors public key. This, however, does not ensure package integrity, thus why a combination of HTTPS and a global certificate are required.

@ericmj

This comment has been minimized.

Member

ericmj commented Aug 28, 2014

What extra security does the global certificate provide over checksum verification?

@jcspencer

This comment has been minimized.

Contributor

jcspencer commented Aug 28, 2014

If we sign the checksum is signed with a global certificate, we can verify that the returned checksum is the same as the one we checked with the global public key

@jcspencer

This comment has been minimized.

Contributor

jcspencer commented Aug 28, 2014

This verifies the package was signed with the global certificate

@ericmj

This comment has been minimized.

Member

ericmj commented Aug 28, 2014

I must be missing something. What security does verifying that the package was signed with the global certificate give us? All packages will be signed with the global certificate I would presume.

Verifying the package checksum against the checksum in the registry file should be enough to check integrity. We just need to ensure that we fetch the registry file with https so that it can't be tampered with.

@jcspencer

This comment has been minimized.

Contributor

jcspencer commented Aug 28, 2014

Ultimately, the signing of the checksum verifies that it is authentic

@ericmj

This comment has been minimized.

Member

ericmj commented Aug 28, 2014

Authentic how? You need to explain the difference in what I know about the package after it has been signed with a global certificate. If all packages are signed with the same certificate it makes no difference.

@jcspencer

This comment has been minimized.

Contributor

jcspencer commented Aug 28, 2014

My proposal is that we include 2 signatures in the packages. One of which is the checksum signed with the authors private key, and the other which is, again, the checksum, but this time it is signed by the global certificate. This verifies integrity, as well as authorship, both of which are important to check

@ericmj

This comment has been minimized.

Member

ericmj commented Aug 28, 2014

I agree with you on the first part, signing with the authors private key is necessary to verify authorship. But signing with a global certificate has no advantages over just verifying the checksum. It just adds unnecessary complexity.

The first step is to add proper integrity checks, the only thing left for that is to get https fully working. I'm closing this issue until #54 is done.

@ericmj ericmj closed this Aug 28, 2014

@jcspencer

This comment has been minimized.

Contributor

jcspencer commented Aug 28, 2014

That's a fair point. I'll look into how we can get #54 closed and verify the HTTPS SSL certificate.

@jcspencer

This comment has been minimized.

Contributor

jcspencer commented Sep 10, 2014

Ultimately, we can just sign a checksum by piping it into gpg --sign, and then to verify it, once we have the users public key imported that has been verified (where a service like keybase comes in handy), we can check this with gpg --verify.

@fertapric

This comment has been minimized.

fertapric commented Jul 13, 2018

In the light of recent events in npm, should this issue be reopened?

@ericmj

This comment has been minimized.

Member

ericmj commented Jul 13, 2018

This issue will be opened when we have an idea or an idea is proposed of how to solve it. I don't like keeping issues open that are not actionable so until we will keep it closed.

We don't know how the account was compromised so we don't know if signing would have helped.

npm had to revoke all of their tokens ever issued because the attacker could have extracted old token secrets with the tokens that were stolen during the ~12 hour window when the package was published. In Hex it is not possible to retrieve the token secret after the token has been created since we HMAC the secret, so Hex would have only needed to revoke issued during the 12 hour window.

@aronisstav

This comment has been minimized.

aronisstav commented Sep 7, 2018

I am also interested in this topic.

@ericmj I see that you have made a User signed packages proposal, without linking it here. Which place is the more appropriate to comment on?

(I updated this post after finding the proposal. In my defense (and shame), only today did I find the stackoverflow question, but I had seen this issue a while ago and wanted to work on this today.)

@ericmj

This comment has been minimized.

Member

ericmj commented Sep 7, 2018

Please make comments here because there are no notifications for comments on gists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment