Ubuntu: fixing apt invalid signature warnings

If you have warning messages coming from apt about an invalid signature verification and EXPKEYSIG, then it is likely that a signing key for one of the remote apt repo has expired.

Below is an example coming from an expired podman package at the “download.opensuse.org” repo.

W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_20.04  InRelease: The following signatures were invalid: EXPKEYSIG 4D64390375060AA4 devel:kubic OBS Project <devel:kubic@build.opensuse.org>
W: Failed to fetch http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_20.04/InRelease  The following signatures were invalid: EXPKEYSIG 4D64390375060AA4 devel:kubic OBS Project <devel:kubic@build.opensuse.org>

Using the hex value from the warning message, prepare a variable for our upcoming commands.

# value pulled from warning message EXPKEYSIG
hexid=4D64390375060AA4

# install package for decoding PGP
sudo apt install pgpdump -y

Deprecation of centralized system keyring

Before you follow this article, it is important to understand that the centralized system keyring was deprecated starting in Ubuntu 21 (but is still available in Ubuntu 22).

The legacy implementation had the trusted system keyring file at “/apt/trusted.gpg” or multiple files in “/apt/trusted.gpg.d/”.  The primary issue was that a PGP key added to this file or directory would mean that apt trusted any package coming from any location, as long as it referenced any of these keys.  This was a security risk.

The new implementation is that individual keys are placed into their own file in the “/usr/share/keyrings/” directory.  The apt repo definition files (in /etc/apt) each use a ‘signed-by’ attribute to reference the local file path pointing to a specific key.  This makes the trust explicit, with each remote repo trusting a specific individual key.

As a concrete example of the recommended implementation, below is the apt repo definition found at “/etc/apt/sources.list.d/github-cli.list” for the github CLI apt repo.  Notice the ‘signed-by’ attribute referring to a specific local key.

