【问题标题】:What data is being signed when you `git commit --gpg-sign=<key-id>`?`git commit --gpg-sign=<key-id>` 时正在对哪些数据进行签名?
【发布时间】:2014-05-10 18:50:09
【问题描述】:

我试图弄清楚如何手动签署/验证提交,但我无法弄清楚正在签署哪些数据来创建签名。换句话说,我无法弄清楚gpg --verify &lt;commit-sig&gt; &lt;data&gt; 中的&lt;data&gt; 需要是什么。

这是 git 源代码的相关部分:https://github.com/git/git/blob/master/commit.c#L1047-L1231 但我也是 C 新手。


以下是一些示例数据:

在一个新的 git repo 中,我创建了一个文件 ledger.txt 并使用签名提交来提交它:

git config --global user.signingkey 7E482429
git init
echo "EAC5-531F-38E8-9670-81AE-4E77-C7AA-5FC3-7E48-2429 1\n" > ledger.txt
git add ledger.txt
git commit -m "Initial commit" --gpg-sign=7E482429

它在日志中:

git log --show-signature

    commit 876793da21833b5b8197b08462523fd6aad3e5ba
    gpg: Signature made Fri May  9 20:01:55 2014 CDT using RSA key ID 7E482429
    gpg: Good signature from "Dan Neumann <danrodneu@gmail.com>"
    Author: Dan Neumann <danrodneu@gmail.com>
    Date:   Fri May 9 20:01:55 2014 -0500

        Initial commit

这是打印精美的提交对象(位于.git/objects/87/6793da21833b5b8197b08462523fd6aad3e5ba):

git cat-file -p 876793da21833b5b8197b08462523fd6aad3e5ba

tree 70e7c184c3a89c749174b4987830c287fd78952d
author Dan Neumann <danrodneu@gmail.com> 1399683715 -0500
committer Dan Neumann <danrodneu@gmail.com> 1399683715 -0500
gpgsig -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1

 iQEcBAABAgAGBQJTbXqDAAoJEMeqX8N+SCQpTBIH/3zCpf0w0+xp8hkwz7dTV9Bw
 ercZp4UpxKV1HgqCxu2r/nGIuZyabLwTis1rcwXOVC4DgRxO0f2BiP0xnyL3OhJu
 CKh8l+HZvvGqVH3Dopm0D/kOxDAWHcjokbyzWBbYJX6WhvT8OI7SSYmwuF4r610h
 hkZ1xgjo4p1x9WegY296PzA1wEe6yy9BvvdIpJHoqBVKClgFrZvtE5PidbrAyLGF
 Kl/2f0K3peBdo6XP0Zaml8NyQlFmAlCV831hHgUmZsBSRpgh/WNvrDSNILTlFJgY
 BOPb2yPP+tiJOXYB66MsjQY9GlX7n43miu5wMtdk1AGqh+26OExbSrZcYVFLk4w=
 =sRee
 -----END PGP SIGNATURE-----

Initial commit

这里是提交对象文件的实际内容:

hexdump .git/objects/87/6793da21833b5b8197b08462523fd6aad3e5ba | \
zlib-decompress | \
bin-to-ascii

commit 671\0tree 70e7c184c3a89c749174b4987830c287fd78952d\nauthor Dan Neumann <danrodneu@gmail.com> 1399683715 -0500\ncommitter Dan Neumann <danrodneu@gmail.com> 1399683715 -0500\ngpgsig -----BEGIN PGP SIGNATURE-----\n Version: GnuPG v1\n \n iQEcBAABAgAGBQJTbXqDAAoJEMeqX8N+SCQpTBIH/3zCpf0w0+xp8hkwz7dTV9Bw\n ercZp4UpxKV1HgqCxu2r/nGIuZyabLwTis1rcwXOVC4DgRxO0f2BiP0xnyL3OhJu\n CKh8l+HZvvGqVH3Dopm0D/kOxDAWHcjokbyzWBbYJX6WhvT8OI7SSYmwuF4r610h\n hkZ1xgjo4p1x9WegY296PzA1wEe6yy9BvvdIpJHoqBVKClgFrZvtE5PidbrAyLGF\n Kl/2f0K3peBdo6XP0Zaml8NyQlFmAlCV831hHgUmZsBSRpgh/WNvrDSNILTlFJgY\n BOPb2yPP+tiJOXYB66MsjQY9GlX7n43miu5wMtdk1AGqh+26OExbSrZcYVFLk4w=\n =sRee\n -----END PGP SIGNATURE-----\n\nInitial commit\n

