main
  1# frozen_string_literal: true
  2
  3RSpec.describe Xml::Kit::Certificate do
  4  subject { described_class.new(certificate, use: :signing) }
  5
  6  let(:certificate) { generate_key_pair('password')[0] }
  7
  8  describe '#fingerprint' do
  9    specify { expect(subject.fingerprint).to be_instance_of(Xml::Kit::Fingerprint) }
 10  end
 11
 12  describe '#for?' do
 13    context 'when it is for signing' do
 14      subject { described_class.new(certificate, use: :signing) }
 15
 16      specify { expect(subject).to be_for(:signing) }
 17      specify { expect(subject).to be_signing }
 18      specify { expect(subject).not_to be_for(:encryption) }
 19      specify { expect(subject).not_to be_encryption }
 20    end
 21
 22    context 'when it is for encryption' do
 23      subject { described_class.new(certificate, use: :encryption) }
 24
 25      specify { expect(subject).to be_for(:encryption) }
 26      specify { expect(subject).not_to be_for(:signing) }
 27      specify { expect(subject).to be_encryption }
 28      specify { expect(subject).not_to be_signing }
 29    end
 30
 31    context 'when it is for both signing and encryption' do
 32      subject { described_class.new(certificate) }
 33
 34      specify { expect(subject).to be_for(:encryption) }
 35      specify { expect(subject).to be_for(:signing) }
 36      specify { expect(subject).to be_encryption }
 37      specify { expect(subject).to be_signing }
 38    end
 39  end
 40
 41  describe 'equality' do
 42    specify { expect(subject).to eql(subject) }
 43    specify { expect(described_class.new(certificate, use: :signing)).to eql(described_class.new(certificate, use: :signing)) }
 44  end
 45
 46  describe '#to_h' do
 47    specify { expect(subject.to_h).to eql(use: :signing, fingerprint: subject.fingerprint.to_s) }
 48  end
 49
 50  describe '#stripped' do
 51    let(:expected) { certificate.to_s.gsub(/-----BEGIN CERTIFICATE-----/, '').gsub(/-----END CERTIFICATE-----/, '').delete("\n") }
 52
 53    specify { expect(subject.stripped).to eql(expected) }
 54  end
 55
 56  describe '#x509' do
 57    let(:expected) { OpenSSL::X509::Certificate.new(certificate.to_s) }
 58    let(:actual) { subject.x509 }
 59
 60    specify { expect(actual).to be_instance_of(OpenSSL::X509::Certificate) }
 61    specify { expect(actual.to_s).to eql(expected.to_s) }
 62  end
 63
 64  describe '#expired?' do
 65    let(:certificate) { OpenSSL::X509::Certificate.new }
 66
 67    context 'when the certificate has not expired yet' do
 68      subject { described_class.new(certificate, use: :signing) }
 69
 70      before do
 71        certificate.not_before = 1.minute.ago
 72        certificate.not_after = 10.minutes.from_now
 73      end
 74
 75      specify { expect(subject).not_to be_expired(Time.now) }
 76    end
 77
 78    context 'when the current time is after the time of the expiration' do
 79      subject { described_class.new(certificate, use: :signing) }
 80
 81      before do
 82        certificate.not_before = 10.minutes.ago
 83        certificate.not_after = 1.minute.ago
 84      end
 85
 86      specify { expect(subject).to be_expired(Time.now) }
 87    end
 88  end
 89
 90  describe '#active?' do
 91    subject { described_class.new(certificate, use: :signing) }
 92
 93    let(:certificate) { OpenSSL::X509::Certificate.new }
 94    let(:private_key) { OpenSSL::PKey::RSA.new(2048) }
 95
 96    context 'when the current time is within the active window' do
 97      before do
 98        certificate.not_before = 1.minute.ago
 99        certificate.not_after = 10.minutes.from_now
100        certificate.public_key = private_key.public_key
101        certificate.sign(private_key, OpenSSL::Digest::SHA256.new)
102      end
103
104      specify { expect(subject).to be_active(Time.now) }
105
106      context 'when reading an x509 pem' do
107        subject { described_class.new(certificate.to_pem, use: :signing) }
108
109        specify { expect(subject).to be_active(Time.now) }
110      end
111    end
112
113    context 'when the current time is before the active window' do
114      before do
115        certificate.not_before = 1.minute.from_now
116        certificate.not_after = 10.minutes.from_now
117        certificate.public_key = private_key.public_key
118        certificate.sign(private_key, OpenSSL::Digest::SHA256.new)
119      end
120
121      specify { expect(subject).not_to be_active(Time.now) }
122
123      context 'when reading an x509 pem' do
124        subject { described_class.new(certificate.to_pem, use: :signing) }
125
126        specify { expect(subject).not_to be_active(Time.now) }
127      end
128    end
129
130    context 'when the current time is after the active window' do
131      before do
132        certificate.not_before = 10.minutes.ago
133        certificate.not_after = 1.minute.ago
134        certificate.public_key = private_key.public_key
135        certificate.sign(private_key, OpenSSL::Digest::SHA256.new)
136      end
137
138      specify { expect(subject).not_to be_active(Time.now) }
139
140      context 'when reading an x509 pem' do
141        subject { described_class.new(certificate.to_pem, use: :signing) }
142
143        specify { expect(subject).not_to be_active(Time.now) }
144      end
145    end
146  end
147
148  describe '#not_after, #not_before' do
149    subject { described_class.new(certificate, use: :signing) }
150
151    let(:certificate) { OpenSSL::X509::Certificate.new }
152
153    before do
154      certificate.not_before = 1.minute.from_now
155      certificate.not_after = 10.minutes.from_now
156    end
157
158    specify { expect(subject.not_after).to eql(certificate.not_after) }
159    specify { expect(subject.not_before).to eql(certificate.not_before) }
160  end
161
162  describe '#to_xml' do
163    context 'when generated' do
164      let(:result) { Hash.from_xml(subject.to_xml) }
165
166      specify { expect(result['KeyDescriptor']).to be_present }
167      specify { expect(result['KeyDescriptor']['use']).to eql('signing') }
168      specify { expect(result['KeyDescriptor']['KeyInfo']['xmlns']).to eql(Xml::Kit::Namespaces::XMLDSIG) }
169      specify { expect(result['KeyDescriptor']['KeyInfo']['X509Data']['X509Certificate']).to eql(subject.stripped) }
170    end
171
172    context 'when the certificate can be used for both signing and encryption' do
173      subject { described_class.new(certificate, use: nil) }
174
175      let(:result) { Hash.from_xml(subject.to_xml) }
176
177      specify { expect(result['KeyDescriptor']).to be_present }
178      specify { expect(result['KeyDescriptor']['use']).to be_nil }
179    end
180  end
181end