iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🔐

Retrieving OpenPGP Public Keys Registered on GitHub

に公開
2

GitHub allows you to register OpenPGP public keys to verify digital signatures when committing or tagging, and you can retrieve these registered OpenPGP public keys arbitrarily using the REST API.

For example, the information for the public keys I have registered can be retrieved like this[1].

$ curl -s https://api.github.com/users/spiegel-im-spiegel/gpg_keys
[
  {
    "id": 1043333,
    "primary_key_id": null,
    "key_id": "B4DA3BAE7E20B81C",
    "raw_key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n\r\n...\r\n-----END PGP PUBLIC KEY BLOCK-----\r\n",
    "public_key": "...",
    "emails": [
      {
        "email": "spiegel.im.spiegel...",
        "verified": true
      }
    ],
    "subkeys": [
      {
        "id": 1043334,
        "primary_key_id": 1043333,
        "key_id": "4308C4946F760D3C",
        "raw_key": null,
        "public_key": "...",
        "emails": [

        ],
        "subkeys": [

        ],
        "can_sign": false,
        "can_encrypt_comms": true,
        "can_encrypt_storage": true,
        "can_certify": false,
        "created_at": "2020-10-13T22:07:23.000Z",
        "expires_at": null
      }
    ],
    "can_sign": true,
    "can_encrypt_comms": false,
    "can_encrypt_storage": false,
    "can_certify": true,
    "created_at": "2020-10-13T22:07:23.000Z",
    "expires_at": null
  }
]

Please note that I have omitted some parts with ....

Since multiple public keys can be registered, the data is returned in an array structure. For instance, if you want to extract the first key, you can use the jq command:

$ curl -s https://api.github.com/users/spiegel-im-spiegel/gpg_keys | jq .[0]

If you already know the Key ID, you can do something like this:

$ curl -s https://api.github.com/users/spiegel-im-spiegel/gpg_keys | jq '.[]|select(.key_id=="B4DA3BAE7E20B81C")'

jq is incredibly convenient!

Within the retrieved information, the content of the raw_key field is the actual OpenPGP public key data registered on GitHub. To extract this, you can use jq with the -r option like this:

$ curl -s https://api.github.com/users/spiegel-im-spiegel/gpg_keys | jq -r '.[]|select(.key_id=="B4DA3BAE7E20B81C")|.raw_key'
-----BEGIN PGP PUBLIC KEY BLOCK-----

...
-----END PGP PUBLIC KEY BLOCK-----

This OpenPGP public key data can be imported directly into GnuPG and similar tools.

$ curl -s https://api.github.com/users/spiegel-im-spiegel/gpg_keys | jq -r '.[]|select(.key_id=="B4DA3BAE7E20B81C")|.raw_key' | gpg --import

It seems that for some registered public keys, the raw_key field might be null (perhaps for older registrations?). In this case, it cannot be retrieved as OpenPGP public key data, but you can still extract only the public key packet from the public_key field.

However, since it is BASE64 encoded, you will need to decode it into binary data using commands like base64 or openssl. Furthermore, you can visualize the extracted public key packet using my own tool, gpgpdump.

$ curl -s https://api.github.com/users/spiegel-im-spiegel/gpg_keys | jq -r '.[]|select(.key_id=="B4DA3BAE7E20B81C")|.public_key' | base64 -d | gpgpdump -u
Public-Key Packet (tag 6) (1198 bytes)
    Version: 4 (current)
    Public key creation time: 2013-04-28T10:29:43Z
    Public-key Algorithm: DSA (Digital Signature Algorithm) (pub 17)
    DSA p (3072 bits)
    DSA q (q is a prime divisor of p-1) (256 bits)
    DSA g (3070 bits)
    DSA y (= g^x mod p where x is secret) (3067 bits)

Please note that a public key packet alone cannot be used as an OpenPGP public key[2]. If the raw_key field is missing but you still want to obtain the OpenPGP public key, you can extract the list of key IDs like this:

$ curl -s https://api.github.com/users/spiegel-im-spiegel/gpg_keys | jq -r .[].key_id
B4DA3BAE7E20B81C

Then, you would have to import it into GnuPG or similar tools from a key server as follows:

$ gpg --recv-keys B4DA3BAE7E20B81C

[Update 2020-10-14]

I was informed in the comments (thanks for the info!) that adding .gpg to the end of your user profile URL allows you to retrieve the OpenPGP public key data. In my case:

$ curl -s https://github.com/spiegel-im-spiegel.gpg
-----BEGIN PGP PUBLIC KEY BLOCK-----

...
-----END PGP PUBLIC KEY BLOCK-----

You can retrieve it this way. So you can either do:

$ curl -s https://github.com/spiegel-im-spiegel.gpg | gpg --import

or directly import it into GnuPG using:

$ gpg --fetch-key https://github.com/spiegel-im-spiegel.gpg

By the way, if multiple public keys are registered, all key data will be retrieved in a concatenated state. Conversely, for a user who hasn't registered any public keys, it will look something like this:

$ curl -s https://github.com/nokeyuser.gpg
-----BEGIN PGP PUBLIC KEY BLOCK-----
Note: This user hasn't uploaded any GPG keys.


=twTO
-----END PGP PUBLIC KEY BLOCK-----

[Update 2020-11-23]

I have updated my tool gpgpdump to be able to extract and visualize OpenPGP public keys registered on GitHub.

For example, if you find a signature like this on GitHub:

verified-signature.png

You can view the contents of the public key with the following command line:

$ gpgpdump github spiegel-im-spiegel --keyid B4DA3BAE7E20B81C -u
Public-Key Packet (tag 6) (1198 bytes)
    Version: 4 (current)
    Public key creation time: 2013-04-28T10:29:43Z
    Public-key Algorithm: DSA (Digital Signature Algorithm) (pub 17)
    DSA p (3072 bits)
    DSA q (q is a prime divisor of p-1) (256 bits)
    DSA g (3070 bits)
    DSA y (= g^x mod p where x is secret) (3067 bits)
...

For details, please check the following article:

https://text.baldanders.info/release/2020/11/gpgpdump-v0_10_0-is-released/

References

脚注
  1. When accessing the GitHub REST API using the curl command, it is technically correct to include the -H "Accept: application/vnd.github.v3+json" option, but it seems to work fine without it for now. I will omit the GraphQL API this time. ↩︎

  2. An OpenPGP public key consists of multiple packets, such as a public key packet, a user ID packet, and signature packets. A public key packet alone cannot certify the key itself, so it cannot be used at least in GnuPG. ↩︎

GitHubで編集を提案

Discussion