你git commit -gpg-sign = <key-id>`时会签署什么数据?</key-id>

时间:2014-05-10 18:50:10

标签: c git gnupg

我试图弄清楚如何手动签署/验证提交,但我无法弄清楚正在签署哪些数据来创建签名。换句话说,我无法弄清<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

2 个答案:

答案 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

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');

评论&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 --verifygpg2 --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不使用这些选项中的任何一个,它迫使我们在两个不满意的选项之间做出选择:

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

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

  3. 总结了坏消息。好消息是,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进行验证,这些提交由私钥(我将 拥有的相应公钥签名)转换为清除文件。到目前为止,我只收到过“签名错误”的回复。如果我弄清楚我哪里出错了,我会更新这个答案。