Inspecting OpenPGP certificates

Inspecting OpenPGP certificates

This article outlines using the new rpgp CLI tool to inspect OpenPGP certificates (aka “public keys”)1.

The rpgp tool is available as part of the rpgpie crate. This article describes the tool as of rpgpie version 0.6.6.

rpgp can be installed with the Rust cargo tool like this: cargo install rpgpie --features=cli).

Different views of OpenPGP certificate internals #

The rpgp tool can show information about OpenPGP certificates in two different modes:

  • rpgp show prints the internal structure of a certificate in detail, without much interpretation. This command offers a very raw low-level debugging view of the internals of certificates (with the -v option, this command shows an almost complete view of all internal details of a certificate).
  • rpgp status prints a more summarized view, and applies OpenPGP validity semantics. This view is much closer to what end-users may want to know about an OpenPGP certificate (including which components of a certificate have expired or been revoked). However, note that even this view is highly technical. Modern end-user applications should not need to show this degree of detail about OpenPGP certificates to their user.

In the following sections, we’ll look at the output of the status command, for three different certificates.

Status output for a real-world v4 certificate #

First, let’s check out the structure of my current certificate. This is a relatively typical “version 4” OpenPGP certificate. It uses ECC algorithms based on Curve 25519.

To inspect a certificate, we need to obtain a copy of it. For example, we can pull it from a public OpenPGP keyserver, like this:

$ curl -s "https://pgpkeys.eu/pks/lookup?op=get&search=0x23da7c0eaa711f0170013595b518d342eb2d4805" > heiko.cert

Now we can see what’s going on inside the certificate:

$ rpgp status heiko.cert
πŸ” EdDSA/Curve25519 v4 23da7c0eaa711f0170013595b518d342eb2d4805
  ⏱️ Created 2023-04-23 03:04:56 UTC
  βœ… Active, expires 2026-04-22 03:04:56 UTC
  🏴 Key flags: Certify

  πŸ”‘ EdDSA/Curve25519 v4 954fc07eb1a70fc30bfc10f839d6c12995a8d067
    ⏱️ Created 2023-05-09 21:02:23 UTC
    βœ… Active, expires 2026-04-22 10:12:46 UTC
    🏴 Key flags: Auth

  πŸ”‘ ECDH/Curve25519 v4 f84f06b6f44c9090f1c27f89c8edabd42aa0c4e8
    ⏱️ Created 2023-05-09 21:02:12 UTC
    βœ… Active, expires 2026-04-22 10:12:46 UTC
    🏴 Key flags: Encrypt

  πŸ”‘ EdDSA/Curve25519 v4 03c75b9e40375ce18d815946dae9a9050fccf1eb
    ⏱️ Created 2023-05-09 21:01:49 UTC
    βœ… Active, expires 2026-04-22 10:12:46 UTC
    🏴 Key flags: Sign

  πŸ”‘ ECDH/Curve25519 v4 c09cbaaf8dcc628209789ad3c283ad022c2ed0de
    ⏱️ Created 2023-04-23 03:04:56 UTC
    🚫 Revoked (soft) 2023-12-09 23:58:06 UTC: KeySuperseded "subkey is retired" 

  πŸͺͺ ID "<heiko.schaefer@posteo.de>"
    βœ… Active, expires 2026-04-22 10:46:31 UTC

  πŸͺͺ ID "Heiko Schaefer"
    βœ… Active, expires 2026-04-22 10:46:31 UTC

  πŸͺͺ ID "Heiko Schaefer <heiko@schaefer.name>"
    βœ… Active, expires 2026-04-22 10:46:31 UTC

  πŸͺͺ ID "Heiko Schaefer <heiko.schaefer@posteo.de>"
    βœ… Active, expires 2026-04-22 10:46:31 UTC

The output shows:

  • The top-level “primary” component key and its metadata in athe first block
  • A series of four subkeys with their respective metadata
  • A set of four User IDs that are associated with my certificate

Each component key shows its cryptographic algorithm, the OpenPGP key version (here: “4”) and the fingerprint of that component key. This is followed by the creation time of the key and a line that shows its validity status.

For active component keys, a final line shows the “key flags” for that component key (specifying which operations that component key can perform).

Note that the last of the subkeys is revoked (this is visualized with a “prohibited” emoji). This subkey used to be marked as an encryption key (however, this view does not show that information explicitly).

The revoked subkey remains part of the public record about my certificate, even though it’s not supposed to be used anymore2.

Each component has an associated validity line - keys as well as identity components. Validity is shown with an emoji for easy visual recognition, followed by more verbose textual information about the component’s status.

Finally, note that OpenPGP User IDs don’t have an explicitly modeled creation time.

