Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What data is being signed when you `git commit --gpg-sign=<key-id>`?

Tags:

git

gnupg

I'm trying to figure out how to sign/verify commits by hand, but I can't figure out what data is being signed to create the signature. In other words, I can't figure out what <data> in gpg --verify <commit-sig> <data> needs to be.

Here's the relevant bit of git's source code: https://github.com/git/git/blob/master/commit.c#L1047-L1231 but I'm also new to C.


Here's some example data:

In a fresh git repo, I create a file ledger.txt and commit it with a signed commit:

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

And here it is in the log:

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 <[email protected]>"
    Author: Dan Neumann <[email protected]>
    Date:   Fri May 9 20:01:55 2014 -0500

        Initial commit

Here's the pretty-printed commit object (which lives in .git/objects/87/6793da21833b5b8197b08462523fd6aad3e5ba):

git cat-file -p 876793da21833b5b8197b08462523fd6aad3e5ba

tree 70e7c184c3a89c749174b4987830c287fd78952d
author Dan Neumann <[email protected]> 1399683715 -0500
committer Dan Neumann <[email protected]> 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

And here are the actual contents of the commit object file:

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

commit 671\0tree 70e7c184c3a89c749174b4987830c287fd78952d\nauthor Dan Neumann <[email protected]> 1399683715 -0500\ncommitter Dan Neumann <[email protected]> 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
like image 500
danneu Avatar asked May 10 '14 18:05

danneu


People also ask

What is signing key ID in git?

If you're using a GPG key that matches your committer identity and your verified email address associated with your account on GitHub.com, then you can begin signing commits and signing tags. If you don't have a GPG key that matches your committer identity, you need to associate an email with an existing key.

What is GPG signing key?

GPG keys are a way to sign and verify work from trusted collaborators. This page describes how to generate a GPG key to sign and verify commits and tags for use with Bitbucket Data Center and Server.


1 Answers

After reading the code in commit_tree_extended, it seems the data used to sign is the part from "tree" to the end of the comment, of course excluding the signature.

In your example, it should be:

tree 70e7c184c3a89c749174b4987830c287fd78952d
author Dan Neumann <[email protected]> 1399683715 -0500
committer Dan Neumann <[email protected]> 1399683715 -0500

Initial commit

From the git source:

Init of buffer:

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

Parent commits traversing:

/*
* 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;
}

Person/date information:

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

The comment & encoding check:

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

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

That's where the signing happens. Signature will be added after the header.

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

There would be parent information too if your commit had some.

like image 66
PoKo Avatar answered Oct 13 '22 23:10

PoKo