debian-mirror-gitlab/lib/gitlab/ssh/signature.rb

87 lines
2.5 KiB
Ruby
Raw Normal View History

2022-07-23 23:45:48 +05:30
# frozen_string_literal: true
# Signature verification with ed25519 keys
# requires this gem to be loaded.
require 'ed25519'
module Gitlab
module Ssh
class Signature
include Gitlab::Utils::StrongMemoize
2023-03-04 22:38:38 +05:30
GIT_NAMESPACE = 'git'
2022-07-23 23:45:48 +05:30
def initialize(signature_text, signed_text, committer_email)
@signature_text = signature_text
@signed_text = signed_text
@committer_email = committer_email
end
def verification_status
strong_memoize(:verification_status) do
next :unverified unless all_attributes_present?
2023-03-04 22:38:38 +05:30
next :unverified unless valid_signature_blob?
2022-07-23 23:45:48 +05:30
next :unknown_key unless signed_by_key
2023-03-04 22:38:38 +05:30
next :other_user unless committer
2022-07-23 23:45:48 +05:30
next :other_user unless signed_by_key.user == committer
2023-03-04 22:38:38 +05:30
if signed_by_user_email_verified?
:verified
else
:unverified
end
2022-07-23 23:45:48 +05:30
end
end
2022-08-27 11:52:29 +05:30
def signed_by_key
strong_memoize(:signed_by_key) do
next unless key_fingerprint
2023-03-04 22:38:38 +05:30
Key.signing.find_by_fingerprint_sha256(key_fingerprint)
2022-08-27 11:52:29 +05:30
end
end
2023-03-17 16:20:25 +05:30
def key_fingerprint
strong_memoize(:key_fingerprint) { signature&.public_key&.fingerprint }
end
2022-07-23 23:45:48 +05:30
private
def all_attributes_present?
# Signing an empty string is valid, but signature_text and committer_email
# must be non-empty.
@signed_text && @signature_text.present? && @committer_email.present?
end
# Verifies the signature using the public key embedded in the blob.
# This proves that the signed_text was signed by the private key
# of the public key identified by `key_fingerprint`. Afterwards, we
# still need to check that the key belongs to the committer.
def valid_signature_blob?
return false unless signature
2023-03-04 22:38:38 +05:30
return false unless signature.namespace == GIT_NAMESPACE
2022-07-23 23:45:48 +05:30
signature.verify(@signed_text)
end
def committer
# Lookup by email because users can push verified commits that were made
# by someone else. For example: Doing a rebase.
2023-03-04 22:38:38 +05:30
strong_memoize(:committer) { User.find_by_any_email(@committer_email) }
end
def signed_by_user_email_verified?
signed_by_key.user.verified_emails.include?(@committer_email)
2022-07-23 23:45:48 +05:30
end
def signature
strong_memoize(:signature) do
::SSHData::Signature.parse_pem(@signature_text)
rescue SSHData::DecodeError
nil
end
end
end
end
end