Inspecting a modern V6 certificate #

The current specification of OpenPGP is RFC 9580 (it has been published a bit over a year ago, now). RFC 9580 defines the updated “version 6” key format, which is at this point well-supported by most OpenPGP implementations.

However, version 6 keys are still rare in production use. Still, we can easily produce a version 6 certificate (for example with most SOP tools) and inspect it with rpgp status.

First, let’s make a fresh example v6 certificate to look at, with the rsop tool:

$ rsop generate-key --profile rfc9580 "<alice@example.org>" | rsop extract-cert > alice_v6.cert

And then look into this certificate with:

$ rpgp status alice_v6.cert
πŸ” Ed25519 v6 82d496f62a2419443eb2b9be73159edd0fbdddaf9860db2cdb1164ad16ce918e
  ⏱️ Created 2025-08-24 22:16:36 UTC
  βœ… Active (no expiration)
  🏴 Key flags: Certify, Sign

  πŸ”‘ X25519 v6 513694cc5bb335f0d5c991defbd94ddc7e6e4ce3025b0d489cf67301ec9d3093
    ⏱️ Created 2025-08-24 22:16:36 UTC
    βœ… Active (no expiration)
    🏴 Key flags: Encrypt

  πŸͺͺ ID "<alice@example.org>" (primary)
    βœ… Active (no expiration)

This is a very simple/minimal certificate. It has a primary key, one encryption subkey and one User ID. All components of this certificate are marked as indefinitely valid - they have no expiration time.

(Version 6 certificates are presumably going to become more common as PQC keys gain popularity in the OpenPGP ecosystem. The upcoming draft-ietf-openpgp-pqc allows use of most PQC algorithms only with version 6 keys. See the blog article on Post-quantum cryptography in OpenPGP for more context.)

Viewing certificate status in JSON format #

Starting with rpgpie version 0.6.6, the rpgp status command can alternatively present its information in JSON format. This is useful for scripted workflows that rely on processing machine-readable data.

WARNING: The rpgp JSON format is currently not stable! All details of this format are subject to change! See the tracking issue for updates and to engage.

(At some point I will commit to not changing the JSON format on a whim, but that point is not right now.)

That said, let’s look at the simple v6 certificate from the previous section again, this time as JSON formatted status information, by passing the --json option:

$ rpgp status --json alice_v6.cert
{
  "primary": {
    "fingerprint": "9a47c697b8dfa657ad8d2bc31df18da8924a281f2f589600352f7bac05f61a81",
    "version": 6,
    "created": "2025-08-24T22:26:06Z",
    "algorithm": "Ed25519",
    "status": {
      "valid": {}
    },
    "key_flags": [
      "Certify",
      "Sign"
    ]
  },
  "subkeys": [
    {
      "fingerprint": "7e1a88fc27cfbb94ab1e088f32bfc3551bc88b4044a02f8ff685a0b14ad8ff9c",
      "version": 6,
      "created": "2025-08-24T22:26:06Z",
      "algorithm": "X25519",
      "status": {
        "valid": {}
      },
      "key_flags": [
        "Encrypt"
      ]
    }
  ],
  "user_ids": [
    {
      "id": "<alice@example.org>",
      "primary": true,
      "status": {
        "valid": {}
      }
    }
  ]
}

Note that the information in this JSON output is exactly the same as in the human-readable output in the previous section. It’s just presented in a different shape.

Inspecting historical certificates #

Finally, rpgp is just as happy to inspect ancient PGP certificates as it is with cutting edge v6 certificates:

$ rpgp status hal_1992.cert
πŸ” RSA(1024) v2 515c99ff35994387e2d430173749a06c
  ⏱️ Created 1992-09-08 05:12:44 UTC
  🚫 Invalid: no active signature in primary user id

  πŸͺͺ ID "Hal Finney <74076.1041@compuserve.com>"
    🚫 Invalid: no active signature

This historical PGP certificate is almost 33 years old today, and uses the prehistoric “v2” key format.

While it’s certainly not practically useful to use such keys in the current era, it may still sometimes be helpful (or just plain fun) to inspect them, for informational purposes - or to marvel at the longevity of the OpenPGP format for a minute.


  1. This blog post is a slightly expanded version of this mastodon thread↩︎

  2. Keeping information about this revoked subkey available on key servers is useful. Its ongoing presence serves to notify all peers that this subkey has been revoked - even peers who have not obtained updates about the certificate since the revocation took place. Otherwise, some peers who still have an old copy of my certificate might mistakenly encrypt messages to me with the now defunct key (which could be annoying: I might not be able to decrypt such messages anymore). ↩︎