Skip to content

Add Gitlab::Ssh::Signature for SSH signature verification

Brian Williams requested to merge bwill/ssh-signatures/ssh-classes into master

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

  1. The signature is valid for the given plaintext
  2. 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.

  1. 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.

  2. 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
  3. Sign the message:

    ssh-keygen -Y sign -n file -f id_test message.txt
  4. 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.

Edited by Brian Williams

Merge request reports