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

Checking that we trust recipients breaks GPG's web of trust model #26

Open
bruntonspall opened this issue Apr 10, 2015 · 1 comment
Open

Comments

@bruntonspall
Copy link

The code at https://github.com/sihil/hiera-eyaml-gpg/blob/master/lib/hiera/backend/eyaml/encryptors/gpg.rb#L129-L138 checks whether the recipients that we are encrypting to are listed as having full validity within the web of trust.

This breaks the concept of the web of trust, since it conflates whether a recipient is who they say they are, and whether you trust a key to sign other keys.

I understand that this was done in order to check that an attacker had not added their own key to the list of recipients, and this is a valid attack to be concerned about, but the trust model is the wrong tool to solve that problem.

The issue that this gives for us is:

  1. We distribute passwordless keys to various public servers, for different stages.
    We are happy to encrypt to those keys, if somebody can possess that key they can decrypt the relevant parts of the context. That's a risk model that we already take with puppetmaster's anyway.
    However we are not happy to trust those keys to perform encryption or signing. If somebody can possess one of those keys and sign their own key with it, we don't want to trust the new key. If somebody uses one of those keys to write a new encrypted blob to out git repository we don't want to trust that block
    We only trust the human managed keys where we have confidence that the person will follow reasonable measures before signing another persons key
  2. Even worse, we have a developer passwordless key that we publish as part of our public repo.
    This key is used in vagrant builds to apply known compromised credentials (such as user DB, password: password) to developer machines. We know that key is publicly accessible, and we deliberate set the trust as NEVER for our GPG implementation, so we know that the key cannot ever be trusted to sign or encrypt anything.

Currently, the implementation we have here requires all of the team to trust that compromised key, or to set the always trust option, defeating the point of us setting up a web of trust.

I believe the correct solution here is probably:

  1. Remove the check for whether the recipients are trusted.
  2. To combat the original attack, the recipients list should be signed, and the tool should attempt to verify the signature before using it. The file should only verify the signature if the signing key is trusted, so it proves that a human you trust has modified the recipients list and correctly signed it. Manual recipient lists should work as before.
  3. You probably need a parameter to skip verifying the signature, to allow for upgrades and for users who choose not to use the recipient list signing function (always-trust maybe)
  4. the decrypt function should probably check that the encrypted contents are signed by someone on the web of trust. I believe this is the default in GPGME (sign and encrypt, decrypt and verify). The passwordless keys on the puppetmaster should trust either each member of staff, or a master key that trusts each member of staff (giving a proper web of trust). Only files encrypted by a trusted key should be accepted.
@sihil
Copy link
Collaborator

sihil commented Apr 13, 2015

Hmmm. Tricky.

The code you refer to checks for the validity of keys solely in order to provide a more helpful error message than that returned by the GPG library (notably, specifying which of the keys isn't trusted). You can double check, but I'm pretty sure that removing the check will simply replace the error with another more cryptic message directly from the GPG call here (note that we also pass in the always_trust parameter to this call): https://github.com/sihil/hiera-eyaml-gpg/blob/master/lib/hiera/backend/eyaml/encryptors/gpg.rb#L141

It might be that GPGME::VALIDITY_FULL is too high and the latter call would pass with lower validity levels. However, fundamentally all I'm doing in this code is wrapping the existing behaviour of GPG which is tripping you up here due to GPG being designed only for human->human communication and not really designed for communication with machines - in which I agree the human->human web of trust

GPG does have separate concepts of trust and validity. The former being the level of trust in the owner of a key and the latter being the confidence in a given encryption or signing key. I haven't used it enough, but it might be possible that there are ways of saying a key is valid without trusting it.

One alternative is to have a whitelist of valid keys that are not validity checked. Any key not on the whitelist is checked by the code that is there and we always pass in always_trust=true to the main GPG call.

If you can build the model you are after with the GPG CLI then I'm happy to tweak the implementation or accept a PR. However, I have a hunch that you are trying to change how the GPG library works.

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

No branches or pull requests

3 participants