在 BASH 脚本中验证 PGP 签名的正确方法(固定精确的长指纹)

在 BASH 脚本中验证 PGP 签名的正确方法(固定精确的长指纹)

我有:

  1. 一份文件
  2. 该文件的 ASCII 装甲格式的独立 PGP 签名以及
  3. 40 个字符(长格式)的指纹,用于标识必须具有有效签名的一个密钥

gpg使用*nix 上的命令编写 BASH 脚本来验证给定签名对于给定文件是否有效(仅适用于给定指纹)的正确方法是什么?

注意:理想情况下,解决方案不会只是从gpg-- 解析 STDOUT,这样,如果将来输出的单词或格式稍有更改,所提供的解决方案中的 BASH 脚本就不会中断。

而且,尤其重要的是,分离签名可以由多个密钥进行签名。因此,例如,如果攻击者获取文件及其分离的签名并编辑该文件,同时将自己的签名添加到分离的签名中,则此解决方案应该会失败。请注意,在这种攻击中,我们将其指纹固定在脚本中的密钥会出现一个错误的签名,而攻击者的密钥会出现一个良好的签名,这是无关紧要的。在这种情况下,解决方案必定会失败。

例如,请考虑以下情况:

  1. https://files.pythonhosted.org/packages/cb/85/8a1588a04172e0853352ecfe214264c65a62ab35374d9ad9c569cf94c2a3/python_gnupg-0.4.6-py2.py3-none-any.whl
  2. https://files.pythonhosted.org/packages/cb/85/8a1588a04172e0853352ecfe214264c65a62ab35374d9ad9c569cf94c2a3/python_gnupg-0.4.6-py2.py3-none-any.whl.asc
  3. CA749061914EAC138E66EADB9147B477339A9B86

目前我的 BASH 脚本中有以下内容

#!/bin/bash

ONLY_TRUST_THIS_FINGERPRINT='CA749061914EAC138E66EADB9147B477339A9B86'

tmpDir="`mktemp -d`" || exit 1
pushd "${tmpDir}"

wget https://files.pythonhosted.org/packages/cb/85/8a1588a04172e0853352ecfe214264c65a62ab35374d9ad9c569cf94c2a3/python_gnupg-0.4.6-py2.py3-none-any.whl
wget https://files.pythonhosted.org/packages/cb/85/8a1588a04172e0853352ecfe214264c65a62ab35374d9ad9c569cf94c2a3/python_gnupg-0.4.6-py2.py3-none-any.whl.asc
wget https://keys.openpgp.org/vks/v1/by-fingerprint/CA749061914EAC138E66EADB9147B477339A9B86

mkdir gnupg
gpg --homedir "${tmpDir}/gnupg" --import CA749061914EAC138E66EADB9147B477339A9B86

在上面的脚本中应该遵循哪些命令来安全地确认该文件具有来自与我们固定指纹匹配的私钥的有效签名?

编辑:这是一个简单的示例输出,gpg --verify ...它具有攻击者的良好签名和实际开发人员的错误签名;它应该失败。

user@disp2952:/tmp/tmp.nUmxfwbwfK$ gpg --homedir gnupg/ --verify python_gnupg-0.4.6-py2.py3-none-any.whl.asc
gpg: WARNING: unsafe permissions on homedir '/tmp/tmp.nUmxfwbwfK/gnupg'
gpg: assuming signed data in 'python_gnupg-0.4.6-py2.py3-none-any.whl'
gpg: Signature made Sat 29 Aug 2020 10:04:03 PM +0545
gpg:                using RSA key 2DA3BAD0DB41087CA7E5E4C1F93C17B957F73F5A
gpg: Good signature from "Mallory <[email protected]>" [unknown]
gpg: Signature made Fri 17 Apr 2020 07:54:23 PM +0545
gpg:                using RSA key 9147B477339A9B86
gpg: BAD signature from "Vinay Sajip (CODE SIGNING KEY) <[email protected]>" [unknown]
user@disp2952:/tmp/tmp.nUmxfwbwfK$ echo $?
1
user@disp2952:/tmp/tmp.nUmxfwbwfK$ 

答案1

使用gpgv:

gpgv --homedir "${tmpDir}/gnupg" --keyring "${tmpDir}/gnupg/pubring.kbx" python_gnupg-0.4.6-py2.py3-none-any.whl.asc python_gnupg-0.4.6-py2.py3-none-any.whl

仅当使用给定密钥环中的密钥验证所有签名时,它才会指示成功(退出代码 0)。

如果您想检查导入的密钥是否与您要求的指纹匹配,您可以要求gpg列出密钥环中与指纹匹配的密钥:

gpg --homedir "${tmpDir}/gnupg" --no-default-keyring --keyring "${tmpDir}/gnupg/pubring.kbx" --list-keys "${ONLY_TRUST_THIS_FINGERPRINT}"

如果密钥存在于密钥环中,则表示成功,否则表示失败。

如果你想改进信任检查,你应该真正存储下载的密钥,并始终使用存储的密钥来验证下载,而不是每次都重新下载密钥。这是某些发行版(特别是 Debian)中用于验证新上游版本的方法:已知良好的密钥存储在软件包源中(在 Debian 中,而不是上游),并且新版本仅在由已知良好的密钥。

相关内容