使用 OpenPGP 子项签署提交失败

Signing commit with OpenPGP subkey fails

我想使用我的 GPS (2) 子密钥之一在 Git 中签署 commits/tags 即,我新创建的具有长 ID B0##...

的 RSA4096 仅签名密钥
sec#  ed25519/9F############## 2016-01-07 [expires: 2023-01-05]
  Key fingerprint = FC08 HEX HEX HEX 
uid                 [ultimate] MY NAME <MY.NAME@foo bar>
ssb   rsa4096/C9############## 2016-01-07 [expires: 2022-01-05]
ssb   ed25519/C6############## 2016-01-07 [expires: 2022-01-05]
ssb   rsa4096/B0############## 2016-01-13 [expires: 2022-01-11]

我正在使用删除(备份)主密钥的密钥环作为 'better key policy'

因此,我尝试为 Git

设置签名密钥
[user]
    ...
    signingkey = B0##############

但是,提交和签名失败

> git commit -S  -m "test commit"
gpg: skipped "B0##############": secret key not available
gpg: signing failed: secret key not available
error: gpg failed to sign the data
fatal: failed to write commit object

其中一个 gpg-agent 启动并且 运行。

我的第一个猜测是,Git 不理解长键符号,而是尝试了短键符号

> gpg2 --list-secret-keys  --keyid-format short
...
ssb   rsa4096/DB###### 2016-01-13 [expires: 2022-01-11]

> ~/.gitconfig
[user]
   ...
   signingkey = DB######

但也失败了

> git commit -S  -m "test commit short"
gpg: skipped "DB######": secret key not available
gpg: signing failed: secret key not available
error: gpg failed to sign the data
fatal: failed to write commit object

所以,我想知道这里有什么问题,如果 Git 只能使用主密钥进行签名但不理解子密钥的使用(或者如果我在某个地方搞砸了)?

Git默认使用gpg,在大多数系统上是GnuPG 1,不支持椭圆曲线密码。由于您的主键是椭圆曲线键,因此 GnuPG 1 根本无法使用该键。当尝试将密钥与 GnuPG (gpg --default-key key-id --sign) 一起使用时,您将能够观察到相同的情况。

配置 Git 以使用 gpg2,这需要至少是 GnuPG 2.1(你有,因为你可以使用椭圆曲线键):

git config --global gpg.program gpg2

Git 的最新版本现在默认使用 gpg2,但 Git 2.25(2020 年第一季度)修复了另一个故障源。

用于解析 GPG 输出的代码过去错误地假定主键的指纹对于有效签名将始终存在,这一点已得到纠正。

参见 commit 67a6ea6 (22 Nov 2019), and commit 392b862 (21 Nov 2019) by Hans Jerry Illikainen (illikainen)
(由 Junio C Hamano -- gitster -- in commit f06dff7 合并,2019 年 12 月 5 日)

gpg-interface: limit search for primary key fingerprint

Signed-off-by: Hans Jerry Illikainen

The VALIDSIG status line from GnuPG with --status-fd is documented to have 9 required and 1 optional fields.

The final, and optional, field is used to specify the fingerprint of the primary key that made the signature in case it was made by a subkey.

However, this field is only available for OpenPGP signatures; not for CMS/X.509.

If the VALIDSIG status line does not have the optional 10th field, the current code will continue reading onto the next status line.

And this is the case for non-OpenPGP signatures.

The consequence is that a subsequent status line may be considered as the "primary key" for signatures that does not have an actual primary key.

Limit the search of these 9 or 10 fields to the single line to avoid this problem.

If the 10th field is missing, report that there is no primary key fingerprint.

The documentation says:

VALIDSIG <args>

The args are:

  • <fingerprint_in_hex>
  • <sig_creation_date>
  • <sig-timestamp>
  • <expire-timestamp>
  • <sig-version>
  • <reserved>
  • <pubkey-algo>
  • <hash-algo>
  • <sig-class>
  • [ <primary-key-fpr> ]

This status indicates that the signature is cryptographically valid.
[...] PRIMARY-KEY-FPR is the fingerprint of the primary key or identical to the first argument.

The primary-key-fpr parameter is used for OpenPGP and not available for CMS signatures. [...]