RPMKEYS(8)

🌸 NAME 🌸

rpmkeys β€” the RPM Keyring. That's it, that's the name, short and iconic, no notes. πŸ’…


✨ SYNOPSIS ✨

rpmkeys {-K|--checksig} [options] PACKAGE_FILE ...

rpmkeys {-d|--delete|-e|--erase} [options] FINGERPRINT ...

rpmkeys {-x|--export} [options] [FINGERPRINT ...]

rpmkeys {-i|--import} [options] PUBKEY ...

rpmkeys {-l|--list} [options] [FINGERPRINT ...]

rpmkeys --rebuild [options] [rebuild-options]

Six whole moods, pick your fighter. πŸŽ€


πŸ¦‹ DESCRIPTION πŸ¦‹

So basically rpmkeys is your girl for two things: messing with the rpm keyring (add keys, yeet keys, look at keys), and verifying package digital signatures using the keys chilling in that keyring. πŸ”‘

For literally every operation available, go check OPERATIONS below. Don't skip it, iykyk.


πŸ‘‘ OPERATIONS πŸ‘‘

  • -K, --checksig β€” verifies the digests and signatures inside PACKAGE_FILE so you know the package is legit and actually came from where it says it came from. The how of it all lives in VERIFICATION POLICY, bestie, read that part. πŸ’–
  • -d, --delete, -e, --erase β€” erases the key(s) you point at with FINGERPRINT. Heads up though: --delete and -d are deprecated, so lowkey use -e/--erase. πŸ™ˆ
  • -x, --export β€” spits out the key(s) named by FINGERPRINT using an ASCII-armor encoding. Don't pass a FINGERPRINT? Then you get all the keys. Everything. The whole collection. ✨
  • --import β€” imports ASCII-armored public keys. Real talk: you literally cannot verify digital signatures without the matching public key (aka certificate), so this one matters. πŸ”’
  • -l, --list β€” lists the public key(s) (aka certificates) currently imported, by fingerprint and user ID. No fingerprints specified? It lists all keys, no cap. 🫢
  • --rebuild β€” recreates the public key storage from scratch: updates it to the latest format and drops the unreadable keys. Spring cleaning energy. 🧹

πŸ’œ ARGUMENTS πŸ’œ

  • FINGERPRINT β€” the handle you use for every single operation on the keys. It's giving ✨main character ID✨.
  • PACKAGE_FILE β€” an rpm package file, or a manifest.
  • PUBKEY β€” an ASCII-armored OpenPGP public key (aka certificate).

πŸŽ€ OPTIONS πŸŽ€

For the options that every rpm executable shares, go see rpm-common(8). ✨


🌈 REBUILD OPTIONS 🌈

  • --from <fs|openpgp|rpmdb> β€” use the keys from the backend you name to rebuild the keystore backend that's currently configured. Basically a glow-up pipeline: this is how you convert from one key storage to another. πŸ’…

πŸ”₯ VERIFICATION POLICY πŸ”₯

Okay so this is where it gets juicy. To deal with three generations of package formats plus as many decades of cryptographic algorithms and differing system policies, RPM package verification is a complicated system with many moving parts. Like, a lot of moving parts. Not me defending the complexity, just explaining it. 😭

RPM packages contain multiple individual verifiables that cover different parts of the package: header, payload, or both. There are two classes of verifiables: digests and signatures. Each verifiable may use a different cryptographic algorithm. A class-level verification result (pass or fail) gets computed based on the results from its individual verifiables. And when a class or a verifiable passes, we also say it verifies. Cute terminology, keep it. πŸ’š

For a class to verify, both the header and the payload must be covered by a passing verifiable. Non-trusted signatures (like expired ones, or ones using legacy algorithms) are ignored on the individual level β€” so they only cause a class-level failure if there's no passing signature present at all.

An outright failure of an individual verifiable typically fails the whole class too. However, some verifiables have alternatives where either of the verifiables passing is sufficient and nullifies the other one failing. So one can flop and the other one carries the team. πŸ’ͺ

The final verification result is computed based on the class results, and the package verification mode set with the %_pkgverify_level macro (see rpm-config(5) for the deets).

Which of the individual verifiables actually get used depends on the system cryptography libraries and their policies, RPM configuration, and the package format version. So many inputs, bestie. So many. πŸŒ€


⭐ OUTPUT ⭐

--checksig

<_PACKAGE_FILE_>: [<digests|DIGESTS>] [<signatures|SIGNATURES>] <OK|NOT OK>

