我试图弄清楚如何手动签署/验证提交,但我无法弄清楚正在签署哪些数据来创建签名。换句话说,我无法弄清<data>
中gpg --verify <commit-sig> <data>
需要的内容。
以下是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
答案 0 :(得分:5)
在阅读 commit_tree_extended 中的代码后,用于签名的数据似乎是&#34; tree&#34;在评论的最后,当然不包括签名。
在您的示例中,它应该是:
tree 70e7c184c3a89c749174b4987830c287fd78952d
author Dan Neumann <danrodneu@gmail.com> 1399683715 -0500
committer Dan Neumann <danrodneu@gmail.com> 1399683715 -0500
Initial commit
缓冲区初始化:
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');
评论&amp;编码检查:
/* 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;
如果你的提交有一些,那么也会有父信息。
答案 1 :(得分:1)
这个答案正在进行中。
首先,对当前Git签名机制的问题进行一些反思。
理想情况下,Git会使用GnuPG的内置签名机制之一。如果它这样做,那么只需使用GnuPG的gpg --verify
或gpg2 --verify
就可以轻松验证Git提交而无需调用Git或编写脚本。
在这方面,很遗憾Git没有采用GnuPG的“分离签名”签名机制,正如Linux内核邮件列表in 2005所提出的那样。最近,Owen Jacobson列出了一些additional reasons,为什么超过Git的当前方法需要分离签名。他指出目前:
签名嵌入在他们签名的对象中。签名是对象身份的一部分;由于Git是内容寻址的,这意味着在不修改对象身份的情况下,对象既不能追溯签名也不能追溯剥离其签名。 Git的分布式模型意味着这些类型的身份变化既复杂又易于检测。
提交签名是二等公民。它们是Git套件中最近的一个新增功能,它们的实现和社交约定都在不断发展。
只能签署一些对象。虽然Git对工作流程的规则相对较弱,但签名系统假设您使用Git更广泛的工作流程之一,将您的选项限制为最多一个签名,并将签名限制为标记和提交(省略blob,树和refs) )。
Mike Gerwitz points out是Git目前做法最严重的后果之一。 Git提交有一个“提交者”和一个“作者”字段,允许提交者和提交者作为两个独立的人。但是,Git提交目前只允许包含一个签名。那么,谁的签名呢?理想情况下,提交者的作者和都能够签署提交。分离的签名将允许这样做。因此,嵌套的内联签名也是如此。但是因为Git不使用这些选项中的任何一个,它迫使我们在两个不满意的选项之间做出选择:
提交者剥离作者的签名并自己签署提交。
提交者拒绝签署提交。
总结了坏消息。好消息是,Git的GnuPG包装器至少包含--show-signature
的{{1}}选项,它使用GnuPG验证签名。这允许Git日志显示签名是否由带有您信任的UID的密钥创建。
如果是,GnuPG将显示:
git log
如果没有,GnuPG将显示:
Good signature from "John Doe <john.doe@example.com>"
如Poko's answer所示,您的提交在其表面上显示为等同于以下已清除的文档:
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.
但是,假设我们将其保存为-----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
GnuPG的意思是因为我没有你的公钥,所以它实际上无法判断签名是好还是坏。所以,即使我篡改内容,我也得到相同的输出:
$ 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
所以这意味着Poko可能没有正确地弄清楚你究竟签了什么。
为了解决这个问题,我尝试将提交的提交转换为清除文件,然后将它们传递给GnuPG进行验证,这些提交由私钥(我将 拥有的相应公钥签名)转换为清除文件。到目前为止,我只收到过“签名错误”的回复。如果我弄清楚我哪里出错了,我会更新这个答案。