GnuPG treats reordered OpenPGP certificates differently
Open, LowPublic

Description

Anyone can reassemble an OpenPGP certificate into a different order.

The two attached OpenPGP certificates contain the same OpenPGP packets, but the user IDs are present in a different order:


But importing them into clean GnuPG homedirs shows different primary key validity and different primary key usage flags:

$ for x in alice alice-reordered ; do mkdir -m 0700 $x; gpg --homedir=$x --import $x.key; gpg --homedir=$x --list-keys; done
gpg: keybox '/home/dkg/alice/pubring.kbx' created
gpg: /home/dkg/alice/trustdb.gpg: trustdb created
gpg: key 3CB7A19683B428D1: public key "<alice.jones@example.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1
/home/dkg/alice/pubring.kbx
------------------------------------------------------------
pub   rsa3072 2020-03-12 [C] [expires: 2025-03-11]
      7138FE5EB6895581ED99E3AD3CB7A19683B428D1
uid           [ unknown] <alice.jones@example.com>
uid           [ unknown] <alice@example.net>
sub   rsa3072 2020-03-12 [E]

gpg: keybox '/home/dkg/alice-reordered/pubring.kbx' created
gpg: /home/dkg/alice-reordered/trustdb.gpg: trustdb created
gpg: key 3CB7A19683B428D1: public key "<alice.jones@example.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1
/home/dkg/alice-reordered/pubring.kbx
----------------------------------------------------------------------
pub   rsa3072 2020-03-12 [SC] [expires: 2022-03-12]
      7138FE5EB6895581ED99E3AD3CB7A19683B428D1
uid           [ unknown] <alice.jones@example.com>
uid           [ unknown] <alice@example.net>
sub   rsa3072 2020-03-12 [E]

$ 

I'm not clever or malicious enough see an immediate attack vector in this ambiguity, but i can certainly imagine it being an accidental maintenance problem.

For example, imagine Bob and Carol both have Alice's certificate, but Bob received alice.key and Carol received alice-reordered.key.

On 2022-03-13, Carol says to Bob "hey, do you have Alice's OpenPGP certificate, my copy is expired". Bob says "sure, the copy i've got is good for a few more years, here you go." Carol imports Bob's copy, but her expiration date doesn't change.

Outside of Alice, Bob, and Carol, this makes me worry about the sustainability of the review process for critical keyrings, like the debian keyring.

(i discovered the above while writing up a suggestion for a new test for an OpenPGP linter)

Details

Version
2.2.19
dkg created this task.Mar 12 2020, 8:01 PM
dkg updated the task description. (Show Details)Mar 12 2020, 8:29 PM
werner triaged this task as High priority.Mar 13 2020, 5:33 PM
werner claimed this task.
werner added a project: OpenPGP.
werner lowered the priority of this task from High to Low.Mar 16 2020, 1:04 PM

It is easy to explain:

/* Find the latest valid user ID with a key expiration set

All the self-signatures can carry information pertaining to the key, for example the expiration date. We use the latest one but iff both user-ids and their self-signatures are created at the the same time (here 2020-03-12 17:26:30), we can't decide which to use and the code picks the first one. We simply can't decide what was meant.

So if we want to get a stable search order we could implement some strategy for this corner case:

  1. Use the earliest expiration time
  2. Use the latest expiration time.
  3. Sort the user ids.

If we really want to handle this I would like to use case 3 because that would be consistent with possible other information in several self-signatures.