What are public_key fields in GitHub gpg_keys API?

GitHub provides an API endpoint for querying users' PGP keys. For example, information about my keys can be found here.

In this JSON document, the raw_key is what programs like GnuPG need. What about public_key fields? GitHub official document says:

The data returned in the public_key response field is not a GPG formatted key. When a user uploads a GPG key, it is parsed and the cryptographic public key is extracted and stored. This cryptographic key is what is returned by the APIs on this page. This key is not suitable to be used directly by programs like GPG.

With the help of the gpgpdump tool, I found that contents in public_key fields are actually base64-encoded OpenPGP packets, which are defined in RFC 4880.

$ curl -s https://api.github.com/users/yan12125/gpg_keys | jq -r '.[0].public_key' | base64 -d | ./gpgpdump
Public-Key Packet (tag 6) (1198 bytes)
        Version: 4 (current)
        Public key creation time: 2016-04-06T02:36:01+08:00
                57 04 05 91
        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) (3069 bits)

As an OpenPGP key is composed of a series of OpenPGP packets, it is theoretically possible to reconstruct a key for verifying stuffs. To achieve that, an extra user ID packet and a GnuPG patch are needed. The following Python 3 script can be used to generate a user ID packet:

TAG_UID = 13

uid = 'foo@example.com'
# RFC 4880, Sec 4.2.1.  Old Format Packet Lengths
header = bytes([0x80 | (TAG_UID << 2), len(uid)])
packet = header + uid.encode('ascii')

sys.stdout.buffer.write(packet)

And the following GnuPG patch forces verification even if there are no signatures.

diff --git a/g10/sig-check.c b/g10/sig-check.c
index 4c172d692..eb4653535 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -177,7 +177,7 @@ check_signature2 (ctrl_t ctrl,
                  gnupg_compliance_option_string (opt.compliance));
       rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
     }
-  else if (!pk->flags.valid)
+  else if (0)
     {
       /* You cannot have a good sig from an invalid key.  */
       rc = gpg_error (GPG_ERR_BAD_PUBKEY);

In practice, no self-signatures simply means the key cannot be trusted. So this is just a fun experiment :)

P.S. I've also posted similar contents to https://stackoverflow.com/a/57712714/3786245.

social