Skip to content

Commit

Permalink
Merge pull request #19 from EthicalIdentity/feature/openssl3.0compati…
Browse files Browse the repository at this point in the history
…bility

updating ruby-version, refactoring ec_crypto_suite to support OpenSSL…
  • Loading branch information
jonmchan authored Oct 24, 2023
2 parents c1baee9 + f99691c commit d55d85d
Show file tree
Hide file tree
Showing 23 changed files with 381 additions and 102 deletions.
12 changes: 7 additions & 5 deletions .github/workflows/rspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,21 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ['2.6', '2.7', '3.0']
ruby-version: ['3.0', '3.1', '3.2']

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Set up Ruby
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
# change this to (see https://github.com/ruby/setup-ruby#versioning):
# uses: ruby/setup-ruby@v1
uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
uses: ruby/setup-ruby@master
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: Run tests
run: bundle exec rake
env:
CODECOV_TOKEN: 4b75ccca-3149-4610-99fb-3a5aeff4ff00
- uses: codecov/codecov-action@v3
with:
token: 4b75ccca-3149-4610-99fb-3a5aeff4ff00

5 changes: 2 additions & 3 deletions .github/workflows/rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ jobs:

steps:
- uses: actions/checkout@v2
- name: Set up Ruby 2.7
- name: Set up Ruby 3.0
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
ruby-version: 3.0
- name: Cache gems
uses: actions/cache@v1
with:
Expand All @@ -22,7 +22,6 @@ jobs:
- name: Install gems
run: |
bundle config path vendor/bundle
bundle config set without 'default doc job cable storage ujs test db'
bundle install --jobs 4 --retry 3
- name: Run RuboCop
run: bundle exec rubocop --parallel
3 changes: 1 addition & 2 deletions .github/workflows/yardoc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
- name: Set up Ruby 2.7
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
ruby-version: 3.2
- name: Cache gems
uses: actions/cache@v1
with:
Expand All @@ -22,7 +22,6 @@ jobs:
- name: Install gems
run: |
bundle config path vendor/bundle
bundle config set without 'default doc job cable storage ujs test db'
bundle install --jobs 4 --retry 3
- name: Run yard stats
run: bundle exec yard stats --list-undoc --no-cache --fail-on-warning
6 changes: 4 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Metrics/BlockLength:

AllCops:
NewCops: enable
TargetRubyVersion: 2.6
TargetRubyVersion: 3.0
Exclude:
- vendor/bundle/**/*
# exclude protoc generated code
Expand All @@ -20,4 +20,6 @@ AllCops:
- 'lib/orderer/*'
- 'lib/peer/*'


