Page MenuHome GnuPG

Keyring/keybox denial of service
Closed, ResolvedPublic

Description

If an adversary is able to insert or update any OpenPGP certificate stored in the victim's GnuPG's keyring (or keybox), the adversary can prevent the victim from subsequently importing any certificate of their choosing.

This appears to be the case with or without use-keyboxd on gpg 2.4.7. I have not tested any other version.

For example, if the user can be convinced to import the OpenPGP certificate blocker.cert (attached here), then a future attempt to import any of the keys shipped in /usr/share/gnupg/distsigkey.gpg will fail.

Below is a transcript of this process without use-keyboxd enabled, but the same concern seems to apply with use-keyboxd as well.

0 dkg@bob:~$ gpg --import blocker.cert 
gpg: keybox '/home/dkg/.gnupg/pubring.kbx' created
gpg: /home/dkg/.gnupg/trustdb.gpg: trustdb created
gpg: key 686B3732F1BA1156: public key "This is a dangerous certificate" imported
gpg: Total number processed: 1
gpg:               imported: 1
0 dkg@bob:~$ gpg --list-keys
/home/dkg/.gnupg/pubring.kbx
--------------------------------------------------------
pub   ed25519 2025-02-10 [SCA]
      9547A24942568307926B6ECB686B3732F1BA1156
uid           [ unknown] This is a dangerous certificate
sub   rsa3072 2017-03-17 [E]
sub   ed25519 2020-08-24 []
sub   ed25519 2021-05-19 []
sub   brainpoolP256r1 2021-10-15 []

0 dkg@bob:~$ gpg --import /usr/share/gnupg/distsigkey.gpg  
gpg: key BCEF7E294B092E28: 1 signature not checked due to a missing key
gpg: key BCEF7E294B092E28: doesn't match our copy
gpg: key 528897B826403ADA: 4 signatures not checked due to missing keys
gpg: key 528897B826403ADA: doesn't match our copy
gpg: key E98E9B2D19C6C8BD: 2 signatures not checked due to missing keys
gpg: key E98E9B2D19C6C8BD: doesn't match our copy
gpg: bad key signature from key 528897B826403ADA: Wrong key usage (0x10, 0x0)
gpg: key 549E695E905BA208: 1 signature not checked due to a missing key
gpg: key 549E695E905BA208: 1 bad signature
gpg: key 549E695E905BA208: doesn't match our copy
gpg: Total number processed: 4
2 dkg@bob:~$ gpg --list-keys
/home/dkg/.gnupg/pubring.kbx
--------------------------------------------------------
pub   ed25519 2025-02-10 [SCA]
      9547A24942568307926B6ECB686B3732F1BA1156
uid           [ unknown] This is a dangerous certificate
sub   rsa3072 2017-03-17 [E]
sub   ed25519 2020-08-24 []
sub   ed25519 2021-05-19 []
sub   brainpoolP256r1 2021-10-15 []

0 dkg@bob:~$

This DoS against the user's keyring affects the ability to verify signatures made from these signing keys. I think the same kind of keyring DoS could be used to prevent importing a certificate for encrypting a message to someone, but I have not crafted such a demonstration.

That said, use-keyboxd might also be an aggravating factor, since at least without use-keyboxd the user can offer --no-default-keyring and --keyring=/usr/share/gnupg/distsigkey.gpg. But those options don't have any effect once use-keyboxd is in play, as per T7265.

Details

Version
2.4.7

Event Timeline

To be clear about what's going on here, blocker.cert has simply adopted the primary keys of each certificate found in /usr/share/gnupg/distsigkey.gpg -- i think GnuPG requires each component key in its keystore to have a unique fingerprint across all component keys in the keystore. so when one certificate claims those fingerprints as subkeys, any certificate that has a primary key with a matching fingerprint gets rejected with doesn't match our copy.

werner added a subscriber: werner.

That is not a new issue. We have the very same issue since ever. However, without keyboxd you had random results depending on the order of the keys in the keyring.

Nevertheless this needs to be addressed.

werner changed the task status from Open to Testing.Tue, Feb 11, 2:57 PM

The actual cause here was that right before storing the imported key we need to decide whether to insert or update a keyblock. For this we need to lookup the key in our database and the lookup function does the usual thing by looking at any fingerprint. This is wrong: Here we need to lookup only by primary fingerprint. This is what the above patches do.

werner claimed this task.

I don't think this is fixed. With this patch in place, if i import blocker.cert first, and then import distsigkey.gpg, it looks to me like i still can't verify signatures made from any of the GnuPG signing keys.

In particular, i see:

0 dkg@bob:~$ gpg --verify gnupg-2.5.4.tar.bz2.sig gnupg-2.5.4.tar.bz2
gpg: Signature made Wed 12 Feb 2025 05:53:38 AM EST
gpg:                using EDDSA key 6DAA6E64A76D2840571B4902528897B826403ADA
gpg: bad data signature from key 528897B826403ADA: Wrong key usage (0x00, 0x0)
gpg: Can't check signature: Wrong key usage
2 dkg@bob:~$

Likewise, if i try to edit the certificate (e.g. to set ownertrust, or to make a local certification), gpg appears to select the wrong one.

So, it looks to me like the denial of service against those keys persists.

the reproducer is:

export GNUPGHOME=$(mktemp -d)
gpg --import blocker.cert
gpg --import /usr/share/gnupg/distsigkey.gpg
wget https://gnupg.org/ftp/gcrypt/gnupg/gnupg-2.5.4.tar.bz2{,.sig}
gpg --verify gnupg-2.5.4.tar.bz2{.sig,}

Sorry. I can't reproduce this. Neither with master nor with the 2.4 repo version.

Okay, I can reproduce it when not using keyboxd.

Well, the different outcome depends on the order of the certificates or the string comparision in keyboxd. So it is not a keyboxd vs. pubring.kbx thing.

The real cause here is that you removed the backsigs from the signature subkeys and also did not mark the subkey as signing key. Thus the backsig was not checked. After disabling the early check for the key usage we see this:

gpg: assuming signed data in 'gnupg-2.5.4.tar.bz2'
gpg: Signature made Wed 12 Feb 2025 11:53:38 AM CET
gpg:                using EDDSA key 6DAA6E64A76D2840571B4902528897B826403ADA
gpg: bad data signature from key 528897B826403ADA: Wrong key usage (0x00, 0x0)
gpg: WARNING: signing subkey 528897B826403ADA is not cross-certified
gpg: please see https://gnupg.org/faq/subkey-cross-certify.html for more information
gpg: Can't check signature: General error

So no real harm here. However, the broken key still inhibits the use of the correct key. A solution for this is to skip the key during selection on the ground of a bad key usage or a broken backsig.

werner lowered the priority of this task from High to Normal.Fri, Feb 21, 12:18 PM

This has been fixed in master with rG48978ccb4e:

ppg: assuming signed data in 'gnupg-2.5.4.tar.bz2'
gpg: Signature made Wed 12 Feb 2025 11:53:38 AM CET
gpg:                using EDDSA key 6DAA6E64A76D2840571B4902528897B826403ADA
gpg: using pgp trust model
gpg: Good signature from "Werner Koch (dist signing 2020)" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
      6DAA6E64A76D2840571B4902528897B826403ADA
gpg: binary signature, digest algorithm SHA512, key algorithm ed25519