12

I am currently wondering how git commit signing exactly works.

Tried to find this out but could not find any exact technical documentation. I am aware how to do git commit signing but am wondering what exactly git does to sign a commit.

What exactly is it that is signed? Is it the full data inside the repository at the given commit, so the data like the commit message etc. and the data of all files? Or is it only the commit with pointers to the contained files etc?

Markus Kreusch
  • 2,071
  • 3
  • 19
  • 33

2 Answers2

9

Although it's not documented anywhere, examination of the source code shows that it's the entire contents of the commit object. Those contents then get modified to insert the signature, so that the verification process must strip out the signature into a separate buffer and pass the original, pre-signature-insertion, data to the GPG signer.

The GPG signature data then take place in calculating the SHA-1 checksum for the commit to become the commit's hash ID. See gpg-interface.c and commit.c, functions sign_buffer and do_sign_commit respectively. The tag signing is in builtin/tag.c (see function do_sign and its caller); signed tags have their signatures appended rather than inserted, but otherwise this works pretty much the same way.

torek
  • 448,244
  • 59
  • 642
  • 775
  • Your assumption I asked inspired by the SHA-1 demo was correct ;) Just to be sure I understood the code correctly (I am more a Java, not a C guy). Only the commit object containing the SHA-1 reference to the tree is signed. So if I have a signed commit I can not be sure the tree is correct but only that the signer created a commit for a tree with the same hash? That's really sad... – Markus Kreusch Feb 24 '17 at 20:59
  • 1
    @MarkusKreusch: yes, the signature *directly* protects only the contents of the commit or tag object. However, commit and tag objects have a fairly obvious form (despite being allowed to contain arbitrary text), and the existing technique for defeating SHA-1 leaves behind an obvious trace. Tree objects have an even-more constrained form: Git could (and should already) easily detect malformed trees. Only blob objects are really subject to second-preimage attacks. All that said, it would be nice if Git could start using SHA-256, but the transition will be rather rough. – torek Feb 24 '17 at 21:57
  • (See also http://stackoverflow.com/q/42433126/1256452 and the link to the mailing list therein.) – torek Feb 24 '17 at 22:21
  • Thanks for the link. Had a closer look at the paper now and came to the conclusion that in this form it will not be possible to use it to create collisions for an existing "good" object in a git repo. But nevertheless would be happy to see Git using SHA-256. – Markus Kreusch Feb 25 '17 at 12:12
  • Statement from Linus regarding git and sha1: https://plus.google.com/+LinusTorvalds/posts/7tp2gYWQugL – Markus Kreusch Feb 26 '17 at 11:08
6

It's the raw commit object returned by git cat-file (with the signature removed) that's signed. If HEAD is a signed commit, you can verify the signature by hand as follows:

git cat-file commit HEAD > signed-commit
grep -B 9999 'BEGIN PGP SIGNATURE-----' signed-commit | head -n -1 > signed-commit.stripped
grep -A 9999 'END PGP SIGNATURE-----' signed-commit | tail -n +2 >> signed-commit.stripped
sed 's/^gpgsig //' signed-commit | sed 's/^ //' > signed-commit.sig
gpg --verify signed-commit.sig signed-commit.stripped 
MMGen
  • 61
  • 1
  • 3
  • this comment shows a clear example of how to evaluate the signed commit without using a git command Added a sample here: https://gist.github.com/stackdump/846c1358f9b8576173f95216abb04c88 – stackdump Jun 23 '19 at 19:53