注意:直到 git 2.5,git verify-commit
并且git verify-tag
只显示人类可读的消息。
如果您想自动执行检查,git 2.6+ (Q3 2015) 添加了另一个输出。
请参阅提交 e18443e、提交 aeff29d、提交 ca194d5、提交 434060e、提交 8e98e5f、提交 a4cc18f、提交 d66aeff(2015 年 6 月 21 日),作者为brian m。卡尔森 ( bk2204
) .
(由Junio C Hamano 合并gitster
——在提交 ba12cb2中,2015 年 8 月 3 日)
verify-tag
/ verify-commit
: 添加选项以打印原始 gpg 状态信息
verify-tag
/verify-commit
默认情况下在标准错误上显示人类可读的输出。
但是,访问原始 gpg 状态信息也很有用,它是机器可读的,允许自动实施签名策略。
添加一个--raw
选项以verify-tag
生成有关标准错误而不是人类可读格式的 gpg 状态信息。
加:
verify-tag
如果签名良好但密钥不受信任,则成功退出。verify-commit
退出失败。
这种行为上的差异是出乎意料和不受欢迎的。
由于verify-tag
较早存在,添加一个失败的测试以具有verify-commit
shareverify-tag
的行为。
git 2.9(2016 年 6 月)更新git 合并文档:
请参阅Keller Fuchs (``)的提交 05a5869(2016 年 5 月 13 日) 。
帮助者:Junio C Hamano ( )。(由Junio C Hamano 合并——在提交 be6ec17中,2016 年 5 月 17 日)
gitster
gitster
--verify-signatures:
--no-verify-signatures:
验证正在合并的侧分支的提示提交是否使用有效密钥签名,即具有有效 uid 的密钥:在默认信任模型中,这意味着签名密钥已由可信密钥签名。
如果侧分支的提示提交未使用有效密钥签名,则合并被中止。
更新 Git 2.10(2016 年第三季度)
请参阅Linus Torvalds ( )的提交 b624a3e(2016 年 8 月 16 日) 。(由Junio C Hamano 合并 -- --在83d9eb0 提交中,2016 年 8 月 19 日)torvalds
gitster
gpg-interface
: 验证 pgp 签名时首选“长”密钥格式输出
" git log --show-signature
" 和其他显示 PGP 签名验证状态的命令现在显示更长的 key-id,因为上世纪的 32 位 key-id 也是如此。
Linus 的原始版本被重新定位以适用于维护轨道,以防万一过去陷入困境的二进制分发者想要将其带到他们较旧的代码库中。
Git 2.11+(2016 年第四季度)将更加精确。
请参阅Michael J Gruber ( )的提交 661a180(2016 年 10 月 12 日) 。(由Junio C Hamano 合并——在提交 56d268b中,2016 年 10 月 26 日)mjg
gitster
“”漂亮格式说明符中显示的 GPG 验证状态%G?
不足以区分过期密钥的签名、撤销密钥的签名等。
已分配新的输出字母来表达它们。
根据gpg2的doc/DETAILS
:
对于每个签名,只会发出代码、 、 、或GOODSIG
中BADSIG
的EXPSIG
一个。EXPKEYSIG
REVKEYSIG
ERRSIG
git pretty-format
文档现在包括:
- '
%G?
': 显示
- "
G
" 代表一个好的(有效的)签名,
- "
B
" 代表错误的签名,
- "
U
" 用于具有未知有效性的良好签名,
- "
X
" 对于一个已经过期的好的签名,
- "
Y
" 用于由过期密钥生成的良好签名,
- "
R
" 用于由撤销的密钥生成的良好签名,
- “
E
”如果无法检查签名(例如缺少密钥),“ N
”表示没有签名
Git 2.12 (Q1 2017) " git tag
" 和 " git verify-tag
"学会了将 GPG 验证状态放在他们的 " --format=<placeholders>
" 输出格式中。
请参阅Santiago Torres ( )的commit 4fea72f、commit 02c5433、commit ff3c8c8(2017 年 1 月 17 日) 。
请参阅Lukas Puehringer (``)的提交 07d347c、提交 2111aa7、提交 94240b9(2017 年 1 月 17 日) 。(由Junio C Hamano 合并——在提交 237bdd9中,2017 年 1 月 31 日)SantiagoTorres
gitster
添加--format
到git tag -v
静音 GPG 验证的默认输出,而是打印格式化的标签对象。
这允许调用者在 GPG 验证时交叉检查来自 refs/tags 的标记名与来自标记对象头的标记名。
Git 2.16(2018 年第一季度)将允许提交签名验证更加自动化,并带有merge.verifySignatures
配置变量。
请参阅Hans Jerry Illikainen (``)的commit 7f8ca20和commit ca779e8(2017 年 12 月 10 日) 。(由Junio C Hamano 合并 -- --在0433d53 提交中,2017 年 12 月 28 日)
gitster
merge
: 添加配置选项verifySignatures
git merge --verify-signatures
可用于验证正在合并的分支的提示提交是否正确签名,但每次都必须指定它很麻烦。
添加一个默认启用此行为的配置选项,它可以被--no-verify-signatures
.
git merge
配置手册页现在显示为:
merge.verifySignatures:
如果为 true,则这等效于--verify-signatures
命令行选项。
Git 2.19(2018 年第三季度)更有帮助,因为“ git verify-tag
”和“ git verify-commit
”已被教导使用底层“ gpg --verify
”的退出状态来表示他们发现的错误或不受信任的签名。
注意:在 Git 2.19 中,gpg.format
可以设置为“ openpgp
”或“ x509
”,gpg.<format>.program
用于指定使用什么程序来处理格式)以允许通过“ gpgsm
”而不是openpgp
通过CMS 使用 x.509 证书“ gnupg
”。
请参阅Junio C Hamano ( ) 的提交 4e5dc9c(2018 年 8 月 9 日)。
帮助者:Vojtech Myslivec ( ) , brian m. 卡尔森 ( )和杰夫金 ( )。(由Junio C Hamano 合并 -- --在提交 4d34122中,2018 年 8 月 20 日)gitster
VojtechMyslivec
bk2204
peff
gitster
gpg-interface
: 将退出状态从gpg
后面传播给调用者
当 gpg-interface API 在 2015 年中期 v2.6.0-rc0~114 左右统一支持签名标签和签名提交的签名验证代码路径时,我们不小心放松了 GPG 签名验证。
G
在此更改之前,通过从 GPG 中查找“”ood 签名来验证签名提交,同时忽略“ gpg --verify
”进程的退出状态,而通过简单地传递“通过”的退出状态来验证签名标签"gpg --verify
。
我们目前拥有的统一代码忽略了“ gpg --verify
”的退出状态,当签名匹配一个未过期的密钥时返回成功验证,而不管对密钥的信任(即除了“ G
”之外,我们接受“ U
”未信任的)。
gpg --verify
当底层“ ”(或“ gpg.program
”配置变量指定的自定义命令)这样做时,使这些命令以其退出状态发出失败信号。
这实质上以向后不兼容的方式改变了它们的行为,以拒绝使用不受信任的密钥进行的签名,即使它们正确验证,因为这就是 " gpg --verify
" 的行为方式。
请注意,如果输出没有说签名是好的或计算正确但使用不受信任的密钥,代码仍然覆盖从“ gpg
”(或)获得的零退出状态,以捕获用户可能给我们的“”周围写得不好的包装器.gpg.program
gpg
我们可以从这个回退代码中排除 " U
"ntrusted 支持,但这会在一次提交中进行两个向后不兼容的更改,所以现在让我们避免这种情况。
如果需要,可以进行后续更改。
在进行任何加密之前,需要对密钥进行信任/签名
在信任方面,取得了进展:
在 Git 2.26(2020 年第一季度)中,gpg.minTrustLevel
引入了配置变量来告诉各种签名验证代码路径所需的最低信任级别。
请参阅Hans Jerry Illikainen ( ) 的提交 54887b4(2019 年 12 月 27 日)。(由Junio C Hamano 合并 -- --在提交 11ad30b中,2020 年 1 月 30 日)illikainen
gitster
签字人:汉斯·杰里·伊利凯宁
以前,合并和拉取操作的签名验证会检查密钥的信任级别是否为TRUST_NEVER
or 或TRUST_UNDEFINED
in verify_merge_signature()
。
如果是这样的话,这个过程die()
'd。
其他进行签名验证的代码路径完全依赖于check_commit_signature()
.
使用好的密钥制作的签名,无论其信任级别如何,都被认为是有效的check_commit_signature()
。
这种行为差异可能会导致用户错误地假设 Git 始终考虑其密钥环中密钥的信任级别,即使对于不考虑的操作(例如在 averify-commit
或期间verify-tag
)也是如此。
它的工作方式是gpg-interface.c
将密钥/签名状态的结果和result
结构成员中最低的两个信任级别存储起来signature_check
(遇到的这些状态行中的最后一个被写入result
)。
这些在 GPG 中分别记录在General status codes
和小节下Key related
。
GPG 文档在TRUST_ status
代码上说明了以下内容:
这些是几个类似的状态代码:
- TRUST_UNDEFINED <error_token>
- TRUST_NEVER <error_token>
- TRUST_MARGINAL [0 [<validation_model>]]
- TRUST_FULLY [0 [<validation_model>]]
- TRUST_ULTIMATE [0 [<validation_model>]]
对于良好的签名,发出这些状态行之一以指示用于创建签名的密钥的有效性。
错误标记值当前仅由 gpgsm 发出。
我的解释是信任级别在概念上与密钥和/或签名的有效性不同。
这似乎也是旧代码的假设,check_signature()
其中 ' G
' (如GOODSIG
)和 ' U
' (如TRUST_NEVER
或TRUST_UNDEFINED)
都被认为是成功的。
U
' ' 的结果具有特殊含义的两种情况是 in (这会verify_merge_signature()
导致)和 in (它影响格式说明符的输出)。git
die()
format_commit_one()
%G?
我认为重构行的处理是有意义的,TRUST_ status
这样用户可以配置全局强制执行的最低信任级别,而不是让各个部分git
(例如合并)自己做(除了具有向后兼容性的宽限期)。
我也认为不将信任级别存储在与密钥/签名状态相同的结构成员中是有意义的。
虽然TRUST_ status
代码的存在确实意味着签名是好的(参见上面包含的片段中的第一段),但据我所知,GPG 中状态行的顺序没有明确定义;因此,如果信任级别存储在结构的同一成员中,则似乎可以用密钥/签名状态覆盖信任级别signature_check
。
此补丁引入了一个新的配置选项:gpg.minTrustLevel
.
它将信任级别验证合并到结构中并向结构中gpg-interface.c
添加新trust_level
成员signature_check
。
向后兼容性是通过引入一种特殊情况来维护的verify_merge_signature()
,如果没有设置用户可配置项,则会强制执行gpg.minTrustLevel
旧的拒绝行为。TRUST_UNDEFINED
TRUST_NEVER
另一方面,如果gpg.minTrustLevel
已设置,则该值将覆盖旧行为。
类似地,%G?
格式说明符将继续U
为使用具有信任级别的密钥创建的签名显示 ' ',TRUST_UNDEFINED
或者TRUST_NEVER,
即使结构成员中U
不再存在“ ”字符。result
signature_check
%GT
还为希望显示签名的所有可能信任级别的用户引入了新的格式说明符。
另一种方法是简单地将信任级别要求放在verify_merge_signature()
.
这也将使行为与执行签名验证的 git 的其他部分保持一致。
但是,要求签署密钥的最低信任级别似乎确实有一个真实的用例。
例如,Qubes OS 项目使用的构建系统当前解析来自 verify-tag 的原始输出,以便为用于签署 git tags的密钥声明最低信任级别。
git config gpg
手册页现在包括:
gpg.minTrustLevel:
指定签名验证的最低信任级别。
如果未设置此选项,则合并操作的签名验证需要至少marginal
信任的密钥。
执行签名验证的其他操作需要至少undefined
信任的密钥。
设置此选项会覆盖所有操作所需的信任级别。支持的值,按重要性升序排列:
undefined
never
marginal
fully
ultimate
在Git 2.26 (Q1 2020)中," git show
" 和其他人在其错误输出中以原始格式提供了一个对象名称,该名称已更正为以十六进制形式提供。
show_one_mergetag:以十六进制形式打印非父级。
当一个合并标签命名一个非父级时,这可能发生在一个浅克隆之后,它的哈希之前被打印为原始数据。
改为以十六进制形式打印。
git -C shallow log --graph --show-signature -n1 plain-shallow
经过一段时间的测试git clone --depth 1 --no-local . shallow
在 Git 2.27(2020 年第二季度)中,与 GnuPG 交互的代码已经过重构。
参见提交 6794898,提交 f1e3df3(2020 年 3 月 4 日),作者Hans Jerry Illikainen ( illikainen
)。
(由Junio C Hamano 合并 -- gitster
--在fa82be9 提交中,2020 年 3 月 27 日)
gpg-interface
: 首选check_signature()
GPG 验证
签字人:汉斯·杰里·伊利凯宁
此提交重构了使用verify_signed_buffer()
outside ofgpg-interface.c
来check_signature()
代替使用。
它也变成verify_signed_buffer()
了文件本地函数,因为它现在仅由check_signature()
.
以前在 Git 的不同部分中使用了两个全局范围的函数来执行 GPG 签名验证:verify_signed_buffer()
和check_signature()
.
现在只check_signature()
使用。
如 Michał Górny 所述,该verify_signed_buffer()
函数不能防止重复签名。
相反,它只确保 GPG 的退出代码正确无误,并且至少存在一个GOODSIG
状态字段。
这与check_signature()
遇到多个签名时返回错误相反。
verify_signed_buffer()
如果调用者自己不解析和验证 GPG 状态消息的各个部分,则较低程度的验证会导致使用问题。
处理这些消息似乎是一项应该保留给gpg-interface.c
函数的任务check_signature()
。
此外,使用verify_signed_buffer()
使得引入依赖于 GPG 状态行内容的新功能变得困难。
现在所有进行签名验证的操作都共享一个到gpg-interface.c
.
这使得将 GPG 签名验证中的更改或附加功能传播到 Git 的所有部分变得更加容易,而不会出现不执行相同程度验证的奇怪边缘情况。
使用 Git 2.31(2021 年第一季度),签名提交和标签现在允许验证对象,其两个对象名称(一个在 SHA-1 中,另一个在 SHA-256 中)都已签名。
请参阅提交 9b27b49、提交 88bce0e、提交 937032e、提交 482c119(2021 年 2 月 11 日)和提交 1fb5cf0、提交 83dff3e(2021 年 1 月 18 日),作者为brian m。卡尔森 ( bk2204
) .
(由Junio C Hamano 合并 -- gitster
--在提交 15af6e6中,2021 年 2 月 22 日)
commit
: 解析签名提交时忽略其他签名
签字人:brian m. 卡尔森
当我们创建具有多个签名的提交时,这些签名都不包含另一个。
因此,当我们生成已签名的有效负载以便我们可以验证提交时,我们必须剥离任何其他签名,否则有效负载将与已签名的不同。
这样做,并准备使用多种算法进行验证,将我们要验证的算法传递到parse_signed_commit
.
Brandon在评论中提出了一个git log
别名,它显示了关键状态:
[alias]
lg = "!f() { \
git log --all --color --graph --pretty=format:'%C(bold yellow)<sig>%G?</sig>%C(reset) %C(red)%h%C(reset) -%C(yellow)%d%C(reset) %s %C(green)(%cr) %C(blue)<%an>%C(reset)' | \
sed \
-e 's#<sig>G</sig>#Good#' \
-e 's#<sig>B</sig>#\\nBAD \\nBAD \\nBAD \\nBAD \\nBAD#' \
-e 's#<sig>U</sig>#Unknown#' \
-e 's#<sig>X</sig>#Expired#' \
-e 's#<sig>Y</sig>#Expired Key#' \
-e 's#<sig>R</sig>#Revoked#' \
-e 's#<sig>E</sig>#Missing Key#' \
-e 's#<sig>N</sig>#None#' | \
less -r; \
}; f"