It’s that time of the year again… Let’s renew our subkeys!

Checking for an expired subkey

GPGs messages are not that clear when a subkey expires. For example, Git may refuse to sign a commit with the cryptic message gpg failed to sign the data. Or the journal logs a message gpg-agent[54444]: command 'PKSIGN' failed: No secret key.

To check for an expired subkey use these commands:

# List all secret keys, there should be one line for your master key 
gpg -K

# Edit the masterkey, this brings up the gpg console
gpg --edit-key <MASTERKEYID>
# List all subkeys
> list
# There should be one line that says `expired`

Renewing the expired subkey

Following good practice, I use a single offline master key without expiration date and multiple subkeys for signing and encryption. See here on how to set that up.

The subkeys are configured to expire annually. If everything was kept save, the expiration date can be changed without creating a new subkey. Use these commands on your (hopefully offline) master GPG home:

# Edit the masterkey, this brings up the gpg console
gpg --home=path/to/offline/home --edit-key <MASTERKEYID>
# List all subkeys
# Select the subkey to renew, <n> is the number of the subkey in the list
>key <n>
# Now the subkey should be marked with an asterisk *.
# Set a new expiration date
# Save the changes and close the console

Exporting/Importing the updated key

The subkey must now be transferred from the offline location to every computer that uses the subkey.

Run the following command to export the subkey into subkey.key then copy that file to your computers.

# Export the secret subkey, note the ! after the id
gpg --home=path/to/offline/home --armor --export-secret-subkeys <SUBKEYID>! > subkey.key

To import the key, run this command:

# Import the key
gpg --import subkey.key

# If you transfer keys between Windows and Unix you may get
# gpg: [don't know]: partial length invalid for packet type 63
# This can be fixed by converting the line endings with dos2unix
dos2unix subkey.key

# Make sure the private key of your master key was NOT transferred by running
gpg -K
# and checking that the line for your master key says `sec#` and not `sec`.

Do not forget to update/republish your public key, for example on GitHub or GitLab. Since the same key is reused, you first have to delete the old version of the key and then re-upload the new version in the GitHub/GitLab settings.

# Export the public key with
gpg --armor --export <MASTERKEYID>