GitHub API OpenPGP密钥格式

时间:2017-09-04 00:33:29

标签: github github-api pgp openpgp

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 doc

  

public_key响应字段中返回的数据不是GPG格式的密钥。当用户上载GPG密钥时,将对其进行解析,并提取并存储加密公钥。此加密密钥是此页面上的API返回的密钥。此密钥不适合由GPG等程序直接使用。

是否可以通过CLI或以编程方式使用这些密钥?

2 个答案:

答案 0 :(得分:3)

返回的密钥是裸(RSA,DSA,...)密钥,OpenPGP的实现不能将其用于再次将其“包装”在适当的OpenPGP密钥包中。我不建议这样做,为什么你应该能够再次构造 key 数据包,你将没有机会为子项和用户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。虽然对密钥的任何程序化引用都应always include the key's fingerprint, not abbreviated key IDs,但至少它们不提供short key IDs that heavily suffer under collision attacks

答案 1 :(得分:1)

在撰写本文时,public_key字段中的内容是在RFC 4880中定义的base64编码的OpenPGP数据包。 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);

无论如何,由于没有自签名,因此验证结果不值得信任。