Git supports using GPG to sign commit records, but GPG is complicated to use. Git started supporting SSH signatures in 2.34, and since we all have SSH keys, it’s time to turn on signatures. But GitHub didn’t support displaying SSH signatures for a long time after this feature was released, so I didn’t push it forward. Yesterday GitHub announced that it officially supports SSH signatures. I’m going to share a little bit about it with you today.
First, why do you need to sign your Git commits? That’s because it’s easy to fake commit identities in Git.
We know that Git requires that the author’s name and email address be specified before committing.
But these two configurations can be filled in as you wish. Anyone can claim to be “taoshu”. To protect my reputation, I can sign my commits with asymmetric cryptography and then publish my public key. This way, other people can verify that the Git changes were submitted by me based on this public key. As long as I don’t reveal my private key, it’s hard for others to pretend to be me and do bad things.
The most common tool for implementing signatures is GPG, and if you’ve played around with Linux, you’re no stranger to the fact that many distributions use GPG as a package manager to sign packages and prevent bad guys from forging them.
However, GPG is not newbie-friendly, so the average Git player rarely turns on signatures. The situation didn’t change until OpenSSH 8.0 was released. This version of OpenSSH supports signing arbitrary data.
The signature feature is broken in OpenSSH 8.7, so it is recommended to use 8.8 or later.
The tool for SSH signing is ssh-keygen, which I guess many people only use when generating SSH keys for the first time, and then never touch it again. It’s a bit strange 🤔 but the signature checking feature is also provided by ssh-keygen.
Suppose there is a file
/tmp/a.txt and we want to sign it using
~/.ssh/id_ed25519, we can execute the following command.
The function of each parameter is as follows.
-Y signindicates that the signature is calculated
-fspecifies the private key
-n fileis to assign a type to the signature
-fileis defined by us, different types of signatures do not conflict
After execution, we get a signature file
/tmp/a.txt.sig, which looks like this.
With a signature, we can verify that someone has not tampered with the contents of the file. To verify the signature a list of public keys is needed.
The first column is the identification of the public key, which we use here as the email address. The second column is the public key type, and the part after that is the content of the public key, which is the content of
~/.ssh/id_ed25519.pub. Each public key occupies one line.
The signature check command is as follows.
The function of each parameter is as follows.
-Y verifyindicates that the signature is to be verified
-fto specify the public key list file
-Ispecifies that the public key identifier is to be used
-n fileneeds to be consistent with the signature
-sspecifies the file where the signature is located
Finally, pass the contents of the file to ssh-keygen via redirection, and if the verification passes, you will get the following result.
If someone modifies the contents of the file, the following results are obtained.
Considering that most Git users have their own SSH keys, wouldn’t it be a waste not to support SSH signing? So Git 2.34 includes SSH signing.
We need to add the following configuration.
After a bit of work, you’re ready to go. All Git commits will then be signed using SSH. If you don’t have automatic signing turned on, you can temporarily turn it on at commit time with the
With the default configuration, we don’t see any difference between signed commits and normal commits. If you want to show the signature information, you need to specify the
This time we see the
Good "git" signatures ... validation message.
If you are using tig, you should add the same parameters, or turn on the following configuration in
Recall our previous example, when the value of
file, the checkmark message is
Good "file".... Now the message is
Good "git"..., which means that Git is using the
-n git argument.
But there’s a problem: Where does Git store the signature information? The answer is the object corresponding to the commit or tag.
We can use
cat-file to see what the object holds.
Look at the line gpgsig, which indicates the current submission signature information. Each line after that has a space in front of it, which means that it’s the same line as gpgsig.
So how does Git sign? I didn’t look at the source code. But my guess is that it removes the gpgsig signature information and then calculates a signature for the rest of the content, with a signature type of git.
So I saved the corresponding content as a file and signed it, and it’s exactly the same as the gpgsig value.
Git signatures are a good solution to the problem of disguising your identity. But it’s not cool enough if the corresponding feature doesn’t show up on GitHub. So when Git 2.34 was first released, users suggested that GitHub add support for it. It finally went live yesterday 😄
Although GitHub supports displaying SSH signatures, you need to upload the keys for signing and for authentication separately. You need to specify the type when uploading. Even if you are using the same key, you will have to upload it again.
Once you upload the public key, GitHub will display the corresponding SSH signature.