Search code examples
gitsshsign

What is the internal working of git signing commits and the user.signingkey option?


I have an understanding of basic encryption, ssh keys and certificates. While configuring signing git commits, I came across https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key

I use ssh key for signing so according to the docs:

$ git config --global user.signingkey /PATH/TO/.SSH/KEY.PUB

This is where I get confused, why are we signing with our public key, isn't that public? According to me, it should sign commits using our locally stored private key, and then wherever we have stored our public key (GitHub, GitLab, etc.) they decrypt this signature using a public key to verify the signature.

I am sure I am missing something under-the-hood, what exactly happens? I speculate that it signs using the private key only but asks the ssh-agent to sign with the corresponding private key.

I think what I am thinking is correct: From https://git-scm.com/docs/git-config#Documentation/git-config.txt-usersigningKey

If git-tag[1] or git-commit[1] is not selecting the key you want it to automatically when creating a signed tag or commit, you can override the default selection with this variable. This option is passed unchanged to gpg’s --local-user parameter, so you may specify a key using any method that gpg supports. If gpg.format is set to ssh this can contain the path to either your private ssh key or the public key when ssh-agent is used. Alternatively it can contain a public key prefixed with key:: directly (e.g.: "key::ssh-rsa XXXXXX identifier"). The private key needs to be available via ssh-agent. If not set git will call gpg.ssh.defaultKeyCommand (e.g.: "ssh-add -L") and try to use the first key available. For backward compatibility, a raw key which begins with "ssh-", such as "ssh-rsa XXXXXX identifier", is treated as "key::ssh-rsa XXXXXX identifier", but this form is deprecated; use the key:: form instead.


Solution

  • Take a look at the part you've highlighted:

    If gpg.format is set to ssh this can contain the path to either your private ssh key or the public key when ssh-agent is used. Alternatively it can contain a public key prefixed with key:: directly (e.g.: "key::ssh-rsa XXXXXX identifier"). The private key needs to be available via ssh-agent.

    Git does use your private key for signing, but when you're using an ssh-agent, the private key is obtained from the agent, rather than from a file on disk. The public key is simply used to identify the appropriate private key.