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

  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 (Ex-GitLab)

Merge request reports

Loading
Loading