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

unable to force specific gpg subkey #1365

Closed
mammothbane opened this issue Dec 5, 2023 · 6 comments · Fixed by #1720 · May be fixed by #1522
Closed

unable to force specific gpg subkey #1365

mammothbane opened this issue Dec 5, 2023 · 6 comments · Fixed by #1720 · May be fixed by #1522

Comments

@mammothbane
Copy link

situation

I use sops to manage secrets for my projects, all using GPG for encryption.

I have a GPG master key with several encryption subkeys:

  • One on my YubiKey (oldest)
  • One on my desktop at home
  • One on my desktop at work (newest)

I just recently added the desktop and work subkeys, and am hoping to be able to configure sops to encrypt my secrets with all of these subkeys so that I can recover in the eventuality that I lose the YubiKey.

state of the world

As far as I understand:

  • sops shells out to gpg to encrypt/decrypt
  • When given a master key fingerprint to use for encryption, gpg will always use the newest encryption subkey
  • By default, any subkey fingerprint passed to gpg will cause it to lookup the master key first, then select an encryption subkey (which will always be the newest one per above)
  • It is possible to override this behavior by passing a specific subkey fingerprint followed by an exclamation mark (disables master key lookup and forces the use of the specified fingerprint)
  • sops truncates key fingerprints to 16 characters during encryption for compatibility reasons

As a result, it isn't possible to tell sops to use a specific key fingerprint, since for a keyid like 0123456789ABCDEF!, sops will produce 123456789ABCDEF! , which is rejected by gpg as malformed.

In my case, this means that everything sops encrypts that points at my gpg key can be encrypted only with my work encryption key, as it's the newest.

proof of concept

The following patch solves this problem for me and lets me specify an exclamation-mark fingerprint to sops:

diff --git a/pgp/keysource.go b/pgp/keysource.go
--- pgp/keysource.go
+++ pgp/keysource.go
@@ -625,9 +625,6 @@
 // shortenFingerprint returns the short ID of the given fingerprint.
 // This is mostly used for compatibility reasons, as older versions of GnuPG
 // do not always like long IDs.
 func shortenFingerprint(fingerprint string) string {
-	if offset := len(fingerprint) - 16; offset > 0 {
-		fingerprint = fingerprint[offset:]
-	}
 	return fingerprint
 }

proposed upstream

In shortenFingerprint, special-case strings with terminal !, chopping the string to 17 characters rather than 16, retaining the full key and the !. If amenable, I could PR this.

related

#808

@jflanglois
Copy link

jflanglois commented Dec 15, 2023

I ran into this specific issue yesterday! I have multiple subkeys for different devices so need a way to specify them. It seems to me like the behavior should be to try the long key first and fall back to shortening (or even just have users in those environments manually specify short ids). @hiddeco do you have more detail on which versions of gpg would barf on long fingerprints?

@Luflosi
Copy link

Luflosi commented Mar 10, 2024

I also ran into this problem.
I'm working around it with the above patch. Thanks @mammothbane!

tilpner added a commit to tilpner/sops that referenced this issue Jun 6, 2024
If shortening fingerprints, the trailing '!' from subkey fingerprints is removed,
and the wrong key is selected later on, potentially resulting in just-created secrets
not being decryptable.

Fixes getsops#1365
tilpner added a commit to tilpner/sops that referenced this issue Jun 6, 2024
If shortening fingerprints, the trailing '!' from subkey fingerprints is removed,
and the wrong key is selected later on, potentially resulting in just-created secrets
not being decryptable.

Fixes getsops#1365

Signed-off-by: tilpner <[email protected]>
tilpner added a commit to tilpner/sops that referenced this issue Jun 6, 2024
If shortening fingerprints, the trailing '!' from subkey fingerprints is removed,
and the wrong key is selected later on, potentially resulting in just-created secrets
not being decryptable.

Fixes getsops#1365

Signed-off-by: tilpner <[email protected]>
tilpner added a commit to tilpner/sops that referenced this issue Jun 14, 2024
If shortening fingerprints, the trailing '!' from subkey fingerprints is removed,
and the wrong key is selected later on, potentially resulting in just-created secrets
not being decryptable.

Fixes getsops#1365

Signed-off-by: tilpner <[email protected]>
@felixfontein
Copy link
Contributor

I tried debugging this. For me it seems that it does not matter whether the key ID is specified in short or long form - the actual key used one of the subkeys (it uses the last one in my latest test, I haven't paid attention to which exact one is used in my earlier tests). So in short: the fix described here and implemented in #1522 does not work for me.

But I can get it working when I append ! to the key ID. And then it doesn't matter whether the ID is short (last 16 hex digits) or long, it always picks exactly that subkey. It's easy to test if you run

echo foo | gpg --no-default-recipient --yes --encrypt -a -r '<keyid>' --trusted-key '<keyid>' --no-encrypt-to | gpg --decrypt

and look at what it says. If I try E8C7A229AC60EF08B53E65D6695FB2F519E20723 or 695FB2F519E20723 for <keyid>, I always get

gpg: encrypted with rsa1024 key, ID 17753C8CA633E0AB, created 2024-12-24
      "Felix Testkey <felix+testkey-main@localhost>"
foo

Here 17753C8CA633E0AB is the short key ID of another subkey. But if I use E8C7A229AC60EF08B53E65D6695FB2F519E20723! or 695FB2F519E20723! for <keyid>, then I get

gpg: encrypted with rsa1024 key, ID 695FB2F519E20723, created 2024-12-24
      "Felix Testkey <felix+testkey-main@localhost>"
foo

which uses the right subkey.

Now I'm wondering whether the behavior depends on the GnuPG version, and since when ! is supported/needed. (I also needed to use ! to actually export that exact subkey, to be able to re-import exactly a specific subkey and not all of them. By default, if you provide the ID of one subkey, it exports all... 🤷) I believe you that for some GnuPG versions passing the long (instead of the short) ID solves the problem, but apparently not for the latest version (2.4.7).

@felixfontein
Copy link
Contributor

Argh, it seems I missed the mention of 'exclamation mark' both in the PR and here. Sorry for the noise 🤦 But at least now I understand the problem a bit better...

@felixfontein
Copy link
Contributor

After some more tests, I agree that the solution proposed in the OP is the best solution:

proposed upstream

In shortenFingerprint, special-case strings with terminal !, chopping the string to 17 characters rather than 16, retaining the full key and the !. If amenable, I could PR this.

Simply removing the shortening as in #1522 would be better for modern versions of GnuPG, but since some (older?) verisons seem to have problems with the full fingerprint, sticking to a minimal change is best.

@felixfontein
Copy link
Contributor

I created #1720 to implement this.

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