Not really. But Kind of?
Did you know that you probably already have a working PKI system for signing artifacts on your laptop today, with no keyservers, web-of-trust, or configuration? You can use it to sign files, and to find the public keys for other people and use them to verify files they signed.
So why aren’t more people using this? I think it’s just gone overlooked because it’s a relatively new feature in apretty old piece of software. I’ve only been able to find one other blog post explaining how it works (outside of the man pages).
Signing and Verifying
Since early 2020, OpenSSH has supported creating and verifying file signatures natively in the ssh-keygen
binary. You can create signatures with:
ssh-keygen -Y sign -n file -f $HOME/.ssh/id_rsa.pub <FILE-TO-SIGN>
This signs the file specified in using your SSH public key at the standard location $HOME/.ssh/id_rsa.pub
. The signature ends up at <FILE-TO-SIGN>.sig
by default, and looks roughly like:
-----BEGIN SSH SIGNATURE-----
U1NIU0lHAAAAAQAAAhcAAAAHc3NoLXJzYQAAAAMBAAEAAAIBAPDRlY/jNksQtIlV6dBN<...>
-----END SSH SIGNATURE-----
If you have a signature, a file, and the SSH public key, you can verify it with ssh-keygen
as well! First you have to create an allowed_signers
file with the public key you want to verify against and a fake Principal
name:
echo "thesigner $(cat id_rsa.pub)" > allowed_signers
Then, use that to verify:
cat <FILE-TO-VERIFY> ssh-keygen -Y verify -n file -f allowed_signers -s <SIGNATURE> -I thesigner
Finding Keys
But how do you find public keys to check against, or distribute yours? PGP uses the web-of-trust and key-servers for this. Web PKI uses Certificate Authorities. Here, we can just use GitHub! Almost everyone using GitHub already has an SSH key configured to push code with, and GitHub exposes these keys for every user.
To see mine, you can hit https://github.com/dlorenc.keys. Replace dlorenc
with your username to see what keys you use, or any other username to see the public keys for that user.
To see them in json
form for scripting, you can access: https://api.github.com/users/dlorenc/keys
Putting It All Together
The allowed_signers
file from before basically contains a map of Principal
to Public Key
. Here, Principal
is just a fancy word for “a string that represents a person”. So we can easily make an allowed_signers file that maps GitHub user names to public keys!
USERNAME="dlorenc"
curl https://github.com/${USERNAME}.keys | while read key; do
echo "$USERNAME $key" >> allowed_signers.github
done
You can run this for any GitHub user, and append into your public key database file.
Then, to check a signature/file against a Github user:
cat FILE | ssh-keygen -Y verify -n file -f allowed_signers.github -I USER -s FILE.sig
Caveats
Obviously there are some caveats here. This requires that users use SSH public keys to push to GitHub. This requires that GitHub users remove old or compromised public keys regularly. This little script does not handle revocation or removing old keys as users clean up their GitHub accounts.
Take a look at the documentation for ssh-keygen
to see more information on how this all works before using it for anything serious.
Thanks to Damien Miller for designing and implementing this feature, and for maintaining OpenSSH!
Follow me on Twitter for more posts like this one.