GitHub API OpenPGP 密钥格式

6

GitHub REST API v3 for GPG Keys返回的public_key字段的格式是什么?

例如,命令curl -v -H "Accept: application/vnd.github.cryptographer-preview" https://api.github.com/users/DurandA/gpg_keys返回以下密钥:

pub   dsa2048/403094DF 2017-09-03 [SC] [expires: 2018-09-03]
uid         [ultimate] Arnaud Durand <arnaud.durand@unifr.ch>
sub   elg2048/A454F414 2017-09-03 [E] [expires: 2018-09-03]

根据API文档中的说明:
引用部分:
公钥响应字段中返回的数据不是GPG格式的密钥。当用户上传GPG密钥时,它会被解析并提取加密公钥进行存储。这个加密的公钥由本页面的API返回。这个密钥不能直接被像GPG这样的程序使用。
是否可能从CLI或编程方式使用这些密钥?
2个回答

4
返回结果:

返回的密钥是裸密钥(RSA、DSA等),如果没有将其包装成适当的OpenPGP密钥数据包,实现OpenPGP的应用程序将无法使用它。我不建议这样做,即使您能够重新构造密钥数据包,也无法构造子密钥和用户ID的绑定签名(这需要访问私钥),也无法成功构造有用的内容。

在社区中共享密钥的“OpenPGP模型”是从密钥服务器网络中获取当前副本(包括所有当前认证和撤销),而不是依赖于可能过时的“第三方位置”(如GitHub)中的版本。这可以通过指纹和密钥ID来实现,它们(或多或少地)唯一地标识特定的密钥--不要搜索邮件地址,每个人都可以创建带有任意用户ID的密钥,并且密钥服务器不执行任何验证。

相反,再看一下API的输出,它为所有密钥(某些为子密钥)返回keyid对象:

[
  {
    "id": 3,
    "primary_key_id": null,
    "key_id": "3262EFF25BA0D270",
    "public_key": "xsBNBFayYZ...",
    "emails": [
      {
        "email": "mastahyeti@users.noreply.github.com",
        "verified": true
      }
    ],
    [snip]
  }
]

要使用这样的密钥 ID,请运行 gpg --recv-keys <key-id>。并向 GitHub 发送一条消息以遵循最佳实践并包括完整的指纹:
这些 64 位十六进制值(在此示例中为3262EFF25BA0D270)是长密钥 ID。虽然对密钥的任何编程引用都应该始终包括密钥的指纹,而不是缩写的密钥 ID,但至少它们不会提供容易受到冲突攻击的短密钥 ID

1
截至目前,public_key字段中的内容是经过base64编码的OpenPGP数据包,这些数据包在RFC 4880中定义。使用gpgpdump可以检查它们。例如,
$ curl -s https://api.github.com/users/DurandA/gpg_keys | jq -r '.[0].public_key' | base64 -d | ./gpgpdump
Public-Key Packet (tag 6) (814 bytes)
        Version: 4 (current)
        Public key creation time: 2017-09-04T06:53:50+08:00
                59 ac 87 fe
        Public-key Algorithm: DSA (Digital Signature Algorithm) (pub 17)
        DSA p (2048 bits)
        DSA q (q is a prime divisor of p-1) (256 bits)
        DSA g (2046 bits)
        DSA y (= g^x mod p where x is secret) (2047 bits)

作为一个OpenPGP密钥由一系列OpenPGP数据包组成,理论上可以重建用于验证的密钥。为了实现这个目标,需要额外的用户ID数据包和GnuPG补丁。以下Python 3脚本可用于生成用户ID数据包:
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)

以下 GnuPG 补丁强制进行验证,即使没有签名。
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);

无论如何,由于没有自签名,验证结果不应被信任。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接