How to sign your project's git history

by on

Git lists the author of every commit ever made to a repository. This comes in quite handy, but is easy to fake. Author data is simply read from the configuration file without any validation. This means you could easily commit to an (open source) repository and pretend to be me.

git config --global "Your Name"
git config --global

The author data is especially important when something goes wrong. Imagine a certain commit caused a security issue, or broke software in a way that should have been caught by tests. Who made this change? It is clear that we shouldn’t trust the author listed by git log in this case.

Tags have partially solved this issue by allowing you to PGP sign them. As the git commit hash includes the parent hash, this signature validates the complete history up to that specific tag. The PGP signature is made by your personal key and is harder to fake.

Tags with a signature

Creating a signed tag is easy once you have set up your private key in GnuPG. Simply call the tag command with the -s flag to sign the tag as you create it.

git tag -s <name>

Git should be able to automatically find your PGP key based on the e-mail address you’ve listed in the setting. In case you don’t want git to figure this out, it is also possible to set a default signing key globally:

git config --global user.signingkey 1234ABCD

That’s it! Now your tag is signed. This moves the problem but doesn’t actually solve it. Signed tags allow you to declare that you have checked the commit log and verified that it wasn’t tampered with. It is now possible to verify the tag using git tag -v. This works fine for small projects and teams with only a few developers. But what if you’re managing something bigger?

Your initial problem remains: How do you know for sure who changed your code? The real solution is obvious…

Signing every commit

Git v1.7.9 introduced the ability to cryptographically sign commits, similar to how it works with tags. The difference here is that the shortcode is uppercase -S as the lowercase flag is used for the Signed-off-by field already. Other than that, usage is pretty much the same.

git commit -am "Fixed something somewhere" -S 1234ABCD

There is quite a bit discussion about wether it is useful to sign every commit. Linus Torvalds explained why he thinks signing commits is a bad idea on a mailing list several years ago. The most important part is quoted below, but you should really read the whole message to get the full picture:

Signing each commit is totally stupid. It just means that you automate it, and you make the signature worth less. It also doesn’t add any real value, since the way the git DAG-chain of SHA1’s work, you only ever need one signature to make all the commits reachable from that one be effectively covered by that one. So signing each commit is simply missing the point.

Git doesn’t provide a way to automatically sign every commit, although you could use a bash alias or something similar to make signing semi-automatic.