Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updating ruby-version, refactoring ec_crypto_suite to support OpenSSL… #19

Merged
merged 20 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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