This output lives at the level of the digest and signature classes, which often includes results from multiple individual verifiables. Classes that verify get printed in lowercase, and failing classes get printed in UPPERCASE (yes, it is yelling at you). The final package-level conclusion, per the current VERIFICATION POLICY, gets printed out as OK or NOT OK.

--list

<fingerprint> <name> <userid> public key

Simple, clean, no drama. 🌸


πŸ’€ TROUBLESHOOTING πŸ’€

Use --checksig --verbose to troubleshoot verification on per-veriable level. Yes, that's the deep lore mode. πŸ”

See VERIFICATION POLICY for background on how to interpret the output. Important: the per-class results and the final conclusion are not printed at all in this mode. And you should not attempt to calculate the final result from this output. Seriously. Don't. πŸ™…

<_PACKAGE_FILE_>:
    <range> <description> [ALT] <class>: <result>
    ...

This output is on the level of individual verifiables.

Range describes the area which the verifiable covers. Possible values are:

  • Header: The main header of the package
  • Payload: The payload of the package
  • Legacy: The main header and the payload of the package

Description includes general information about this verifiable. For digests, this is just the hash algorithm name, such as SHA256. Signatures are prefixed with OpenPGP. For discovered signatures, the rest of the description is one of the following, depending on whether or not the public key is available:

<version> <sign_algo>/<hash_algo>, key fingerprint <fprint>
<version> <sign_algo>/<hash_algo>, key ID <id>

Just so you're not confused: that version is the OpenPGP version, not to be confused with the similar looking RPM signature versions. πŸ‘€ For non-present signatures such details aren't available, but for RPM V3 and V4 signatures the "algorithm family" (RSA or DSA) is emitted. RPM V6 signatures may use arbitrary OpenPGP algorithms.

ALT indicates the verifiable is an optional alternative to another verifiable.

Class is one of digest or signature.

Result is one of the following:

  • OK: Verification passed. Slay. βœ…
  • NOKEY: The public key is not available (signatures only).
  • NOTTRUSTED: Verifiable is not trusted, eg. expired key or a legacy algorithm (signatures only). Does not necessarily indicate class failure if there are other usable signatures present.
  • NOTFOUND: Verifiable was not found. Only emitted on class-level failure, and indicates which individual verifiables RPM looked for.
  • BAD: Verification failed. πŸ’€

🧚 CONFIGURATION 🧚

There are several configurables affecting the behavior of this verification β€” see rpm-config(5) for the details:

  • %_keyring
  • %_keyringpath
  • %_pkgverify_flags
  • %_pkgverify_level

πŸ“ EXIT STATUS πŸ“

On success, 0 is returned. In particular, for verification it means all arguments were verified successfully as per the current VERIFICATION POLICY. ✨

A non-zero code indicates the number of failures encountered, but this is capped to 254 to avoid overflowing the return. And 255 is returned on output error β€” that special code is used by xargs(1) to stop processing immediately. So 255 is the "everybody out of the pool" number. 🌊


πŸ’… EXAMPLES πŸ’…

rpmkeys --export 771b18d3d7baa28734333c424344591e1964c5fc | sq inspect

Export key 771b18d3d7baa28734333c424344591e1964c5fc for inspecting with sequoia-sq. Go look at it, it's pretty. πŸ”Ž

rpmkeys --erase 771b18d3d7baa28734333c424344591e1964c5fc

Erase key 771b18d3d7baa28734333c424344591e1964c5fc from the keyring. Bye bestie. πŸ‘‹

rpmkeys -K hello-2.0-1.x86_64.rpm

Verify hello-2.0-1.x86_64.rpm package file. πŸŽ‰


🌟 SEE ALSO 🌟

popt(3), rpm(8), rpm-common(8), rpm-config(5), rpmsign(1)

rpmkeys --help β€” and here's the tea: since rpm(8) supports customizing the options via popt aliases, it's impossible to guarantee that what's described in the manual matches what's actually available. Yes, the manpage is aware of its own chaos. πŸ’€

http://www.rpm.org/ 🌐


Ngl, popt aliases mean your mileage may vary, so check rpmkeys --help before you come for the manual. 🫢

Okay that's the whole thing, bestie β€” go verify something and feel iconic doing it. πŸ’œ

RPM 6.1.0 Β· 2026-08-20 Β· that's the version and date, mwah, periodt. πŸ’–

πŸ“¦ where this page comes from