Signing commit messages with GPG in Linux
Signing git messages with GPG keys is important, otherwise someone may easily spoof your commit messages on (e.g.) Github (^1). There are different ways to sign commit messages such as with GPG, SSH, or S/MIME.
I prefer to keep my SSH-Keys I use for signing into accounts separate from my keys I use to sign commit messages. Therefore, for signing commit messages, I use explicit GPG keys. I have two GPG keys, one for my private mail and one for my work mail. For both, I added the public key parts to Gitlab(s) and Github, so I can commit from both private and work laptops.
Some of these steps are not as obvious, which is why I wrote down the process here.
Prerequises
In Linux or your Windows Subystem for Linux (WSL), install the dependencies:
sudo apt install gnupg2
sudo apt-get install -y pinentry-tty
pinentry-tty is a program that allows for secure entry of PINs or pass phrases. That means it tries to take care that the entered information is not swapped to disk or temporarily stored anywhere.
Create ~/.gnupg/gpg-agent.conf
.
mkdir -p ~/.gnupg/
nano ~/.gnupg/gpg-agent.conf
.. and add:
pinentry-program /usr/bin/pinentry-tty
Add the following line to your .bashrc
:
export GPG_TTY=$(tty)
e.g.
nano ~/.bashrc
# CTRL+O
source ~/.bashrc
Test:
echo "test" | gpg2 --clearsign
Create GPG key
gpg --full-generate-key
- Key type:
- either RSA and RSA, an asymmetric key pair for encryption and decryption
- or a more modern and lean Elliptic Curve key
- Bit length: 4096 for the highest amount of entropy.
- Expiration date:
1y
. Entirely up to you and your use case, you only want to prove your identity for Git, not guard state-sponsored secrets.
Export the public part:
gpg --armor --export mail@yourmail.com > /tmp/gpgkey.pub
# better use the exact id:
gpg --armor \
--export OU34752JOWOI278732JDJJ732407z9874328 > /tmp/gpgkey.pub
To backup your private key:
gpg -o /tmp/private.gpg \
--export-options backup \
--export-secret-keys OU34752JOWOI278732JDJJ732407z9874328
To later restore your private key from backup (^2):
gpg --import-options restore --import private.gpg
gpg --edit-key mail@yourmail.com
> trust
> 5
> Y
> quit
Test
Enable signing of commit messages globally for git
:
git config --global gpg.program gpg2
git config --global commit.gpgsign true
git config --global alias.logs "log --show-signature"
git config --global user.signingkey OU34752JOWOI278732JDJJ732407z9874328
Test:
cd /tmp/
mkdir test && cd test
echo "Some content" >> example.txt
git init
git add example.txt
git commit -m "test"
git logs
Cleanup:
cd ..
rm -rf test
Add to Gitlab
gpg --armor --export OU34752JOWOI278732JDJJ732407z9874328
Go to your Gitlab https://gitlab.yourgitlab.com/-/profile/gpg_keys and add the public key part of your GPG key.
Extending GPG keys
Check expiration:
gpg -K
> /home/user/.gnupg/pubring.kbx
> -----------------------------
> sec rsa4096 2022-01-13 [SC] [expires: 2023-01-13]
> ...
> uid [ultimate] Your Name <mail@yourmail.com>
> ssb rsa4096 2022-01-13 [E] [expires: 2023-01-13]
Run this command to list the private GPG key you just created, replacing
gpg --list-secret-keys \
--keyid-format LONG mail@yourmail.com
> sec rsa4096/IJAO23IDSALK324DASD 2022-01-13 [SC] [expires: 2023-01-13]
> OU34752JOWOI278732JDJJ732407z9874328
> uid [ultimate] Your Name <mail@yourmail.com>
> ssb rsa4096/9LD7324JSAL435 2022-01-13 [E] [expires: 2023-01-13]
First, note that there’s a short form for the ID (IJAO23IDSALK324DASD
)
and a long form (OU34752JOWOI278732JDJJ732407z9874328
). You can use both
forms to select keys.
There may be multiple subkeys available:
E
means the key is used for used for encryptionSC
means the key is used for Signing/Pubkey
gpg --edit-key mail@yourmail.com
gpg --edit-key IJAO23IDSALK324DASD
Now you can set the expiration for the selected key:
gpg> expire
(follow prompts)
gpg> save
You have to make a decision about extending validity of vs. replacing the subkey(s). Replacing them gives you limited forward security (limited to rather large time frames). If that is important to you then you should have (separate) subkeys for both encryption and signing (the default is one for encryption only).
Private keys never expire. Only public keys do. Otherwise, the world would never notice the expiration as (hopefully) the world never sees the private keys.
Also, to expire (all) subkeys:
- instead of
1
, selectkey 1
*
will be shown in front of “ssb”
key 1
...
save
>sec rsa4096/IJAO23IDSALK324DASD
> created: 2022-01-13 expires: 2024-01-03 usage: SC
> trust: ultimate validity: ultimate
>ssb* rsa4096/9LD7324JSAL435
> created: 2022-01-13 expires: 2023-01-13 usage: E
Update git, gitlab:
git config --global user.signingkey IJAO23IDSALK324DASD
Copy new public key, and update in gitlab:
gpg --armor --export IJAO23IDSALK324DASD
Increase password timeout
The password timeout was too short for me. I want to unlock my GPG Key once per day, meaning I would need to increase the timeout to 8 hours.
nano ~/.gnupg/gpg-agent.conf
Add:
# increase gpg timout for password to 8 hours
default-cache-ttl 28800
max-cache-ttl 28800
Restart:
gpgconf --kill gpg-agent
gpg-agent --daemon
Public key exchange
In order to receive keys from other people, keyservers can be used.
For example, in case your public key was published on keys.openpgp.org, someone else may receive it to their local store by:
gpg --keyserver keys.openpgp.org --recv-keys IJAO23IDSALK324DASD