Skip to main content

RPM and GPG: How to verify Linux packages before installing them

Are you sure that your package is safe from corruption or malicious activity? Here's how signature verification can help.
Image
A package

Large and popular RPM repositories are typically replicated around the world. The projects and companies providing the packages utilize content distribution networks (CDNs) and mirror sites to make their packages available to consumers. For many open-source projects, that includes hosting by volunteers. To detect and avoid malicious replacement packages, package owners can sign the package files, and consumers can verify those signatures.

While GPG can sign any file, manually checking package signatures is not scalable for system administrators. The RPM format has an area specifically reserved to hold a signature of the header and payload. The rpm utility uses GPG keys to sign packages and its own collection of imported public keys to verify the packages. YUM and DNF use repository configuration files to provide pointers to the GPG public key locations and assist in importing the keys so that RPM can verify the packages.

For this article, I will use keys and packages from EPEL. The public key is included in an RPM package, which also configures the yum repo. For some projects, the key may also be available directly from a source web site.

The rpm utility has its own key management

Since the rpm utility has its own key management, there is no need to import the GPG public keys to your personal GPG keyring. In fact, you cannot just verify the file with gpg commands because the signature is not of the entire .rpm file. Instead, the signature is only associated with the critical portions of the package.

Run the following command to use rpm to verify a package:

$ rpm -K epel-release-latest-8.noarch.rpm 
epel-release-latest-8.noarch.rpm: digests SIGNATURES NOT OK

In this case, the "SIGNATURES NOT OK" message appears because the key has not yet been imported for RPM. The default behavior of rpm commands is to verify the signature of packages during any install or verify interactions. If that is not possible, because the package is not signed or the public key is not available, you may need to specify the --nogpgcheck option to skip this step.

If you have access to the GPG public key, you can use the following command to manually import a key:

$ rpm --import RPM-GPG-KEY-EPEL-8 

Since the metadata for the key is stored in the RPM database, you can query and delete keys the same as any package.

Use the following command to list the keys:

$ rpm -qa gpg-pubkey*
gpg-pubkey-7fac5991-4615767f
gpg-pubkey-2f86d6a1-5cf7cefb

Use this command to get the information on a key:

$ rpm -qi gpg-pubkey-2f86d6a1-5cf7cefb
Name : gpg-pubkey
Version : 2f86d6a1
Release : 5cf7cefb
Architecture: (none)
Install Date: Mon 01 Jun 2020 12:14:38 PM EDT
Group : Public Keys
Size : 0
License : pubkey
Signature : (none)
Source RPM : (none)
Build Date : Wed 05 Jun 2019 10:17:31 AM EDT
Build Host : localhost
Relocations : (not relocatable)
Packager : Fedora EPEL (8) <epel@fedoraproject.org>
Summary : gpg(Fedora EPEL (8) <epel@fedoraproject.org>)
Description :
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: rpm-4.14.2 (NSS-3)
...omitted...

The following command is used to remove a key:

$ sudo rpm -e gpg-pubkey-2f86d6a1-5cf7cefb

More options for key management are described in the man page included with the rpmkey package.

YUM and DNF can add keys to the RPM database

Other package managers make key management even easier. YUM and DNF use configuration files in /etc/yum.repos.d to specify a URL for the GPG key used to verify packages in that repository. The utilities can then import the key if it is not already available for verification.

Image
Contents of the epel.repo file

In the yum repo configuration file, the line gpgcheck=1 indicates that GPG checking should be done for all packages in this repository. It is a Boolean value that can be changed in the configuration or overridden temporarily on the command line with the --nogpgcheck option.

If the GPG public key has not yet been imported to RPM when a package installation begins, then the yum (or dnf) utility can initiate an import of the key. The gpgkey=URI line specifies the source of the key to be imported. This source can be any URI, including a local file or a remote web link. The yum or dnf utility will pause and ask for confirmation to import the key after showing the key ID and fingerprint.

warning: /var/cache/dnf/epel-fafd94c310c51e1e/packages/zsh-syntax-highlighting-0.7.1-1.el8.noarch.rpm: Header V3 RSA/SHA256 Signature, key ID 2f86d6a1: NOKEY

