Skip to content

Commit

Permalink
Merge pull request #41 from cub8/openssl-30-and-ruby-30-support
Browse files Browse the repository at this point in the history
Add OpenSSL 3.0 and Ruby >= 2.7.4 support
  • Loading branch information
mt-clearhaus authored Sep 5, 2023
2 parents 6a75a6b + 99bbec3 commit a04f1ad
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 52 deletions.
11 changes: 7 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
ruby: [2.7]
runs-on: ${{ matrix.os }}
ruby:
- '2.7'
- '3.0'
- '3.1'
- '3.2'
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v2
uses: actions/checkout@v3

- name: Run tests
uses: ruby/setup-ruby@v1
Expand Down
2 changes: 1 addition & 1 deletion lib/pedicel/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Pedicel
VERSION = '1.1.0'.freeze
VERSION = '1.2.0'.freeze
end
9 changes: 5 additions & 4 deletions pedicel.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ Gem::Specification.new do |s|

s.files = Dir.glob("lib/**/*.rb")

s.add_runtime_dependency 'dry-validation', '1.9'
s.add_runtime_dependency 'dry-validation', '~> 1.9'
s.add_runtime_dependency 'dry-core', '1.0.0'
s.add_runtime_dependency 'dry-schema', '~> 1.9'
s.add_runtime_dependency 'dry-logic', '~> 1.0'

s.required_ruby_version = '~> 2.7.4'
s.required_ruby_version = '>= 2.7.4'

s.add_development_dependency 'pedicel-pay', '~> 0.0.8'
s.add_development_dependency 'pry', '~> 0.0'
s.add_development_dependency 'rake', '~> 12.3'
s.add_development_dependency 'rspec', '~> 3.7'
s.add_development_dependency 'pedicel-pay', '~> 0.0'
s.add_development_dependency 'pry', '~> 0.0'
end
64 changes: 31 additions & 33 deletions spec/lib/pedicel/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,37 +105,37 @@
subject { lambda { pedicel.verify_signature } }

it 'does not err when all checks are good' do
is_expected.to_not raise_error
expect { subject.call }.to_not raise_error
end

it 'checks for the custom OIDs (1.a)' do
expect(Pedicel::Base).to receive(:extract_certificates).and_raise(Pedicel::SignatureError, 'boom')

is_expected.to raise_error(Pedicel::SignatureError, 'boom')
expect { subject.call }.to raise_error(Pedicel::SignatureError, 'boom')
end

it 'checks that the root certificate is trusted (1.b)' do
expect(Pedicel::Base).to receive(:verify_root_certificate).and_raise(Pedicel::SignatureError, 'boom')

is_expected.to raise_error(Pedicel::SignatureError, 'boom')
expect { subject.call }.to raise_error(Pedicel::SignatureError, 'boom')
end

it 'checks the chain (1.c)' do
expect(Pedicel::Base).to receive(:verify_x509_chain).and_raise(Pedicel::SignatureError, 'boom')

is_expected.to raise_error(Pedicel::SignatureError, 'boom')
expect { subject.call }.to raise_error(Pedicel::SignatureError, 'boom')
end

it "checks the token's signature (1.d)" do
expect(pedicel).to receive(:validate_signature).and_raise(Pedicel::SignatureError, 'boom')

is_expected.to raise_error(Pedicel::SignatureError, 'boom')
expect { subject.call }.to raise_error(Pedicel::SignatureError, 'boom')
end

it 'checks signing time (1.e)' do
expect(Pedicel::Base).to receive(:verify_signed_time).and_raise(Pedicel::SignatureError, 'boom')

is_expected.to raise_error(Pedicel::SignatureError, 'boom')
expect { subject.call }.to raise_error(Pedicel::SignatureError, 'boom')
end
end

Expand Down Expand Up @@ -197,26 +197,26 @@
end

it 'does not err when all checks are good' do
is_expected.to_not raise_error
expect { subject.call }.to_not raise_error
end

it 'errs if there is no leaf OID' do
pedicel.config.merge!(oid_leaf_certificate: 'invalid oid')

is_expected.to raise_error(Pedicel::SignatureError, /no.*leaf.*found/)
expect { subject.call }.to raise_error(Pedicel::SignatureError, /no.*leaf.*found/)
end

it 'errs if there is no intermediate OID' do
pedicel.config.merge!(oid_intermediate_certificate: 'invalid oid')

is_expected.to raise_error(Pedicel::SignatureError, /no.*intermediate.*found/)
expect { subject.call }.to raise_error(Pedicel::SignatureError, /no.*intermediate.*found/)
end

it 'errs if there are neither a leaf nor an intermediate OID' do
pedicel.config.merge!(oid_leaf_certificate: 'invalid oid')
pedicel.config.merge!(oid_intermediate_certificate: 'invalid oid')

is_expected.to raise_error(Pedicel::SignatureError, /no.*(leaf|intermediate).*found/)
expect { subject.call }.to raise_error(Pedicel::SignatureError, /no.*(leaf|intermediate).*found/)
end
end

Expand All @@ -233,16 +233,15 @@

it 'handles that one certificate can be both intermediate and leaf' do
def create_special_certificate(ca_key, ca_certificate, config, oids)
key = OpenSSL::PKey::EC.new(PedicelPay::EC_CURVE)
key.generate_key
key = OpenSSL::PKey::EC.generate(PedicelPay::EC_CURVE)

cert = OpenSSL::X509::Certificate.new
# https://www.ietf.org/rfc/rfc5280.txt -> Section 4.1, search for "v3(2)".
cert.version = 2
cert.serial = 1
cert.subject = config[:subject][:intermediate]
cert.issuer = ca_certificate.subject
cert.public_key = PedicelPay::Helper.ec_key_to_pkey_public_key(key)
cert.public_key = key
cert.not_before = config[:valid].min
cert.not_after = config[:valid].max