deb [arch=amd64 signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main

Verify local expired PGP key

Option #1: For deprecated trusted keyring

If your system is still using the deprecated system keyring, then apt-key can be used to view the expiration.

# show ownership and expiration date from local keyring
apt-key export $hexid 2>/dev/null | pgpdump | grep -E "User ID -|expiration" -A1

# will also confirm owner and expiration date from local keyring
apt-key list | grep -i "${hexid: -8:4} ${hexid: -4}" -C3

Option #2: For independent key files

If the apt repo file definition is using the recommended ‘signed-by’, then you can view each expiration.

# view path locations of PGP keys, ignore '.save' which are backup files
sudo grep -sr "signed-by" /etc/apt | grep -v save

# get all PGP path locations
pgp_paths=$(sudo grep -srl "signed-by" /etc/apt | grep -v save | xargs cat | grep -Po 'signed-by=\K([^\]" ])*')

# view expiration dates of PGP files
sudo apt install pgpdump -y
for f in $pgp_paths; do echo;echo "==$f"; pgpdump $f | grep -E "User ID -|expiration" -A1; done

Find newest PGP key

The developers of the package should have provided the newest PGP key by either:

  1. Uploading the new PGP key to the web-accessible apt repo; you can perform a manual web search for the apt key
  2. Uploading the PGP key to a central keyserver such as keyserver.ubuntu.com; you can query the keyserver for the apt key

Option #1: New PGP key available on package web site

The naming of the PGP keys for each web-accessible apt repo is not standardized, so I find the easiest discovery method is to manually point your browser at the search engine duckduckgo.com and search the site mentioned in the warning for a PGP public key marker (Google does not find these files as accurately).

Here is an example using our original example of the podman key from opensuse.

site:download.opensuse.org apt “BEGIN PGP PUBLIC KEY BLOCK”

Copy and paste this location into a variable value like below to prepare for the next section.

# define variable based on only search result
remote_key_file=https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_22.04/Release.key

As another example, here is the search expression to find the Google gcloud and kubectl keys.

site:packages.cloud.google.com apt “BEGIN PGP PUBLIC KEY BLOCK”

# define variable based on top search result from above
remote_key_file=https://packages.cloud.google.com/apt/doc/apt-key.gpg.asc

Option #2: New PGP key available on central keyserver

The developers of the package may have uploaded the newest PGP key to a central keyserver such as keyserver.ubuntu.com.  You can use the ‘hexid’ value from the sections above to search the keyserver site.

echo "going to search for: $hexid"
curl -fs "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x${hexid}" | pgpdump | grep -E "User ID -|expiration" -A1

If the expiration date is exceeded, then you cannot use this key.  You are probably not the first to hit this problem, search the issues logs of the specific project and log an issue if necessary.

However, if the PGP key’s expiration is newer (or expiration does not exist), then you can define the variable value like below to prepare for the next section.

remote_key_file="https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x${hexid}"

Have apt trust the PGP key

Now that you have correctly identified the ‘remote_key_file’ location, you can have apt trust this key in one of two ways.

Option #1: Legacy method of adding to system trusted keyring

This method is deprecated as of Ubuntu 21, but ‘apt-key’ can still be used to add the key to your system’s trusted keyring.  This actually makes the key trusted by any and all apt repository, which is a driving factor in its deprecation.

# validate same ownership as original, and newer expiration date
curl -s $remote_key_file | pgpdump | grep -E "User ID -|expiration" -A1

# add new key
curl -s $remote_key_file | sudo apt-key add -

# validate warning message is no longer thrown
sudo apt update

Option #2: Recommended method of ‘signed-by’ for each apt repo

The recommended method of trust is to add a ‘signed-by’ parameter in the apt repo definition file pointing at a local key path.  This ties a specific repo to a specific key and is therefore more secure.

The commands below use our original example from ‘download.opensuse.org’

# validate same ownership as original, and newer expiration date
curl -s $remote_key_file | pgpdump | grep -E "User ID -|expiration" -A1

# example apt repo we are adding
domain=download.opensuse.org

# save key file locally
sudo curl -fsSL $remote_key_file -o /usr/share/keyrings/$domain.asc
# MUST have 644 at least or apt cannot find key
sudo chmod 644 /usr/share/keyrings/$domain.asc

# find apt repo definition file
repo_file=$(sudo grep -srl $domain /etc/apt | grep -v save)
echo "apt repo for $domain found at: $repo_file"

# manually add '[signed-by=<path>]' parameter which is path to pgp file (.asc)
sudo vi $repo_file

# show new apt repo definition
cat $repo_file
deb [signed-by=/usr/share/keyrings/download.opensuse.org.asc] http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_20.04/ /

# optional step, deleting key from deprecated system keyring
sudo apt-key del $hexid


# warning message should no longer be thrown
sudo apt update

 

 

REFERENCES

debian.org, current scheme for package signature checks

debian.org, apt PGP key not in standard location

cirwin.in, online PGP decoder

askubuntu.com, script for finding all legacy keys and converting to new format

askubuntu.com, exporting legacy key from legacy keyring to its own file and referencing in apt repo definition

askubuntu.com, finding the signing key for a ppa launchpad

askubuntu.com, alternate pgp keyserver at pgpkeys.mit.edu (primary=keyserver.ubuntu.com), screenshot showing how to get key id for ppa

linuxuprising.com, script for identifying and exporting all legacy keys from keyring (another alternate keyserver=pool.sks-keyservers.net)

itfoss.com, explanation of legacy keyrings, dearmor, deprecation of ‘apt-key’

omgubuntu.co.uk – fix apt-key deprecation error with export and dearmor

ubuntu man pages, apt-key deprecated in Ubuntu 21

jeffmotoretta.ca – why apt-key is deprecated

NOTES

Alternate central keysites

pgpkeys.mit.edu, pool.sks-keyservers.net

Check if the developers have loaded newer key into keyserver

curl -s "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x${hexid}" | pgpdump | grep -E "User ID -|expiration" -A1