Extra Packages for Enterprise Linux 8 - x86_64 1.6 MB/s | 1.6 kB 00:00    

Importing GPG key 0x2F86D6A1:

 Userid : "Fedora EPEL (8) <epel@fedoraproject.org>"

 Fingerprint: 94E2 79EB 8D8F 25B2 1810 ADF1 21EA 45AB 2F86 D6A1

 From : /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8

Is this ok [y/N]: y

The key is added to RPM, and then the verification and installation of the package continues.

Prepare to sign a package

If you are creating and distributing your own RPM package files, you can sign those packages with the rpmsign utility.

The first step is to create a GPG keypair for signing. Be sure to also export and share the public key. For packages that will be distributed publicly, it is a good idea to use a new keypair and a keyring in a shared location. Additionally, use the --full-gen-key option and then choose to create a signing-only key instead of the default, which creates both a signing and encryption key.

$ gpg --keyring /shared/rpm/.gpg --no-default-keyring --full-gen-key 

Even if only one person is using the key to sign packages, make a separate keypair to use for signing. Do not use the same key for other daily tasks such as personal email encryption.

Next, we need to install the rpm-sign package and set up an rpmmacros file specifying the key to use. The rpm-sign package includes a man page for rpmsign which describes the process. Note that the package name has a dash that is not a part of the command name.

$ sudo yum install rpm-sign
$ man rpmsign

RPM commands get their configuration from several rpmmacros files. There is a default file with lots of samples located at /usr/lib/rpm/macros. If multiple people are responsible for signing packages using the same key, place a central configuration file in the /etc/rpm/macros location. Finally, for a specific person signing the packages, the user's ~/.rpmmacros file can be configured to point to the correct GPG key.

The minimum entry for the rpmmacros file is to specify the name of the key. You can use a name or the key ID. Obtain the key ID with the gpg --list-keys command.

Tip: Run the rpmsign command before setting the gpg_name variable and the message will show the format.

$ rpmsign --addsign my-custom-package.rpm 
You must set "%_gpg_name" in your macro file

In addition to the key name, if the keyring is anywhere other than the default user ~/.gnupg directory, use the gpg_path variable to set the location. This value will be the same as used with the --keyring option when the key was created.

There are additional options available if the GPG binary or command syntax requires something beyond the expected defaults.

Image
contents of ~/.rpmmacros with comments

Sign and publish packages

You are now ready to sign the package or packages. According to the rpmsign man page, the --addsign and --resign commands are interchangeable. Both will replace the signature portion of an RPM package file with current information.

The following command is an example of using the --addsign flag:

$ rpmsign --addsign myprod-2.x86_64.rpm myprod-libs-2.x86_64.rpm

Older versions of rpmbuild included a --sign option that could sign the package during the build process if the GPG keys and rpmmacro files were configured correctly. The --sign option is now deprecated in favor of the separate step of using rpmsign. This approach encourages a build, test, sign, publish workflow.

Finally, make the packages and GPG public key available to clients. One option is to mimic the EPEL project and create an RPM file that includes the GPG public key and one or more yum repo files pointing to the location of the signed packages. For organizations hosting packages on a Red Hat Satellite Server, start by uploading the GPG public key, and then assigning that key to the product or repository that holds the signed packages. All packages in a repository must be signed with the same key. This is a common reason for Satellite administrators to resign packages before uploading.

Wrap up

Now that you know more about managing RPM packages with GPG, you can better understand how to work with rpm, yum, and dnf.

For further reading, check out Securing RPM signing keys and the Administration and Content Management guides in the Red Hat Satellite documentation.

[ Want to learn more about security? Check out the IT security and compliance checklist. ]

Topics:   Security   Linux  
Author’s photo

Susan Lauber

Susan Lauber is a Consultant and Technical Trainer with her own company, Lauber System Solutions, Inc. More about me

Try Red Hat Enterprise Linux

Download it at no charge from the Red Hat Developer program.