Expand Down Expand Up @@ -356,117 +355,116 @@ def create_special_certificate(ca_key, ca_certificate, config, oids)
end

it 'does not err when the chain is good' do
expect{Pedicel::Base.verify_x509_chain(params)}.to_not raise_error
expect{Pedicel::Base.verify_x509_chain(**params)}.to_not raise_error
end

context 'intermediate equals leaf' do
it 'errs if intermediate = leaf (because root did not sign leaf)' do
params[:intermediate] = params[:leaf]
expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to intermediate')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to intermediate')
end

it 'errs even if intermediate = leaf is self-signed' do
params[:intermediate] = params[:leaf] = PedicelPay::Backend.generate.ca_certificate
expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to intermediate')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to intermediate')
end
end

context 'leaf equals intermediate' do
it 'errs if leaf = intermediate (because intermediate did not sign leaf)' do
params[:leaf] = params[:intermediate]
expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to leaf')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to leaf')
end

it 'errs even if leaf = intermediate is self-signed' do
params[:leaf] = params[:intermediate] = PedicelPay::Backend.generate.ca_certificate
expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to intermediate')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to intermediate')
end
end

it 'errs if intermediate equals root (because root did not sign leaf)' do
params[:intermediate] = params[:root]
expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to leaf')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to leaf')
end

it 'errs if root equals intermediate (because intermediate is not self-signed)' do
params[:root] = params[:intermediate]
expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to root')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to root')
end

it 'errs if leaf equals root (because intermediate did not sign leaf)' do
params[:leaf] = params[:root]
expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to leaf')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to leaf')
end

it 'errs if root equals leaf (becuase leaf is not self-signed)' do
params[:root] = params[:leaf]
expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to root')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to root')
end

it 'errs if leaf is used for all 3 certificates (because of multiple reasons)' do
params[:root] = params[:leaf]
params[:intermediate] = params[:leaf]
expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to root')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to root')
end

it 'errs if intermediate is used for all 3 certificates' do
params[:root] = params[:intermediate]
params[:leaf] = params[:intermediate]
expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to root')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to root')
end

it 'does not err when root is used for all 3 certificates' do
params[:intermediate] = params[:root]
params[:leaf] = params[:root]
expect{Pedicel::Base.verify_x509_chain(params)}.to_not raise_error
expect{Pedicel::Base.verify_x509_chain(**params)}.to_not raise_error
end

it 'errs if intermediate is not signed by root' do
params[:root] = PedicelPay::Backend.generate.ca_certificate

expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to intermediate')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to intermediate')
end

it 'errs if leaf is not signed by intermediate (1)' do
params[:leaf] = PedicelPay::Backend.generate.leaf_certificate

expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to leaf')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to leaf')
end

it 'errs if leaf is not signed by intermediate (2)' do
another_backend = PedicelPay::Backend.generate
params[:root] = another_backend.ca_certificate
params[:intermediate] = another_backend.intermediate_certificate

expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to leaf')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to leaf')
end

it 'errs if leaf is not signed by intermediate and intermediate is not signed by root' do
params[:root] = PedicelPay::Backend.generate.ca_certificate
params[:intermediate] = PedicelPay::Backend.generate.intermediate_certificate

expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to intermediate')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to intermediate')
end

it 'errs if certs are interchanged' do
params.keys.permutation.reject{|ks| ks == params.keys}.each do |permutated_keys|
permutated_params = permutated_keys.zip(params.values).to_h

expect{Pedicel::Base.verify_x509_chain(permutated_params)}.to raise_error(Pedicel::SignatureError, /\Ainvalid chain due to (root|intermediate|leaf)\z/)
expect{Pedicel::Base.verify_x509_chain(**permutated_params)}.to raise_error(Pedicel::SignatureError, /\Ainvalid chain due to (root|intermediate|leaf)\z/)
end
end

it 'errs even if the leaf is self-signed' do
params[:leaf] = PedicelPay::Backend.generate.ca_certificate
expect{Pedicel::Base.verify_x509_chain(params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to leaf')
expect{Pedicel::Base.verify_x509_chain(**params)}.to raise_error(Pedicel::SignatureError, 'invalid chain due to leaf')
end

it 'is true when the chain is good' do
expect(Pedicel::Base.verify_x509_chain(params)).to be true
expect(Pedicel::Base.verify_x509_chain(**params)).to be true
end
end


describe 'Pedicel::Base.verify_signed_time' do
let (:signature) { OpenSSL::PKCS7.new(pedicel.signature) }
let (:now) { signature.signers.first.signed_time }
Expand Down
3 changes: 1 addition & 2 deletions spec/lib/pedicel/ec_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,7 @@
end

it "errs if the private key is from another curve than the token's ephemeral public key" do
key = OpenSSL::PKey::EC.new('wap-wsg-idm-ecid-wtls1') # Apple, do never switch to this curve.
key.generate_key
key = OpenSSL::PKey::EC.generate('wap-wsg-idm-ecid-wtls1') # Apple, do never switch to this curve.

expect{pedicel.shared_secret(private_key: key)}.to raise_error(Pedicel::EcKeyError, /curve.*differ/)
end
Expand Down
8 changes: 0 additions & 8 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,2 @@
require 'securerandom'
require 'base64'

def ec_key_to_pkey_public_key(ec_key)
# EC#public_key is not a PKey public key, but an EC point.
pub = OpenSSL::PKey::EC.new(ec_key.group)
pub.public_key = ec_key.is_a?(OpenSSL::PKey::PKey) ? ec_key.public_key : ec_key

pub
end

0 comments on commit a04f1ad

Please sign in to comment.