Use case: you use Git as your version control system and you want to sign your tags and/or commits using a PGP key because it sounds very cool and probably enhances security somewhat.
If you already have a GPG key, jump to next section.
Creating a GPG key
Create a new, generic GPG key by invoking this command:
gpg --full-generate-key
This is an interactive command. It says many nerdy things. To the "what kind of key you want" question, enter 1 (or whatever the option is) for "RSA and RSA (default)". Informed people say that these days EC25519 keys are cooler, but I have no idea. I also have no idea why you cannot create this kind of elliptic curve keys using this interactive mode, because you can do it from the command line. I don't give a damn.
Give it a keysize of 4096, set an expiration date to "key does not expire" and give reasonable answers to the rest of questions. Enter a clever, long passphrase. You'll end up with a new keyring with your new key.
pub rsa4096 2024-04-12 [SC] 8A7E286E3A81676C5718B64E278FD009868D43DE uid Waaaah <sexmachine@example.com> sub rsa4096 2024-04-12 [E]
Creating a signing key
We'll create a special key for signing your code, because it's cool and make things overly complicated and you'll look like you know what you are doing. We'll also set a short expiration life, so that you have to keep returning to this page over and over in the future because you'll have forgotten all these cumbersome steps. Run:
gpg --edit-key sexmachine@example.com
This is interactive again. Type:
gpg> addkey
Enter the option for "RSA (sign only)", 4096 bits keysize, and 1y
(1 year) expiration date. You will need to supply the passphrase for the key. Confirm everything and save and such. You'll see something like
sec rsa4096/278FD009868D43DE created: 2024-04-12 expires: never usage: SC trust: ultimate validity: ultimate ssb rsa4096/A34BD7637BCADEBF created: 2024-04-12 expires: never usage: E ssb rsa4096/1CA4911800F8A2E5 created: 2024-04-12 expires: 2025-04-12 usage: S [ultimate] (1). Waaaah <sexmachine@example.com>
We now have a signing-only key (usage: S
) with an expiration date. Take note of its key Id (in this case, it's the 1CA4911800F8A2E5
string).
If you need to get this information again, run gpg --list-secret-keys --keyid-format=long
.
Uploading your GPG keys to a keyserver
It's a good thing to upload your keys to a keyserver for the rest of people to find it. Keyservers come and go. These days, https://keys.openpgp.org:443
seems to work fine. So, send your keys there using the following command:
gpg --keyserver https://keys.openpgp.org:443 --send-key 1CA4911800F8A2E5
People will be able to get your key by typing
gpg --keyserver https://keys.openpgp.org:443 --search-keys sexmachine@example.com
This command allows people to interactively add your key to their keyring. But, it sometimes fails with the cryptic message no valid OpenPGP data found
. Why not. I found that going to that web site, searching and downloading the ASCII armored key and importing it by hand works. Meh.
Telling your Git project about your GPG signing key
Move to the working directory of your git project and type:
git config user.signingkey '1CA4911800F8A2E5!'
But use your key Id, not this one. Note the ! at the end. It seems it's necessary because it's a subkey. I don't know why.
Signing tags
Now you are ready to sign tags! You have to do it this way from now:
git tag 0.01 -s -m "New development release 0.01 (codename Potato Head)"
Note the -s
argument. Also, signed tags must have a message. If you don't provide one, a $EDITOR will be spawned for you to do it.
If everything is OK, GPG will ask you for the passphrase. I've found that this sometimes fails, I have no idea why. It's probably related to the gpg-agent
program or shit. Try killing it. Or signing some dummy text from the standard input by running gpg --sign -a
, entering the passphrase and recalling the git tag
command. All this GPG thing looks very fragile.
If you are still here, you'll see that a git log
or git tag
does not show anything new. You must use git show {tag name}
. You'll see something like
tag 0.01 Tagger: Waaaah <sexmachine@example.com> Date: Fri Apr 12 19:42:58 2024 +0200 New development release 0.01 (codename Potato Head) -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEkCwFKCMlLL6wb6f47iFRZCH8+ZIFAmYZcqIACgkQ7iFRZCH8 +ZL9QxAAlLlENIcEJe/hHRNfvlDgk7/PS1MJUYyam32E8tO8MsLRHZ164icAoaGC XuEY2fiFrH7q0az5+LzA9Cy2EZND1UCHgM7m4Vu6beNR7xKw80eHu/0FTc+stLGO vDxGmHOpVtSG03PU8E/bmTk2TXB9qcJzR/jBeqz4V+31+8gaF6XOSBhMfP+hdUu4 /FpAAXCOT6NGIG3vYCMaobxudnIZBLtqBtVzHHrk5qu3SJB4ReddO2HFu9528E/j nzzpXlVqAGSJ5iY80K49CE/kirvICZwJf6LlaKuXJvrLntia+sr3Axq4DPjdujex r8wMjxYiIce0iGRywWng3ZXwafFdRHmCSUbv85NeHLymdapSs7ly1NbqFBo5NKzX Fhj81KD4HUeP+7BsppYzM0zW5tjngHA2qzhHIK4xMIqtVLCXI460rBsz+xbGbGOW PMjGXEw6pBwbiRXmwe8iE0JP4AHsxN+05B6mHKeqemsinOx5/B7n+KgbjhLtWANX kNFzdaRScfDcdnqlApV8aL6//d2P14Mh3ncqgfQNJh2SIgEsdxsGPDfUA2jTZ0K/ fLxxm+C7P52/LvTLHbzH6EHINUz27j5NKsS8Z5K2ozHRGwSErrKGw++GfDxeeQnP W56MS4uvjVdafjP581ldggjHayo653heJxBvQhRIwfLbMRvZbMc= =HAcq -----END PGP SIGNATURE-----
Oh yeah.
Verifying tags
Cool guys that have your GPG public key available in their keyring can verify the tag using git tag -v {tag name}
. GPG barfs a noisy message telling something about a good signature.
Signing commits
You can also sign individual commits. You must add the -S
(capital S) argument to your git commit
line, because using -s
like you did in git tag
would be too easy to remember.
Verifying commits
Again, it seems like everything remains the same, unless you add the magic incantation --show-signature
to the git log
command. This dumps specially joyful messages from GPG talking about good signatures and such. If your logs contain many signed commits it may became very slow.
Command summary
Creating a signed commit:
git commit -S -a -m "Commit message"
Creating a signed tag:
git tag -s 1.23 -m "Tag description"
Verifying a signed tag:
git tag -v 1.23
Showing signature information in logs:
git log --show-signature
Final words
Is this worth the effort? I'm not sure. It surely looks techy.
If you found this post useful, you may buy Ángel a coffee.