debian-mirror-gitlab/spec/lib/gitlab/x509/signature_spec.rb

447 lines
16 KiB
Ruby
Raw Normal View History

2020-04-22 19:07:51 +05:30
# frozen_string_literal: true
require 'spec_helper'
2020-07-28 23:09:34 +05:30
RSpec.describe Gitlab::X509::Signature do
2020-04-22 19:07:51 +05:30
let(:issuer_attributes) do
{
subject_key_identifier: X509Helpers::User1.issuer_subject_key_identifier,
subject: X509Helpers::User1.certificate_issuer,
crl_url: X509Helpers::User1.certificate_crl
}
end
2023-03-04 22:38:38 +05:30
it_behaves_like 'signature with type checking', :x509 do
subject(:signature) do
described_class.new(
X509Helpers::User1.signed_commit_signature,
X509Helpers::User1.signed_commit_base_data,
X509Helpers::User1.certificate_email,
X509Helpers::User1.signed_commit_time
)
end
end
2021-04-17 20:07:23 +05:30
shared_examples "a verified signature" do
2021-12-11 22:18:48 +05:30
let!(:user) { create(:user, email: X509Helpers::User1.certificate_email) }
2021-06-02 17:11:27 +05:30
subject(:signature) do
described_class.new(
2021-04-17 20:07:23 +05:30
X509Helpers::User1.signed_commit_signature,
X509Helpers::User1.signed_commit_base_data,
X509Helpers::User1.certificate_email,
X509Helpers::User1.signed_commit_time
)
2021-06-02 17:11:27 +05:30
end
2021-04-17 20:07:23 +05:30
2021-06-02 17:11:27 +05:30
it 'returns a verified signature if email does match' do
2021-04-17 20:07:23 +05:30
expect(signature.x509_certificate).to have_attributes(certificate_attributes)
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
expect(signature.verified_signature).to be_truthy
expect(signature.verification_status).to eq(:verified)
end
2022-11-25 23:54:43 +05:30
it 'returns a verified signature if email does match, case-insensitively' do
signature = described_class.new(
X509Helpers::User1.signed_commit_signature,
X509Helpers::User1.signed_commit_base_data,
X509Helpers::User1.certificate_email.upcase,
X509Helpers::User1.signed_commit_time
)
expect(signature.x509_certificate).to have_attributes(certificate_attributes)
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
expect(signature.verified_signature).to be_truthy
expect(signature.verification_status).to eq(:verified)
end
2021-12-11 22:18:48 +05:30
context "if the email matches but isn't confirmed" do
let!(:user) { create(:user, :unconfirmed, email: X509Helpers::User1.certificate_email) }
2021-06-02 17:11:27 +05:30
2021-12-11 22:18:48 +05:30
it "returns an unverified signature" do
expect(signature.verification_status).to eq(:unverified)
end
2021-06-02 17:11:27 +05:30
end
2021-04-17 20:07:23 +05:30
it 'returns an unverified signature if email does not match' do
signature = described_class.new(
X509Helpers::User1.signed_commit_signature,
X509Helpers::User1.signed_commit_base_data,
"gitlab@example.com",
X509Helpers::User1.signed_commit_time
)
expect(signature.x509_certificate).to have_attributes(certificate_attributes)
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
expect(signature.verified_signature).to be_truthy
expect(signature.verification_status).to eq(:unverified)
end
it 'returns an unverified signature if email does match and time is wrong' do
signature = described_class.new(
X509Helpers::User1.signed_commit_signature,
X509Helpers::User1.signed_commit_base_data,
X509Helpers::User1.certificate_email,
Time.new(2020, 2, 22)
)
expect(signature.x509_certificate).to have_attributes(certificate_attributes)
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
expect(signature.verified_signature).to be_falsey
expect(signature.verification_status).to eq(:unverified)
end
it 'returns an unverified signature if certificate is revoked' do
expect(signature.verification_status).to eq(:verified)
signature.x509_certificate.revoked!
expect(signature.verification_status).to eq(:unverified)
end
end
2020-04-22 19:07:51 +05:30
context 'commit signature' do
let(:certificate_attributes) do
{
subject_key_identifier: X509Helpers::User1.certificate_subject_key_identifier,
subject: X509Helpers::User1.certificate_subject,
email: X509Helpers::User1.certificate_email,
serial_number: X509Helpers::User1.certificate_serial
}
end
context 'verified signature' do
context 'with trusted certificate store' do
before do
store = OpenSSL::X509::Store.new
certificate = OpenSSL::X509::Certificate.new(X509Helpers::User1.trust_cert)
store.add_cert(certificate)
allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
end
2021-04-17 20:07:23 +05:30
it_behaves_like "a verified signature"
end
2020-04-22 19:07:51 +05:30
2021-04-17 20:07:23 +05:30
context 'with the certificate defined by OpenSSL::X509::DEFAULT_CERT_FILE' do
before do
store = OpenSSL::X509::Store.new
certificate = OpenSSL::X509::Certificate.new(X509Helpers::User1.trust_cert)
file_path = Rails.root.join("tmp/cert.pem").to_s
2020-04-22 19:07:51 +05:30
2021-04-17 20:07:23 +05:30
File.open(file_path, "wb") do |f|
f.print certificate.to_pem
end
2020-04-22 19:07:51 +05:30
2022-08-13 15:12:31 +05:30
allow(Gitlab::X509::Certificate).to receive(:default_cert_file).and_return(file_path)
2020-04-22 19:07:51 +05:30
2021-04-17 20:07:23 +05:30
allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
2020-04-22 19:07:51 +05:30
end
2021-04-17 20:07:23 +05:30
it_behaves_like "a verified signature"
2020-04-22 19:07:51 +05:30
end
context 'without trusted certificate within store' do
before do
store = OpenSSL::X509::Store.new
allow(OpenSSL::X509::Store).to receive(:new)
.and_return(
store
)
end
it 'returns an unverified signature' do
signature = described_class.new(
X509Helpers::User1.signed_commit_signature,
X509Helpers::User1.signed_commit_base_data,
X509Helpers::User1.certificate_email,
X509Helpers::User1.signed_commit_time
)
expect(signature.x509_certificate).to have_attributes(certificate_attributes)
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
expect(signature.verified_signature).to be_falsey
expect(signature.verification_status).to eq(:unverified)
end
end
end
context 'invalid signature' do
it 'returns nil' do
signature = described_class.new(
X509Helpers::User1.signed_commit_signature.tr('A', 'B'),
X509Helpers::User1.signed_commit_base_data,
X509Helpers::User1.certificate_email,
X509Helpers::User1.signed_commit_time
)
expect(signature.x509_certificate).to be_nil
expect(signature.verified_signature).to be_falsey
expect(signature.verification_status).to eq(:unverified)
end
end
context 'invalid commit message' do
it 'returns nil' do
signature = described_class.new(
X509Helpers::User1.signed_commit_signature,
'x',
X509Helpers::User1.certificate_email,
X509Helpers::User1.signed_commit_time
)
expect(signature.x509_certificate).to be_nil
expect(signature.verified_signature).to be_falsey
expect(signature.verification_status).to eq(:unverified)
end
end
end
context 'certificate_crl' do
describe 'valid crlDistributionPoints' do
before do
allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension).and_call_original
allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension)
.with('crlDistributionPoints')
.and_return("\nFull Name:\n URI:http://ch.siemens.com/pki?ZZZZZZA2.crl\n URI:ldap://cl.siemens.net/CN=ZZZZZZA2,L=PKI?certificateRevocationList\n URI:ldap://cl.siemens.com/CN=ZZZZZZA2,o=Trustcenter?certificateRevocationList\n")
end
it 'creates an issuer' do
signature = described_class.new(
X509Helpers::User1.signed_commit_signature,
X509Helpers::User1.signed_commit_base_data,
X509Helpers::User1.certificate_email,
X509Helpers::User1.signed_commit_time
)
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
end
end
describe 'valid crlDistributionPoints providing multiple http URIs' do
before do
allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension).and_call_original
allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension)
.with('crlDistributionPoints')
.and_return("\nFull Name:\n URI:http://cdp1.pca.dfn.de/dfn-ca-global-g2/pub/crl/cacrl.crl\n\nFull Name:\n URI:http://cdp2.pca.dfn.de/dfn-ca-global-g2/pub/crl/cacrl.crl\n")
end
it 'extracts the first URI' do
signature = described_class.new(
X509Helpers::User1.signed_commit_signature,
X509Helpers::User1.signed_commit_base_data,
X509Helpers::User1.certificate_email,
X509Helpers::User1.signed_commit_time
)
expect(signature.x509_certificate.x509_issuer.crl_url).to eq("http://cdp1.pca.dfn.de/dfn-ca-global-g2/pub/crl/cacrl.crl")
end
end
end
context 'email' do
describe 'subjectAltName with email, othername' do
before do
allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension).and_call_original
allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension)
.with('subjectAltName')
.and_return("email:gitlab@example.com, othername:<unsupported>")
end
it 'extracts email' do
signature = described_class.new(
X509Helpers::User1.signed_commit_signature,
X509Helpers::User1.signed_commit_base_data,
'gitlab@example.com',
X509Helpers::User1.signed_commit_time
)
expect(signature.x509_certificate.email).to eq("gitlab@example.com")
end
end
describe 'subjectAltName with othername, email' do
before do
allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension).and_call_original
allow_any_instance_of(Gitlab::X509::Signature).to receive(:get_certificate_extension)
.with('subjectAltName')
.and_return("othername:<unsupported>, email:gitlab@example.com")
end
it 'extracts email' do
signature = described_class.new(
X509Helpers::User1.signed_commit_signature,
X509Helpers::User1.signed_commit_base_data,
'gitlab@example.com',
X509Helpers::User1.signed_commit_time
)
expect(signature.x509_certificate.email).to eq("gitlab@example.com")
end
end
end
2020-05-24 23:13:21 +05:30
2023-03-04 22:38:38 +05:30
describe '#signed_by_user' do
2021-06-02 17:11:27 +05:30
subject do
described_class.new(
X509Helpers::User1.signed_tag_signature,
X509Helpers::User1.signed_tag_base_data,
X509Helpers::User1.certificate_email,
X509Helpers::User1.signed_commit_time
2023-03-04 22:38:38 +05:30
).signed_by_user
2021-06-02 17:11:27 +05:30
end
2020-05-24 23:13:21 +05:30
context 'if email is assigned to a user' do
2023-03-04 22:38:38 +05:30
let!(:signed_by_user) { create(:user, email: X509Helpers::User1.certificate_email) }
2020-05-24 23:13:21 +05:30
it 'returns user' do
2023-03-04 22:38:38 +05:30
is_expected.to eq(signed_by_user)
2020-05-24 23:13:21 +05:30
end
end
it 'if email is not assigned to a user, return nil' do
2021-06-02 17:11:27 +05:30
is_expected.to be_nil
2020-05-24 23:13:21 +05:30
end
end
context 'tag signature' do
let(:certificate_attributes) do
{
subject_key_identifier: X509Helpers::User1.tag_certificate_subject_key_identifier,
subject: X509Helpers::User1.certificate_subject,
email: X509Helpers::User1.certificate_email,
serial_number: X509Helpers::User1.tag_certificate_serial
}
end
let(:issuer_attributes) do
{
subject_key_identifier: X509Helpers::User1.tag_issuer_subject_key_identifier,
subject: X509Helpers::User1.tag_certificate_issuer,
crl_url: X509Helpers::User1.tag_certificate_crl
}
end
context 'verified signature' do
2021-12-11 22:18:48 +05:30
let_it_be(:user) { create(:user, :unconfirmed, email: X509Helpers::User1.certificate_email) }
2021-06-02 17:11:27 +05:30
subject(:signature) do
described_class.new(
X509Helpers::User1.signed_tag_signature,
X509Helpers::User1.signed_tag_base_data,
X509Helpers::User1.certificate_email,
X509Helpers::User1.signed_commit_time
)
end
2020-05-24 23:13:21 +05:30
context 'with trusted certificate store' do
before do
store = OpenSSL::X509::Store.new
certificate = OpenSSL::X509::Certificate.new X509Helpers::User1.trust_cert
store.add_cert(certificate)
allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
end
2021-12-11 22:18:48 +05:30
context 'when user email is confirmed' do
before_all do
user.confirm
end
2020-05-24 23:13:21 +05:30
2021-12-11 22:18:48 +05:30
it 'returns a verified signature if email does match', :ggregate_failures do
expect(signature.x509_certificate).to have_attributes(certificate_attributes)
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
expect(signature.verified_signature).to be_truthy
expect(signature.verification_status).to eq(:verified)
end
2021-06-02 17:11:27 +05:30
2021-12-11 22:18:48 +05:30
it 'returns an unverified signature if email does not match', :aggregate_failures do
signature = described_class.new(
X509Helpers::User1.signed_tag_signature,
X509Helpers::User1.signed_tag_base_data,
"gitlab@example.com",
X509Helpers::User1.signed_commit_time
)
expect(signature.x509_certificate).to have_attributes(certificate_attributes)
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
expect(signature.verified_signature).to be_truthy
expect(signature.verification_status).to eq(:unverified)
end
2021-06-02 17:11:27 +05:30
2021-12-11 22:18:48 +05:30
it 'returns an unverified signature if email does match and time is wrong', :aggregate_failures do
signature = described_class.new(
X509Helpers::User1.signed_tag_signature,
X509Helpers::User1.signed_tag_base_data,
X509Helpers::User1.certificate_email,
Time.new(2020, 2, 22)
)
expect(signature.x509_certificate).to have_attributes(certificate_attributes)
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
expect(signature.verified_signature).to be_falsey
expect(signature.verification_status).to eq(:unverified)
end
2020-05-24 23:13:21 +05:30
2021-12-11 22:18:48 +05:30
it 'returns an unverified signature if certificate is revoked' do
expect(signature.verification_status).to eq(:verified)
2020-05-24 23:13:21 +05:30
2021-12-11 22:18:48 +05:30
signature.x509_certificate.revoked!
2020-05-24 23:13:21 +05:30
2021-12-11 22:18:48 +05:30
expect(signature.verification_status).to eq(:unverified)
end
2020-05-24 23:13:21 +05:30
end
2021-12-11 22:18:48 +05:30
it 'returns an unverified signature if the email matches but is not confirmed' do
2020-05-24 23:13:21 +05:30
expect(signature.verification_status).to eq(:unverified)
end
end
context 'without trusted certificate within store' do
before do
store = OpenSSL::X509::Store.new
allow(OpenSSL::X509::Store).to receive(:new)
.and_return(
store
)
end
it 'returns an unverified signature' do
expect(signature.x509_certificate).to have_attributes(certificate_attributes)
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
expect(signature.verified_signature).to be_falsey
expect(signature.verification_status).to eq(:unverified)
end
end
end
context 'invalid signature' do
it 'returns nil' do
signature = described_class.new(
X509Helpers::User1.signed_tag_signature.tr('A', 'B'),
X509Helpers::User1.signed_tag_base_data,
X509Helpers::User1.certificate_email,
X509Helpers::User1.signed_commit_time
)
expect(signature.x509_certificate).to be_nil
expect(signature.verified_signature).to be_falsey
expect(signature.verification_status).to eq(:unverified)
end
end
context 'invalid message' do
it 'returns nil' do
signature = described_class.new(
X509Helpers::User1.signed_tag_signature,
'x',
X509Helpers::User1.certificate_email,
X509Helpers::User1.signed_commit_time
)
expect(signature.x509_certificate).to be_nil
expect(signature.verified_signature).to be_falsey
expect(signature.verification_status).to eq(:unverified)
end
end
end
2020-04-22 19:07:51 +05:30
end