Friday, February 9, 2018

Do not use git's built in gpg signing until git uses something other than SHA-1

If you trust SHA-1 and think it's secure then this post isn't for you.

If you think SHA-1 has been weak for years, is not sufficient now, and is dangerous moving into the future, this post is for you.

Git's online documentation describes how to sign a git commit.
$ git commit -a -S -m 'signed commit'
The massive elephant in the tiny git security room is that SHA-1 is no longer considered secure, and has been considered weak for a long time (about 13 years).  Bruce Schneier warned in February 2005 that SHA-1 needed to be replaced.  Git development didn't start until April 2005.  Before git had started development, SHA-1 was identified as needing to be deprecated.

When signing a git commit using the built in gpg function the project is not rehashed with a secure hash function, like SHA-256 or SHA3-256.  Instead, gpg signs the commit hash directly.

And yes, this commit hash is still a SHA-1 hash.   It's not signing the result of a secure hash algorithm.

A signing algorithm is only as good as its weakest point.  Just because something is signed doesn't magically make it secure if the underlying hash algorithm is insecure.  Worse, if a secure hash algorithm, like SHA-3, hashes the result of an insecure hash algorithm, like the git commit hash, the result is still insecure.

To make signing git code secure, the SHA-1 hash should be discarded and everything must be rehashed with a secure algorithm before signing.  This however is not yet standardized in the git world.  Anything one does securely will not be relevant for existing git infrastructure.  Go ahead and sign your code using something secure, your square peg won't fit into git's infrastructure.  Anything secure will need infrastructure over and above git to ensure security.

Git is moving to support secure hashes, but it's not adopted yet.  Even when it is, it will take time for the infrastructure to catch up.

So what's so bad about signing a SHA-1 hash?  If an attacker finds a collision they can have two copies of a repository, a good version and a bad version both with the signature's blessing. Google's security blog has better examples, but for simplicity:

              SHA-1 ( good code )     = hash123
              SHA-1( hacker code )   = hash123

If the hash "hash123" is signed with with git's built in gpg functionality, not only is the signature valid for "good" code, but it could be valid for "hacker" code.  Developers on the other side of the wire must have systems above and beyond git that prevent such attacks.

A malicious agent can commit a "good" version of a repo, wait until the commit is added to security sensitive repos, and then push the "bad" version.  Bingo.

With specific commit hashes you cannot verify the the version you are building in production is the exact same code as the one a security team audited prior to release without trusting systems external of git.

Alternatives?  Don't use git's built in gpg signing functionality.  Instead, compress your repo and sign the resulting file manually.  Anyone on the other side of the wire will need to familiarize themselves with this process, manually verify, or use a tool outside of git to verify.