【问题讨论】:

  • git log --show-signature 将为您验证签名(请参阅this question)。那么,为什么——除了知道被签名的确切数据——你想在低级别上弄乱 git 对象? :) (+1 表示您的好问题的价值。)
  • 好问题。我正在探索同样的事情。基本上,问题归结为:为了让git cat-file -p 876793da21833b5b8197b08462523fd6aad3e5ba | something | gpg --verify - 产生“良好的签名”,something 的正确值是多少?你找到答案了吗?

标签: git gnupg


【解决方案1】:

看了commit_tree_extended中的代码,看来用来签名的数据是从“树”到注释末尾​​的部分,当然不包括签名。

在你的例子中,它应该是:

tree 70e7c184c3a89c749174b4987830c287fd78952d
author Dan Neumann <danrodneu@gmail.com> 1399683715 -0500
committer Dan Neumann <danrodneu@gmail.com> 1399683715 -0500

Initial commit

From the git source:

缓冲区初始化:

strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */
strbuf_addf(&buffer, "tree %s\n", sha1_to_hex(tree));

父提交遍历:

/*
* NOTE! This ordering means that the same exact tree merged with a
* different order of parents will be a _different_ changeset even
* if everything else stays the same.
*/
while (parents) {
    struct commit_list *next = parents->next;
    struct commit *parent = parents->item;

    strbuf_addf(&buffer, "parent %s\n",
    sha1_to_hex(parent->object.sha1));
    free(parents);
    parents = next;
}

人员/日期信息:

if (!author)
    author = git_author_info(IDENT_STRICT);
strbuf_addf(&buffer, "author %s\n", author);
strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_STRICT));
if (!encoding_is_utf8)
    strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);

while (extra) {
    add_extra_header(&buffer, extra);
    extra = extra->next;
}
strbuf_addch(&buffer, '\n');

注释和编码检查:

/* And add the comment */
strbuf_addbuf(&buffer, msg);

/* And check the encoding */
if (encoding_is_utf8 && !verify_utf8(&buffer))
    fprintf(stderr, commit_utf8_warn);

这就是签名发生的地方。签名将添加在标题之后。

if (sign_commit && do_sign_commit(&buffer, sign_commit))
    return -1;

如果您的提交有一些父信息,也会有父信息。

【讨论】:

  • 如果可能的话,我建议将代码部分分成更小的部分,这样人们就不必在里面垂直滚动来查看整个内容。
  • 所以它是代码的 SHA-1 摘要的签名?听起来是个坏主意。
【解决方案2】:

这个答案正在进行中。

背景

首先,对当前 Git 签名机制存在的问题进行一些反思。

理想情况下,Git 会使用 GnuPG 的一种内置签名机制。如果这样做了,那么只需使用 GnuPG 的 gpg --verifygpg2 --verify,就可以轻松验证 Git 提交,而无需调用 Git 或编写脚本。

在这方面,很遗憾 Git 没有采用 Linux Kernel Mailing List in 2005 中提出的 GnuPG 的“分离签名”签名机制。最近,Owen Jacobson 列出了一些 additional reasons 为什么分离签名比 Git 当前的方法更受欢迎。他指出,目前:

  • 签名嵌入在他们签名的对象中。签名是对象身份的一部分;由于 Git 是内容寻址的,这意味着在不修改对象身份的情况下,既不能对对象进行追溯签名,也不能追溯剥离其签名。 Git 的分布式模型意味着这类身份更改既复杂又容易检测。

  • 提交签名是二等公民。它们是 Git 套件中相对较新的成员,围绕它们的实施和社会惯例都在不断发展。

  • 只能对某些对象进行签名。虽然 Git 关于工作流的规则相对较弱,但签名系统通过将选项限制为最多一个签名以及将签名限制为标签和提交(省略 blob、树和引用)来假设您正在使用 Git 更广泛的工作流之一)。

Mike Gerwitz points out Git 当前方法的最严重后果之一。 Git 提交同时具有“提交者”和“作者”字段,允许提交者和提交者是两个不同的人。然而,Git 提交目前只允许包含一个签名。那么,应该是谁的签名呢?理想情况下,作者提交者都能够签署提交。分离的签名将允许这样做。就此而言,嵌套的内联签名也是如此。但是因为 Git 不使用这些选项中的任何一个,它迫使我们在两个不满意的选项之间进行选择:

  1. 提交者剥离作者的签名并自己签署提交。

  2. 提交者拒绝签署提交。

总结了坏消息。好消息是Git 的GnuPG 包装器至少包含git log--show-signature 选项,它使用GnuPG 验证签名。这允许 Git 日志显示签名是否由带有您信任的 UID 的密钥生成。