RSpec/SpecFilePathFormat:
Exclude:
- spec/fabric/entities/*
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.7.5
3.2.2
9 changes: 9 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,12 @@ gemspec

gem 'rake', '~> 12.3.3'
gem 'rspec', '~> 3.0'

gem 'factory_bot', '~> 6.3.0'
gem 'grpc-tools', '~> 1.59.0'
gem 'rubocop', '~> 1.57', '>= 1.57.1'
gem 'rubocop-rspec', '~> 2.24.1'
gem 'simplecov', '~> 0.22.0'
gem 'simplecov-cobertura', '~> 2.1'
gem 'timecop', '~> 0.9.8'
gem 'yard', '~> 0.9.34'
1 change: 0 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

require 'bundler/gem_tasks'
require 'rspec/core/rake_task'
require 'rake/notes/rake_task'

RSpec::Core::RakeTask.new(:spec)

Expand Down
13 changes: 2 additions & 11 deletions fabric-gateway.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
spec.description = 'Ruby port of the Hyperledger Fabric Gateway SDK'
spec.homepage = 'https://github.com/ethicalidentity/fabric-gateway-ruby'
spec.license = 'MIT'
spec.required_ruby_version = Gem::Requirement.new('>= 2.6.0')
spec.required_ruby_version = Gem::Requirement.new('>= 3.0')

spec.metadata['allowed_push_host'] = 'https://rubygems.org'

Expand All @@ -28,17 +28,8 @@ Gem::Specification.new do |spec|
spec.bindir = 'exe'
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ['lib']
spec.add_dependency('google-protobuf', '>= 3.19.1')
spec.add_dependency('google-protobuf', '~> 3.24', '>= 3.24.4')
spec.add_dependency('grpc', '~> 1.42')
spec.add_development_dependency('codecov', '~> 0.6.0')
spec.add_development_dependency('factory_bot', '~> 6.2.0')
spec.add_development_dependency('grpc-tools', '~> 1.46.2')
spec.add_development_dependency('rake-notes', '~> 0.2.0')
spec.add_development_dependency('rubocop', '~> 1.23.0')
spec.add_development_dependency('rubocop-rspec', '~> 2.6.0')
spec.add_development_dependency('simplecov', '~> 0.21.2')
spec.add_development_dependency('timecop', '~> 0.9.4')
spec.add_development_dependency('yard', '~> 0.9.27')
spec.metadata = {
'rubygems_mfa_required' => 'true'
}
Expand Down
73 changes: 48 additions & 25 deletions lib/fabric/ec_crypto_suite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,15 @@ def sign(private_key, message)

def verify(public_key, message, signature)
digest = digest message
openssl_pkey = openssl_pkey_from_public_key public_key
openssl_pkey = pkey_from_public_key public_key
sequence = OpenSSL::ASN1.decode signature
return false unless check_malleability sequence, openssl_pkey.group.order

openssl_pkey.dsa_verify_asn1(digest, signature)
end

def generate_private_key
key = OpenSSL::PKey::EC.new curve
key.generate_key!
key = OpenSSL::PKey::EC.generate(curve)

key.private_key.to_s(16).downcase
end
Expand Down Expand Up @@ -133,15 +132,35 @@ def decrypt(secret, data)
aes.update(encrypted_data) + aes.final
end

def pkey_pem_from_private_key(private_key)
# when https://github.com/ruby/openssl/pull/555 gets merged, consider refactoring
# the code here
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def pkey_from_private_key(private_key)
public_key = restore_public_key private_key
key = OpenSSL::PKey::EC.new curve
key.private_key = OpenSSL::BN.new private_key, 16
key.public_key = OpenSSL::PKey::EC::Point.new key.group,
OpenSSL::BN.new(public_key, 16)

pkey = OpenSSL::PKey::EC.new(key.public_key.group)
pkey.public_key = key.public_key
group = OpenSSL::PKey::EC::Group.new(curve)

private_key_bn = OpenSSL::BN.new(private_key, 16)
public_key_bn = OpenSSL::BN.new(public_key, 16)
public_key_point = OpenSSL::PKey::EC::Point.new(group, public_key_bn)

asn1 = OpenSSL::ASN1::Sequence(
[
OpenSSL::ASN1::Integer.new(1),
OpenSSL::ASN1::OctetString(private_key_bn.to_s(2)),
OpenSSL::ASN1::ObjectId(curve, 0, :EXPLICIT),
OpenSSL::ASN1::BitString(public_key_point.to_octet_string(:uncompressed), 1, :EXPLICIT)
]
)

OpenSSL::PKey::EC.new(asn1.to_der)
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/MethodLength

def pem_from_private_key(private_key)
pkey = pkey_from_private_key(private_key)

pkey.to_pem
end
Expand All @@ -151,29 +170,33 @@ def key_from_pem(pem)
key.private_key.to_s(16).downcase
end

def pkey_from_x509_certificate(certificate)
def public_key_from_x509_certificate(certificate)
cert = OpenSSL::X509::Certificate.new(certificate)
cert.public_key.public_key.to_bn.to_s(16).downcase
end

def openssl_pkey_from_public_key(public_key)
pkey = OpenSSL::PKey::EC.new curve
pkey.public_key = OpenSSL::PKey::EC::Point.new(pkey.group, OpenSSL::BN.new(public_key, 16))
# rubocop:disable Metrics/MethodLength
def pkey_from_public_key(public_key)
group = OpenSSL::PKey::EC::Group.new(curve)

pkey
end
public_key_bn = OpenSSL::BN.new(public_key, 16)
public_key_point = OpenSSL::PKey::EC::Point.new(group, public_key_bn)

private

def pkey_from_private_key(private_key)
public_key = restore_public_key private_key
key = OpenSSL::PKey::EC.new curve
key.private_key = OpenSSL::BN.new private_key, 16
key.public_key = OpenSSL::PKey::EC::Point.new key.group,
OpenSSL::BN.new(public_key, 16)
asn1 = OpenSSL::ASN1::Sequence.new(
[
OpenSSL::ASN1::Sequence.new([
OpenSSL::ASN1::ObjectId.new('id-ecPublicKey'),
OpenSSL::ASN1::ObjectId.new(group.curve_name)
]),
OpenSSL::ASN1::BitString.new(public_key_point.to_octet_string(:uncompressed))
]
)

key
OpenSSL::PKey::EC.new(asn1.to_der)
end
# rubocop:enable Metrics/MethodLength

private

# barely understand this code - this link provides a good explanation:
# http://coders-errand.com/malleability-ecdsa-signatures/
Expand Down
2 changes: 1 addition & 1 deletion lib/fabric/entities/identity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def initialize(private_key: nil, public_key: nil, certificate: nil, msp_id: nil,
# @return [boolean] true if valid, false otherwise
#
def validate_key_integrity
cert_pubkey = @crypto_suite.pkey_from_x509_certificate(certificate)
cert_pubkey = @crypto_suite.public_key_from_x509_certificate(certificate)
priv_pubkey = @crypto_suite.restore_public_key(@private_key)

@public_key == cert_pubkey && @public_key == priv_pubkey
Expand Down
4 changes: 2 additions & 2 deletions lib/fabric/entities/status.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ module Fabric
#
class Status
TRANSACTION_STATUSES = ::Protos::TxValidationCode.constants.map(&::Protos::TxValidationCode.method(:const_get))
.collect do |i|
.to_h do |i|
[::Protos::TxValidationCode.lookup(i), i]
end.to_h
end

# @return [Integer] Block number in which the transaction committed.
attr_reader :block_number
Expand Down
12 changes: 2 additions & 10 deletions spec/fabric/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,7 @@

context 'when passing invalid client_opts' do
let(:expected_message) do
if RUBY_VERSION.start_with?('2.6')
'unknown keyword: bad_arg'
else
'unknown keyword: :bad_arg'
end
'unknown keyword: :bad_arg'
end

it 'raises an error' do
Expand All @@ -57,11 +53,7 @@

context 'when grpc_client host and creds are passed' do
let(:expected_args) do
if RUBY_VERSION.start_with?('2.6')
['localhost:1234', :this_channel_is_insecure, {}]
else
['localhost:1234', :this_channel_is_insecure]
end
['localhost:1234', :this_channel_is_insecure]
end

before do
Expand Down
8 changes: 4 additions & 4 deletions spec/fabric/contract_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@
end

describe '#submit' do
let(:proposal_double) { instance_double('Proposal') }
let(:transaction_double) { instance_double('Transaction') }
let(:proposal_double) { instance_double(Fabric::Proposal) }
let(:transaction_double) { instance_double(Fabric::Transaction) }

before do
allow(transaction_double).to receive(:result).and_return('mocked result')
Expand Down Expand Up @@ -229,8 +229,8 @@
end

describe '#submit_transaction' do
let(:proposal_double) { instance_double('Proposal') }
let(:transaction_double) { instance_double('Transaction') }
let(:proposal_double) { instance_double(Fabric::Proposal) }
let(:transaction_double) { instance_double(Fabric::Transaction) }

before do
allow(transaction_double).to receive(:result).and_return('mocked result')
Expand Down
Loading

0 comments on commit d55d85d

Please sign in to comment.