Add Gitlab::Ssh::Signature for SSH signature verification
What does this MR do and why?
Describe in detail what your merge request does and why.
For #343879 (closed)
Adds a Gitlab::Ssh::Signature
class which is responsible for cryptographic verification of commit
signatures that are signed by SSH keys. It takes a signature, a plaintext, and a committer email and
verifies that
- The signature is valid for the given plaintext
- The SSH key used to sign the plaintext belongs a user whose email address is verified and matches the committer email
The specification for SSH signatures can be referenced in openssh-portable/PROTOCOL.sshsig. We make use of an existing dependency, ssh_data for performing signature verification. This dependency is maintained by GitHub, and we already use it in production for parsing SSH public keys. SSH signature verification was added to ssh_data in version 1.3.0 via https://github.com/github/ssh_data/pull/31. (Gem diff)
How to set up and validate locally
Your SSH version (ssh -V
) should be OpenSSH_8.0p1
or newer.
-
Generate an SSH key pair:
ssh-keygen -t ed25519
I recommend saving this key pair to the current directory (e.g. id_test) instead of your
~/.ssh/
directory and then deleting it when you are done testing. -
Create a text file with a message:
echo -n 'You accept the world as you find it and apply your principles where you can.' > message.txt
-
Sign the message:
ssh-keygen -Y sign -n file -f id_test message.txt
-
Use the rails console to create the key and verify the message:
user = User.find(1) key = Key.create( key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIELaINtPpdqTHD57qGll7jacPbuzsz5yc3S1KJ9PhCzU", # cat id_test.pub user: user, title: "Test key" ) signed_text = 'You accept the world as you find it and apply your principles where you can.' signature_text = <<~SIG -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgQtog20+l2pMcPnuoaWXuNpw9u7 OzPnJzdLUon0+ELNQAAAAEZmlsZQAAAAAAAAAGc2hhNTEyAAAAUwAAAAtzc2gtZWQyNTUx OQAAAEBJvqHO5J7eiVg7nbgvsFQEecNIRkAUb8T2RZQVCdkrdZtPInxhVEDD2rNNTs/78j wOfLEHJMVh/aq8feYDay0I -----END SSH SIGNATURE----- SIG committer_email = user.email signature = Gitlab::Ssh::Signature.new(signature_text, signed_text, committer_email) signature.verification_status
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
-
I have evaluated the MR acceptance checklist for this MR.