Skip to content

Fixing old SHA1-infested OpenPGP keys

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!

Published inHow Tos

3 Comments

  1. Jon Jon

    I tried these commands and still I can’t sign keys. I’m using gpg 2.2.19. Any suggestions on where to look next?

  2. jeff jeff

    Hi,
    Thanks for your article, I know understand my problem 🙂
    However I did not manage to remove SHA1 algo from the list. It appears that gpg modify the algo list butt do not remove SHA1. It is like gpg was adding it by default.
    I tried in the interactive mode (non batch) to enter a list but gpg adds it ! (using ‘setpref SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed’ )
    Do you have an idea how to solve this?
    Jeff.

Leave a Reply

Your email address will not be published. Required fields are marked *