How can we remove our expired keys from our keyring?
In this post I’m going to briefly cover how to purge all expired and revoked keys from your keyring using gpg2.
Tl;Dr
gpg2 --list-public-keys --with-colons | grep -a '^pub:[re]:' | cut -d : -f5 | xargs -l gpg --batch --yes --delete-keys
Prerequisite knowledge
If you’re reading this post I’m assuming your well-versed enough to be able to use pgp keys fluidly to encrypt and sign data.
If not, DON’T worry. I recommend checking out these two linoxide posts to get a more comprehensive guide on how to use gpg.
The Backstory
As you may know, working with pgp keys using gpg is a fairly seamless, barebones process. However, that may not always be a good thing.
As I was learning more about keyring maintenance earlier today, I realized I had way to me expired keys still hanging out in my keyring. I also noticed that NO WHERE in the dusty documentation was there a way to easily purge your keyring of invalid keys.
The most I could possibly do was utilize the gpg2 --list-public-keys --list-options show-unusable-uids
and delete them individually from there.
show-unusable-uids
Show revoked and expired user IDs in key listings. Defaults to no.
Not only would this be a tedious process if you haven’t been doing your regular cleaning, but I also found this command to be unreliable as it wouldn’t show me all of my invalid keys.
It may have had something to do with this bit of text that I also happened to stumble across in the dusty docs.
--with-colons
Print key listings delimited by colons. Note that the output will be encoded in UTF-8 regardless of any --display-charset setting. This format is useful when GnuPG is called
from scripts and other programs as it is easily machine parsed. The details of this format are documented in the file ‘doc/DETAILS’, which is included in the GnuPG source
distribution.
Interesting…
It turns out that the human readable format that we are used to seeing for a typical gpg public key output doesn’t play nice with the machine. Instead we need to convert our output into a “machine parseable” format.
In Other Words
We have to go from something like this:
gpg2 --list-public-keys
pub rsa4096 2015-01-05 [SC]
2D1771FE4D767DJSA6B089FAD655A4F21830E06A
uid [ expired ] John Doe <hisexpiredkey.com>
pub rsa4096 2012-11-15 [SC]
5B2DA4B9F9JFPB2019d1878102F77ACF3F48CB21
uid [ revoked ] Jane Doe <herexpiredkey.org>
sub rsa4096 2012-11-15 [E]
pub rsa4096 2022-04-17 [SC] [expires: 2023-04-12]
840391C6B5198E5BC46E29AE395DBDA8FA41644F
uid [ultimate] Al.exe (Based in Los Angeles if anyone wants to trade signatures.) <alEXE-tech@protonmail.com>
sub rsa4096 2022-04-17 [E] [expires: 2023-04-12]
To this:
gpg2 --list-public-keys --with-colons
uid:e::::1420483577::A4JFSYYYE957FE7F6D94F14069E9087E8A5FC4DA::John Doe <hisexpiredkey.com>::::::::::0:
pub:e:4096:1:ACC2602F3F4290SJLB21:1353005334:::-:::scESC::::::23::0:
fpr:::::::::B35B2DJFJ109F10949226F77ACC2602F3F48CB21:
uid:r::::1353005334::99A0C38FCCF794BF803B9E397F9DJ74389219594::Jane Doe <herexpiredkey.org>::::::::::0:
pub:r:4096:1:4F75939930498E2ADJDJ:13523215334::::::e::::::23:
fpr:::::::::73471302917A6769JJSJJKSK4F75939930498E2A:
uid:u::::1650178921::2BA40199B357A5BA344476AA186305F77F6CBF63::Al.exe (Based in Los Angeles if anyone wants to trade signatures.) <alEXE-tech@protonmail.com>::::::::::0:
sub:u:4096:1:FEF4CDCAD14A38FD:1650178921:1681282921:::::e::::::23:
fpr:::::::::7BA9BD9DEE25951A626DF556FEF4CDCAD14A38FD:
Quite a disgusting bit of output if you ask me. But if it helps us get the job done then so be it. More details on how to interpret this nonsense can be viewed here
The Command
After scouring the internet for a couple hours I managed to stumble across this old debian-security thread that had the piped command chain to do our job.
gpg2 --list-public-keys --with-colons | grep -a '^pub:[re]:' | cut -d : -f5 | xargs -l gpg --batch --yes --delete-keys
Let me quickly break down some of the important details for you all.
First we are going to list our public keys like I previously showed you. We are then piping that into grep so we will only target the public keys (pub), that are either revoked(r) or expired(e).
pub:e:4096:1:ACC2602F3F4290SJLB21:1353005334:::-:::scESC::::::23::0:
pub:r:4096:1:4F75939930498E2ADJDJ:13523215334::::::e::::::23:
We then utilize the cut
command to separate our line sections by colons and remove all columns, EXCEPT the 5th column (or field).
ACC2602F3F4290SJLB21
4F75939930498E2ADJDJ
From there, it’s just a matter of running gpg --delete-keys
on a batch of keys.
Conclusion
GnuPG does one job, and it does that job right! Unfortunately, it can be a bit of a headache at times.
Thanks for Reading! :>
– Al.exe