90

My gnupg keyring contains hundreds of unnecessary entries. How would I remove the expired, revoked and unsigned keys from it?

I would like to keep the keys that have signed my key, and import new keys only as required. I'd previously imported the entire web of trust for my key's signatories. It would seem that one of my key signers has picked up a very large number of signatures in his travels, and these are now clogging up my keyring.

scruss
  • 1,097

5 Answers5

83

From Charles Lockhart’s GPG Cheat Sheet:

I've used User Name as being the name associated with the key.  Sorry that isn't very imaginative.  I think gpg is pretty wide in its user assignments, e.g., the name for my private key is “Charles Lockhart”, but I can reference that by just putting in “Lockhart”.  That doesn't make any sense, sorry.

            ︙

to delete a public key (from your public key ring):

$ gpg --delete-key "User Name"

This removes the public key from your public key ring.
NOTE: If there is a private key on your private key ring associated with this public key, you will get an error! You must delete your private key for this key pair from your private key ring first.

to delete a private key (a key on your private key ring):

$ gpg --delete-secret-key "User Name"

This deletes the secret key from your secret key ring.

MelBurslan
  • 1,394
20

The man page of gpg advises against parsing the normal output of --list-keys but it offers parseable output with --with-colons.

This removes all public keys that are expired or revoked:

gpg --list-keys --with-colons \
  | awk -F: '$1 == "pub" && ($2 == "e" || $2 == "r") { print $5 }' \
  | xargs gpg --batch --yes --delete-keys

How does it work?

  1. tell gpg to output keys in a parsable format (the docs for this format are a little hidden: the man page says they are in doc/DETAILS in the source, my distro installed them in /usr/share/doc/gunpg/DETAILS)
  2. tell awk to use colon as field delimiter: -F:
  3. only select lines where the first field is "pub", these are public keys
  4. only select lines where the second field is either "e" or "r", these are revoced or expired keys
  5. print only field five of the selected lines, that is the key id
  6. use xargs to hand the lines to gpg and delete them
Lucas
  • 301
9

I have a bash script scheduled to run weekly from cron to handle this:

#!/bin/bash
# Clean up the GPG Keyring.  Keep it tidy.
# blog.lavall.ee

echo -n "Expired Keys: " for expiredKey in $(gpg2 --list-keys | awk '/^pub.* [expired: / {id=$2; sub(/^.*//, "", id); print id}' | fmt -w 999 ); do echo -n "$expiredKey" gpg2 --batch --quiet --delete-keys $expiredKey >/dev/null 2>&1 if [ $? -eq 0 ]; then echo -n "(OK), " else echo -n "(FAIL), " fi done echo done.

echo -n "Update Keys: " for keyid in $(gpg -k | grep ^pub | grep -v expired: | grep -v revoked: | cut -d/ -f2 | cut -d' ' -f1); do echo -n "$keyid" gpg2 --batch --quiet --edit-key "$keyid" check clean cross-certify save quit > /dev/null 2>&1 if [ $? -eq 0 ]; then echo -n "(OK), " else echo -n "(FAIL), " fi done echo done.

gpg2 --batch --quiet --refresh-keys > /dev/null 2>&1 if [ $? -eq 0 ]; then echo "Refresh OK" else echo "Refresh FAIL." fi

dessert
  • 263
4
% gpg --edit-key KEYID
gpg> clean
User ID [...]: 139 signatures removed
gpg> save
% gpg --version
gpg (GnuPG) 1.4.18
[...]
fche
  • 198
1
#!/bin/bash
echo -n "Expired Keys: "
list_expired_keys="$(gpg2 --list-keys | grep -1 pub | sed 'N;s/\n/ /' | awk '/^pub.* \[expired\: / {id=$7; sub(/^.*\//, "", id); print id}' | fmt -w 999)";
list_revoked_keys="$(gpg2 --list-keys | grep -1 pub | sed 'N;s/\n/ /' | awk '/^pub.* \[revoked\: / {id=$7; sub(/^.*\//, "", id); print id}' | fmt -w 999)";
for key in $list_expired_keys $list_revoked_keys; do
    echo -n "$key"
    gpg2 --batch --quiet --delete-keys $key >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo -n "(OK), "
    else
        echo -n "(FAIL), "
    fi
done
echo done.

here is a bash-script doing the job. It is an adaption of https://superuser.com/a/859739 for gpg2 where the key id is in the second line.

dessert
  • 263
Brian
  • 11