你在git commit –gpg-sign = `时签署了什么数据?

我正试图弄清楚如何手动签署/validation提交,但我无法弄清楚正在签署哪些数据来创建签名。 换句话说,我无法弄清楚gpg --verify 是什么gpg --verify

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


这是一些示例数据:

在一个新的git ledger.txt ,我创建了一个文件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 " Author: Dan Neumann  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  1399683715 -0500 committer Dan Neumann  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  1399683715 -0500\ncommitter Dan Neumann  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 

在读取commit_tree_extended中的代码后,用于签名的数据似乎是从“树”到注释末尾​​的部分,当然不包括签名。

在您的示例中,它应该是:

 tree 70e7c184c3a89c749174b4987830c287fd78952d author Dan Neumann  1399683715 -0500 committer Dan Neumann  1399683715 -0500 Initial commit 

来自git源码 :

缓冲区的初始化:

 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; 

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

这个答案是一项正在进行的工作。

背景

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

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

在这方面,很遗憾Git没有采用GnuPG的“独立签名”签名机制,正如2005年 Linux内核邮件列表中提出的那样 。 最近,Owen Jacobson列出了一些额外的原因,为什么超出签名比Git目前的方法更合适。 他指出目前:

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

  • 承诺签名是二等公民。 它们是Git套件中最近的一个新增function,它们的实现和社交约定都在不断发展。

  • 只能签署一些对象。 虽然Git对工作流程的规则相对较弱,但签名系统假设您使用Git更广泛的工作流程之一,将您的选项限制为最多一个签名,并将签名限制为标记和提交(省略blob,树和refs) )。

Mike Gerwitz 指出了 Git目前方法中最严重的后果之一。 Git提交有一个“提交者”和一个“作者”字段,允许提交者和提交者作为两个独立的人。 但是,Git提交目前只允许包含一个签名。 那么,谁的签名呢? 理想情况下,作者提交者都可以签署提交。 分离的签名将允许这样做。 因此,嵌套的内联签名也是如此。 但是因为Git不使用这些选项中的任何一个,它迫使我们在两个不满意的选项之间做出选择:

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

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

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

如果是,GnuPG将显示:

 Good signature from "John Doe " 

如果没有,GnuPG将显示:

 Good signature from "John Doe " WARNING: This key is not certified with a trusted signature! There is no indication that the signature belongs to the owner. 

你的问题

如Poko的回答所示 ,从表面上看,您的提交似乎等同于以下已清除的文档:

 -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 tree 70e7c184c3a89c749174b4987830c287fd78952d author Dan Neumann  1399683715 -0500 committer Dan Neumann  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并尝试validation它,这是输出:

 $ 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  1399683715 -0500 committer Dan Neumann  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进行validation。 到目前为止,我只收到过“签名不好”的回复。 如果我弄清楚我哪里出错了,我会更新这个答案。