如何验证gpg签名与公钥文件匹配?

39

我知道如何使用gpg验证,步骤如下:

$ gpg --verify somefile.sig
gpg: Signature made Tue 23 Jul 2013 13:20:02 BST using RSA key ID E1B768A0
gpg: Good signature from "Richard W.M. Jones <rjones@redhat.com>"
gpg:                 aka "Richard W.M. Jones <rich@annexia.org>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: F777 4FB1 AD07 4A7E 8C87  67EA 9173 8F73 E1B7 68A0

但我真正想做的是针对特定公钥文件验证文件。

这是程序的一部分,它从网站下载大文件,并需要在使用它们之前验证它们是否被篡改。网站将包含文件和签名。该程序将随附GPG公钥。当我上传文件到网站时,我将用相应的私钥进行签名(显然不会分发)。看起来该程序应该能够执行以下操作:

gpg --no-default-keyring --verify file.sig \
    --is-signed-with /usr/share/program/goodkey.asc

但是gpg没有像这样的选项。看起来唯一的方法是解析gpg命令的输出,但这似乎非常不安全(其中包含由攻击者控制的文本)。

编辑:我不知道在这里回答自己的问题的礼仪是什么,但我找到的答案是使用--status-fd标志。此标志生成易于解析的输出,我可以检查所需指纹:

gpg --status-fd <N> --verify file.sig

在文件描述符N上产生:

[GNUPG:] SIG_ID rpG8ATxU8yZr9SHL+VC/WQbV9ac 2013-07-23 1374582002
[GNUPG:] GOODSIG 91738F73E1B768A0 Richard W.M. Jones <rjones@redhat.com>
[GNUPG:] VALIDSIG F7774FB1AD074A7E8C8767EA91738F73E1B768A0 2013-07-23 1374582002 0 4 0 1 2 00 F7774FB1AD074A7E8C8767EA91738F73E1B768A0
[GNUPG:] TRUST_UNDEFINED

这就是例如perl的GnuPG库如何工作的方式。

如果您将应该用于下载的公钥放在旁边,那么有什么可以防止任何人篡改文件并将自己的公钥放在旁边的措施吗? - Jens Erat
1
公钥不在下载旁边。公钥包含在软件中。下载旁边的文件是分离的签名。 - Rich
1
现在我明白了,有点误解你的意思。回答自己的问题是值得赞赏的,最好将其放入下面的答案字段中。大约两天后,您将能够将其选择为“已回答您的问题”。 - Jens Erat
请注意,您收到的状态-fd输出仅因为公钥在您的密钥环中而获得,它并不能解决直接调用密钥文件而不是导入密钥到默认(或任何其他)密钥环的问题。 - Ben
2个回答

33

只有当文件是GPG(OpenPGP)文件格式而不是ASCII装甲版本(例如pubkey.gpg而不是pubkey.asc)时,才能使用特定的公钥文件作为密钥环的一部分。

因此,这将验证该文件:

gpg --no-default-keyring --keyring /path/to/pubkey.gpg --verify /path/to/file.txt.gpg

而这将不会:

gpg --no-default-keyring --keyring /path/to/pubkey.asc --verify /path/to/file.txt.gpg

编辑:我在SuperUser网站上回答了一个类似的问题,并且提供了更详细的解释:

https://superuser.com/questions/639853/gpg-verifying-signatures-without-creating-trust-chain/650359#650359


12
请注意,--keyring 的路径必须是绝对路径。如果只是文件名,则会在 ~/.gnupg 中查找密钥环文件。如果想要在当前目录中查找密钥环,请在文件名前加上 ./ - Jess
没错,那绝对正确。我希望我的通用/path/to足够了,但考虑到可能会有混淆,强调一下是值得的,谢谢。半相关的是,2.1分支最近获得了一组新命令,即使在ASCII装甲文件中也可以更有效地执行此操作,但仅在2.1.14或更高版本中可用(这些添加项是在2016年7月初制作的;在2.1.14发布一周之前)。一些详细信息在此帖子中,看起来相当简单,但不太可能被回溯到2.0或1.4。 - Ben
@Ben,你应该说--keyring路径必须包含斜杠,因为./whatever不是绝对路径。 - Wildcard
1
@Wildcard 你说得对,我应该说如果 --keyring 的参数只是一个文件名(不是相对/绝对路径),那么它将在 ~/.gnupg 中寻找。 - Jess
2
你能不能只使用 gpg --dearmor pubkey.asc 命令并使用输出呢? - ZN13
为什么gpg仍然难以使用?签名验证有3个输入参数:签名、公钥和相关文件。为什么没有一个简单的命令来执行验证呢?当我们看一下GPG应该如何使用时,Git已经开始支持SSH签名提交也就不足为奇了。 - wheeler

12

我想出了以下脚本:

#!/bin/bash

set -e

keyfile=$(mktemp --suffix=.gpg)
function cleanup {
    rm "$keyfile"
}
trap cleanup EXIT

gpg2 --yes -o "$keyfile" --dearmor "$1"
gpg2 --status-fd 1 --no-default-keyring --keyring "$keyfile" --trust-model always --verify "$2" 2>/dev/null

用作:

$ check-sig.sh <ascii-armored-keyfile> <signature-document>

如果输出为 [GNUPG:] NODATA 1 和 [GNUPG:] NODATA 2,这意味着什么? - slashdottir
1
你可以修改该脚本的最后一行,将其改为gpg2 --no-default-keyring --keyring "$keyfile" --trust-model always --verify "$2" 2> /dev/null && echo valid || echo invalid。这样它就会简单地返回“valid”或“invalid”。 - b_laoshi

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