如果是,GnuPG 会显示:

Good signature from "John Doe <john.doe@example.com>"

如果没有,GnuPG 会显示:

Good signature from "John Doe <john.doe@example.com>"
WARNING: This key is not certified with a trusted signature!
         There is no indication that the signature belongs to the owner.

你的问题

Poko's answer 中所示,您的提交从表面上看等同于以下明确签名的文档:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

tree 70e7c184c3a89c749174b4987830c287fd78952d
author Dan Neumann <danrodneu@gmail.com> 1399683715 -0500
committer Dan Neumann <danrodneu@gmail.com> 1399683715 -0500
Initial commit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAABAgAGBQJTbXqDAAoJEMeqX8N+SCQpTBIH/3zCpf0w0+xp8hkwz7dTV9Bw
ercZp4UpxKV1HgqCxu2r/nGIuZyabLwTis1rcwXOVC4DgRxO0f2BiP0xnyL3OhJu
CKh8l+HZvvGqVH3Dopm0D/kOxDAWHcjokbyzWBbYJX6WhvT8OI7SSYmwuF4r610h
hkZ1xgjo4p1x9WegY296PzA1wEe6yy9BvvdIpJHoqBVKClgFrZvtE5PidbrAyLGF
Kl/2f0K3peBdo6XP0Zaml8NyQlFmAlCV831hHgUmZsBSRpgh/WNvrDSNILTlFJgY
BOPb2yPP+tiJOXYB66MsjQY9GlX7n43miu5wMtdk1AGqh+26OExbSrZcYVFLk4w=
=sRee
-----END PGP SIGNATURE-----

但是,假设我们将其保存为 danneau_stackoverflow_example.asc 并尝试验证它,输出如下:

$ gpg --verify danneau_stackoverflow_example.asc 
gpg: Signature made Sat 10 May 2014 02:01:55 BST
gpg:                using RSA key C7AA5FC37E482429
gpg: Can't check signature: public key not found

GnuPG 的意思是,因为我没有你的公钥,它实际上无法判断签名是好是坏。所以,即使我篡改了内容,我也会得到相同的输出:

$ echo "-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

tree 70e7c184c3a89c749174b4987830c287fd78952d
author Dan Neumann <danrodneu@gmail.com> 1399683715 -0500
committer Dan Neumann <danrodneu@gmail.com> 1399683715 -0500

EVIL MESSAGE HERE

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAABAgAGBQJTbXqDAAoJEMeqX8N+SCQpTBIH/3zCpf0w0+xp8hkwz7dTV9Bw
ercZp4UpxKV1HgqCxu2r/nGIuZyabLwTis1rcwXOVC4DgRxO0f2BiP0xnyL3OhJu
CKh8l+HZvvGqVH3Dopm0D/kOxDAWHcjokbyzWBbYJX6WhvT8OI7SSYmwuF4r610h
hkZ1xgjo4p1x9WegY296PzA1wEe6yy9BvvdIpJHoqBVKClgFrZvtE5PidbrAyLGF
Kl/2f0K3peBdo6XP0Zaml8NyQlFmAlCV831hHgUmZsBSRpgh/WNvrDSNILTlFJgY
BOPb2yPP+tiJOXYB66MsjQY9GlX7n43miu5wMtdk1AGqh+26OExbSrZcYVFLk4w=
=sRee
-----END PGP SIGNATURE-----
" | gpg --verify -
gpg: Signature made Sat 10 May 2014 02:01:55 BST
gpg:                using RSA key C7AA5FC37E482429
gpg: Can't check signature: public key not found

所以这意味着 Poko 可能根本没有正确弄清楚你到底签署了什么。

为了弄清楚这一点,我尝试将由我确实拥有的相应公钥的私钥签名的提交转换为明文签名文件,然后将它们传递给 GnuPG 进行验证。到目前为止,我只收到过“签名错误”的回复。如果我弄清楚我哪里出错了,我会更新这个答案。

【讨论】:

  • “理想情况下,作者和提交者都能够签署提交。” -- 如果提交者不是原作者,那么原作者不是提交者,并且 (a) 不能和 (b) 不应该签名。
  • 您是否了解如何将提交转移到明确签名的消息中?或者您是否能够为分离签名验证生成签名内容?​​
  • 根据传递给 gpg 的标志创建分离签名
猜你喜欢
  • 1970-01-01
  • 2019-03-19
  • 2021-05-08
  • 1970-01-01
  • 1970-01-01
  • 2016-10-12
  • 1970-01-01
  • 1970-01-01
  • 2021-10-25
相关资源
最近更新 更多