I recently created a new OpenPGP key for my Apache (ASF) account. Of course I wanted to sign it with my existing GnuPG key I have since 2007. To my surprise, it failed with these error messages:
gpg: Note: third-party key signatures using the SHA1 algorithm are rejected gpg: signing failed: Invalid digest algorithm gpg: signing failed: Invalid digest algorithm
It took me a few hours to figure out what’s wrong. Obviously something with SHA1, but GnuPG doesn’t tell you WHAT is wrong and HOW to fix it.
The symptom: Keys containing SHA1-Packets
Between 2009 and 2012, when SHA1 was still accepted (and mandatory for GnuPG, although it had first cracks), I wrote a few pages about how [not] to configure GnuPG even more securely (or so I thought).
I included options like export mode, disabled some stuff like photos, enabled dsa2 (new at that time) etc.
Sadly, as time passed, I never reverted those options to the default. If I did, prolonging my key would have cleaned my key from SHA1 self-signatures and other SHA1 packets because the defaults changed.
Lessons learned: I will now stick to the default settings more closely and configure only obvious things like the keyserver url, displaying the whole fingerprint, disabling auto-key-locating and enabling clean on import.
Analyzing if your key is affected
Symption 1: You cannot sign keys anymore
If you try to sign a key and this happens, you might be affected:
(user@host)[~]$ gpg --sign-key bmarwell@apache.org
sec ed25519/111133334567ABCD
created: 2020-11-20 expires: 2027-11-19 usage: SC
trust: ultimate validity: ultimate
[ultimate] (1). Bob Brick <bob@brick.invalid>
sec ed25519/111133334567ABCD
created: 2020-11-20 expires: 2027-11-19 usage: SC
trust: ultimate validity: ultimate
Primary key fingerprint: 0000 2222 4444 6666 8888 AAAA 1111 3333 4567 ABCD
Bob Brick <bob@brick.invalid>
This key is due to expire on 2027-11-19.
How carefully have you verified the key you are about to sign actually belongs
to the person named above? If you don't know what to answer, enter "0".
(0) I will not answer.
(1) I have not checked at all.
(2) I have done casual checking. (default)
(3) I have done very careful checking.
Your selection? (enter '?' for more information): 3
Are you sure that you want to sign this key with your
key "Adam Average <adam@average.invalid>" (826D3E320E691DD1)
I have checked this key very carefully.
Really sign? (y/N) y
gpg: Note: third-party key signatures using the SHA1 algorithm are rejected
gpg: signing failed: Invalid digest algorithm
gpg: signing failed: Invalid digest algorithm
Key not changed so no update needed.
Symptom 2: Check it’s packets
To check for SHA1 sigs, you need to use gpg’s --list-packets
. As it will only analyse binary or armored gpg files, you need to export the key first. Then, look for digest algorithm SHA1 (id 2) like so:
gpg --export <key-fingerprint> | gpg --list-packets | grep -B2 "digest algo 2"
If you see your key ID on the far right end of the "signature" lines (two lines before digest algo, hence the -B2
), your key is polluted with self-signed SHA1 sigs. If it is not your key ID, you can just clean your key. On no output: You shouldn’t be here, you are not affected. 😉
Cleaning the key
Now is a good time to make a backup and also test your restore abilities.
Step 1: Checking your gpg.conf
If you use GnuPG 2.2 or higher, you just need to make sure you do not include any of the following options in your $HOME/.gnupg/gpg.conf
file:
weak-digest
default-preference-list
personal-cipher-preferences
personal-digest-preferences
personal-compress-preferences
digest-algo
cert-digest-algo
If you use GPG <= 2.1.x, then set these options explicitly to not include SHA1. As I have given bad suggestions in the past, look up on the internet a good setting.
Step 2: Re-set your expiry date
You can skip this test if you have no digest algo 2
signature with your own key ID from the previous step.
Even if you haven’t set an expiry date, this step will make to re-set the expiry (either by re-typing the same exact date, setting a new interval or setting 0=never again).
# if you had 'never'
gpg --quick-set-expire <key-fingerprint> 0 '*'
# if you want to set it to the same date, here: Nov 1st, 2020
gpg --quick-set-expire <key-fingerprint> 2022-11-01 '*'
# if you want to set it to a new interval from now, here: 5y
gpg --quick-set-expire <key-fingerprint> 5y '*'
The trailing '*'
is important, including the single quotes. It will make the expiry apply to all subkeys if you have multiple.
Step 3: Cleaning your key
Now it is time to actually update your key’s preferences and remove all the unwanted SHA1 signatures, whether they are your own old SHA1 signatures or third-party signatures. This is also a one-liner.
# update the preferences on your key, then
# clean your key: get rid of expired and/or invalid (SHA1) sigs
gpg --batch --yes --edit-key <key-fingerprint> setpref clean quit
Step 4: Send your keys to the keyservers (optional)
Now it is time to publish your new key if you want to:
# publish to the keyservers
gpg --keyserver keys.gnupg.net --send-keys <key-fingerprint>
Conclusion
After four simple steps, you can now use your GnuPG-Key again to sign other keys.
(user@host)[~]$ gpg --sign-key bmarwell@apache.org
sec ed25519/111133334567ABCD
created: 2020-11-20 expires: 2027-11-19 usage: SC
trust: ultimate validity: ultimate
[ultimate] (1). Bob Brick <bob@brick.invalid>
sec ed25519/111133334567ABCD
created: 2020-11-20 expires: 2027-11-19 usage: SC
trust: ultimate validity: ultimate
Primary key fingerprint: 0000 2222 4444 6666 8888 AAAA 1111 3333 4567 ABCD
Bob Brick <bob@brick.invalid>
This key is due to expire on 2027-11-19.
How carefully have you verified the key you are about to sign actually belongs
to the person named above? If you don't know what to answer, enter "0".
(0) I will not answer.
(1) I have not checked at all.
(2) I have done casual checking. (default)
(3) I have done very careful checking.
Your selection? (enter '?' for more information): 3
Are you sure that you want to sign this key with your
key "Adam Average <adam@average.invalid>" (826D3E320E691DD1)
I have checked this key very carefully.
Really sign? (y/N) y
(user@host)[~]$
Sweet! 😊
References
This article is loosely based on the article of heise.de Aufpoliert: Alte PGP-Schlüssel mit neuen Signaturen. I changed the commands to non-interactive, use different explanations and separated the steps into their own headings, marking the second step as optional.
It is a shame that this article was not available in English before, not even on the GnuPG website!
I hope it helps you and κῦδος to heise.de for their great article!