Signing Git Commits with SSH Keys

written on Tuesday, November 16, 2021 by

Yesterday Git version 2.34.0 was released. An interesting part of the release notes is support for signing commits and tags not with a PGP key, but with an SSH key.

In addition to GnuPG, ssh public crypto can be used for object and push-cert signing. Note that this feature cannot be used with ssh-keygen from OpenSSH 8.7, whose support for it is broken. Avoid using it unless you update to OpenSSH 8.8.

The ability for signing arbitrary data with SSH was added in 2019 with OpenSSH 8.0. However, as noted in the release announcement above, you should use at least OpenSSH 8.8 for this feature to work without issues.

Signing Git Commits with SSH

SSH signatures in Git use the same mechanism as PGP signatures, thus you can keep using the -S flag for commits and the -s flag for tags. However, you need to change the signature format.

To switch the signature format to SSH (either for your current repo or globally):

git config [--global] gpg.format ssh

Additionally, you need to tell Git which SSH key to use for signing. Simply use your public key as the configuration value for user.signingKey.

git config [--global] user.signingKey 'ssh-ed25519 AAAAC3(...)qiXsb user@host'

Now you can create signed commits:

git commit -S -m 'Create a signed commit'

If you want to force all future commits and tags to be signed:

git config [--global] commit.gpgsign true
git config [--global] tag.gpgsign true

Verifying Commit Signatures with SSH

To show and validate signatures, pass --show-signature to git log or git show:

Screenshot of 'git show'

When looking at the resulting commit information, you might notice an error message:

error: gpg.ssh.allowedSignersFile needs to be configured and exist for ssh signature verification

The reason why this signature cannot be verified is because Git does not know which SSH keys to trust. In contrast to PGP, there is no "web of trust" where keys can be signed. Instead, you manage a list of trusted keys on your computer, the "allowed signers file" which works very similar to the "authorized keys file" used by SSH.

First, create a file somewhere on your computer (I'd recommend ~/.config/git/allowed_signers). Then, add an entry for your own signing key, so that your own commits will be trusted by Git. In its simplest form, every line starts with an e-mail address (the e-mail used to create the commit) followed a public key. For example, for my own key:

# ~/.config/git/allowed_signers ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE5bRSsXZ5HnUkMMEWS5/jxEQaqbLb+i6xjMyC6qiXsb danilo@jabba

(If you want to know more about the format of this file, check out the "ALLOWED SIGNERS" section in man 1 ssh-keygen. There are more options you can use, for example key expiration.)

Next, tell Git about this file.

git config [--global] gpg.ssh.allowedSignersFile "$HOME/.config/git/allowed_signers"

Now Git/SSH know whom to trust, and can verify the signature:

Screenshot of 'git show'

Happy signing!

This entry was tagged git and ssh