...for something that's much easier to maintain, and has been supported for years now.
Let me give you four terms in alphabetical order:
If I asked you, which of these are applications, and which of them are generic terms or standards, would you guess correctly?
Only GPG and PGP are applications. OpenPGP and LibrePGP are standards, and this is where the mess begins.
If the current situation remains, the PGP/GPG ecosystem will likely fracture in the future, and GPG may become incompatible with PGP. Together with S/MIME we will end up with 3 incompatible standards for message signing.
This isn't even about GPG, handling cryptographic keys just sucks, which is why it never took off as authentication mechanism for HTTPS or most protocols on top of TLS even though it's superior to passwords. In the end, this means if we can do with less keys we also have less to worry about.
And in regards to GPG, you're installing an entire suite of applications for key management just so you can sprinkle a bit of ASCII at the end of your commits to make the server accept them. It would be preferrable if this was possible with less infrastructure.
If you use a repository server that requires user authentication to push, you likely can get away without doing it if you configure your repository in a certain way. Repository security has increased over the last decade, and now we have options such as:
n
people with repository accessn
people from a set of defined peoplen
successful builds before a pull request can be approvedIn most corporate environments, a central directory (usually accessed via LDAP) manages users. Users usually cannot change the name or e-mail in this directory because these fields are dictated by HR and the e-mail system.
If you require that the e-mail address in the commit matches the data on file, users can only make changes in their name. A change made by elvis.presley@example.com is guaranteed to come from his account and not some prankster that temporarily changed the email address in their git configuration.
If you work with outdated systems that do not provide the mentioned security settings, or stubborn repository owners who refuse to enable said settings, commit signing is a viable way to prove authorship of your commits.
If having the little checkmark next to your name is of vital importance to you, you can still ditch GPG, because modern systems already have everything installed you need to sign commits. The instructions below are the exact same for Windows and Linux, except a few file paths. The linux instructions probably also work for Mac users.
You do not need to install any other software beyond git and an ssh client. An ssh client is usually already present; (Most) Linux distros as well as recent Windows versions include it.
Git can be installed via package manager on all common systems. Additionally for Windows it can be downloaded from git-scm.com.
You can check if you have git by typing git --version
,
and ssh by typing ssh -V
.
Both commands should print their respective version.
First, ensure you have an ed25519 SSH key.
You can check if .ssh/id_ed25519
exists in your user profile.
If it doesn't, create a key by running ssh-keygen -t ed25519
and use the default suggested file name.
Whether to use a password or not is up to you, but be aware that you will have to type it for every single commit you make unless you set up an SSH key agent.
Note: You can of course use other key types for this, but you might as well use this opportunity to ditch your RSA key for a much smaller one that provides equal or better key strength. Don't worry, generating a new key type will not invalidate your existing RSA key.
Type or copy the git commands shown below. Those prefixed with (W) or (L) should only be run on Windows or Linux respectively.
Setting the user name and e-mail is optional, but it's a good idea to keep them in sync with the values you use in your repository servers.
The commands below set global options.
If you want to experiment with a single repository first,
run the commands without --global
from within the repository directory.
All global git settings can be overridden this way.
This means you can have different name, email, signing types, keys, etc.
for each repository if you want. This may be useful to you if you want to separate
your work projects from your personal projects.
git config --global user.name "Elvis Presley"
git config --global user.email elvis.presley@example.com
git config --global gpg.format ssh
(W) git config --global user.signingKey "%USERPROFILE%\.ssh\id_ed25519.pub"
(L) git config --global user.signingKey ~/.ssh/id_ed25519.pub
git config --global commit.gpgSign true
git config --global commit.tagSign true
git config --global tag.forceSignAnnotated true
git config --global push.gpgSign "if-asked"
Explanation of the values:
At this point, create a git repository and make a commit,
then run git show --format=raw
. You should see an SSH signature block.
Copy the contents of the .ssh\id_ed25519.pub
file to your clipboard,
then add it as authorized SSH key to your user profile in your repository server.
Some servers distinguish between an authentication key (repository operations via ssh) and a signing key (commit and tag signing).
You're usually allowed to use the same key for both operations by adding it twice (github for example)
Make sure you copy the contents of the file ending in ".pub" only. The other file contains the private key, which you never want to share.
This step is optional. If all you care for is that the server considers your commits signed, you can stop here. If you want to be able to verify commits yourself, you must obtain the keys to trust first. If you want to have a global trust file, configure it using this command:
(W) git config --global gpg.ssh.allowedSignersFile "%USERPROFILE%\allowed_signers"
(L) git config --global gpg.ssh.allowedSignersFile ~/allowed_signers
The file contains one key per line in this format:
<authority[,authority[,...]]> [option[,...]] <key> [comments]
Because the file uses whitespace to separate values on the same line, you must not insert spaces in other locations than shown above or the parser will be thrown off.
The authority is the e-mail address from the commit that the key is matched against.
This can also contain a wildcard, for example *@example.com
marks the key as valid for all example.com e-mail addresses. This may be useful for people that own their own domain and frequently switch e-mail addresses.
The authority is also what is shown in the commit verification message
Good "git" signature for <AUTHORITY> with <KEYTYPE> key SHA256:<HASH>
You are allowed to have multiple authorities for a key.
The options allow you to specify properties that are not contained in the key itself. SSH keys are mostly just that, the plain key without any extra information you may be familiar with from certificates.
Most likely, you want to limit the date range a key is valid.
You can do this by specifying valid-after="DT"
and valid-before="DT"
.
You're allowed to specify only one of these values.
If a user wants to change their key, you would put the valid-before option with the old key
and the valid-after option with the new key.
"DT" is a date in YYYYMMDD[Z]
or YYYYMMDDHHMM[SS][Z]
format.
The parts in brackets are optional (do not write out the brackets).
The Z
makes it UTC, otherwise the local time zone will be used.
Note that options must not contain a whitespace outside of the quoted value,
and that the quotes are required.
This is the key as-is from the .ssh\id_ed25519.pub
file.
It consists of the key type, followed by a space, followed by the key.
Anything after the key is considered a comment.
Your key likely already has one in the form of username@hostname
if you didn't specify one on the command line.
You can change this value at any time without any negative effects.
The comment in the .pub file and the signers file do not need to be identical.
If you want to change the comment,
you can set a new one with ssh-keygen -c -C "Elvis Presley The King" -t ed25519
When you run git log --show-signature
in your test repository,
it should show a Good "git" signature
message below the commit hash.
Like all git options, you can override global options on a per-repository setting.
A repository that only allows signed commits can store the allowed_signers
file in the repository itself using a path relative to the top-level of the working tree.
This way only committers with an already valid key can add or change keys in the file.
This allows users to update their key and others will fully automatically get it during the next pull.
Since all settings can be overridden on a per-repository basis,
you can keep GPG signing your default and experiment with SSH signing in new repositories,
for this, run all the git config
commands shown above without --global
from inside your repository directory.
This file shows the same identity having two keys. This user has changed their key, so the old key was expired at 2025-01-01, and the new key went into effect at the same day.
test@example.com valid-before="20250101Z" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJM4zG0kGyiLY5FqfptsTTC9AohfsUe65YkjQfHe3C4S Old key
test@example.com valid-after="20250101Z" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDR/RbStVZbaLcF/n1IIqD7C760DMol2LbqLkMMt8vgP New key