Gracefully handle unknown/invalid GPG keys
An unknown public GPG key will result in a GPGME::Error thrown from gpg, which would cause an Error 500 on the signatures endpoint. Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/54729
This commit is contained in:
parent
cfe484795d
commit
184240e86a
2 changed files with 39 additions and 7 deletions
|
@ -44,9 +44,8 @@ module Gitlab
|
||||||
def update_signature!(cached_signature)
|
def update_signature!(cached_signature)
|
||||||
using_keychain do |gpg_key|
|
using_keychain do |gpg_key|
|
||||||
cached_signature.update!(attributes(gpg_key))
|
cached_signature.update!(attributes(gpg_key))
|
||||||
|
@signature = cached_signature
|
||||||
end
|
end
|
||||||
|
|
||||||
@signature = cached_signature
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -59,11 +58,15 @@ module Gitlab
|
||||||
# the proper signature.
|
# the proper signature.
|
||||||
# NOTE: the invoked method is #fingerprint but it's only returning
|
# NOTE: the invoked method is #fingerprint but it's only returning
|
||||||
# 16 characters (the format used by keyid) instead of 40.
|
# 16 characters (the format used by keyid) instead of 40.
|
||||||
gpg_key = find_gpg_key(verified_signature.fingerprint)
|
fingerprint = verified_signature&.fingerprint
|
||||||
|
|
||||||
|
break unless fingerprint
|
||||||
|
|
||||||
|
gpg_key = find_gpg_key(fingerprint)
|
||||||
|
|
||||||
if gpg_key
|
if gpg_key
|
||||||
Gitlab::Gpg::CurrentKeyChain.add(gpg_key.key)
|
Gitlab::Gpg::CurrentKeyChain.add(gpg_key.key)
|
||||||
@verified_signature = nil
|
clear_memoization(:verified_signature)
|
||||||
end
|
end
|
||||||
|
|
||||||
yield gpg_key
|
yield gpg_key
|
||||||
|
@ -71,9 +74,16 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def verified_signature
|
def verified_signature
|
||||||
@verified_signature ||= GPGME::Crypto.new.verify(signature_text, signed_text: signed_text) do |verified_signature|
|
strong_memoize(:verified_signature) { gpgme_signature }
|
||||||
|
end
|
||||||
|
|
||||||
|
def gpgme_signature
|
||||||
|
GPGME::Crypto.new.verify(signature_text, signed_text: signed_text) do |verified_signature|
|
||||||
|
# Return the first signature for now: https://gitlab.com/gitlab-org/gitlab-ce/issues/54932
|
||||||
break verified_signature
|
break verified_signature
|
||||||
end
|
end
|
||||||
|
rescue GPGME::Error
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_cached_signature!
|
def create_cached_signature!
|
||||||
|
@ -92,7 +102,7 @@ module Gitlab
|
||||||
commit_sha: @commit.sha,
|
commit_sha: @commit.sha,
|
||||||
project: @commit.project,
|
project: @commit.project,
|
||||||
gpg_key: gpg_key,
|
gpg_key: gpg_key,
|
||||||
gpg_key_primary_keyid: gpg_key&.keyid || verified_signature.fingerprint,
|
gpg_key_primary_keyid: gpg_key&.keyid || verified_signature&.fingerprint,
|
||||||
gpg_key_user_name: user_infos[:name],
|
gpg_key_user_name: user_infos[:name],
|
||||||
gpg_key_user_email: user_infos[:email],
|
gpg_key_user_email: user_infos[:email],
|
||||||
verification_status: verification_status
|
verification_status: verification_status
|
||||||
|
@ -102,7 +112,7 @@ module Gitlab
|
||||||
def verification_status(gpg_key)
|
def verification_status(gpg_key)
|
||||||
return :unknown_key unless gpg_key
|
return :unknown_key unless gpg_key
|
||||||
return :unverified_key unless gpg_key.verified?
|
return :unverified_key unless gpg_key.verified?
|
||||||
return :unverified unless verified_signature.valid?
|
return :unverified unless verified_signature&.valid?
|
||||||
|
|
||||||
if gpg_key.verified_and_belongs_to_email?(@commit.committer_email)
|
if gpg_key.verified_and_belongs_to_email?(@commit.committer_email)
|
||||||
:verified
|
:verified
|
||||||
|
|
|
@ -26,6 +26,28 @@ describe Gitlab::Gpg::Commit do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'invalid signature' do
|
||||||
|
let!(:commit) { create :commit, project: project, sha: commit_sha, committer_email: GpgHelpers::User1.emails.first }
|
||||||
|
|
||||||
|
let!(:user) { create(:user, email: GpgHelpers::User1.emails.first) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(Gitlab::Git::Commit).to receive(:extract_signature_lazily)
|
||||||
|
.with(Gitlab::Git::Repository, commit_sha)
|
||||||
|
.and_return(
|
||||||
|
[
|
||||||
|
# Corrupt the key
|
||||||
|
GpgHelpers::User1.signed_commit_signature.tr('=', 'a'),
|
||||||
|
GpgHelpers::User1.signed_commit_base_data
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns nil' do
|
||||||
|
expect(described_class.new(commit).signature).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'known key' do
|
context 'known key' do
|
||||||
context 'user matches the key uid' do
|
context 'user matches the key uid' do
|
||||||
context 'user email matches the email committer' do
|
context 'user email matches the email committer' do
|
||||||
|
|
Loading…
Reference in a new issue