diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 038c214..a4b5275 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['3.0', '3.1'] + ruby-version: ['2.7', '3.0', '3.1', '3.2'] steps: - uses: actions/checkout@v3 - name: Set up Ruby diff --git a/lib/web_push/encryption.rb b/lib/web_push/encryption.rb index 2d33f1d..4c6b54e 100644 --- a/lib/web_push/encryption.rb +++ b/lib/web_push/encryption.rb @@ -10,8 +10,7 @@ def encrypt(message, p256dh, auth) group_name = 'prime256v1' salt = Random.new.bytes(16) - server = OpenSSL::PKey::EC.new(group_name) - server.generate_key + server = OpenSSL::PKey::EC.generate(group_name) server_public_key_bn = server.public_key.to_bn group = OpenSSL::PKey::EC::Group.new(group_name) @@ -72,4 +71,4 @@ def blank?(value) value.nil? || value.empty? end end -end \ No newline at end of file +end diff --git a/lib/web_push/vapid_key.rb b/lib/web_push/vapid_key.rb index c69f7aa..c9c8959 100644 --- a/lib/web_push/vapid_key.rb +++ b/lib/web_push/vapid_key.rb @@ -10,8 +10,7 @@ class VapidKey # @return [WebPush::VapidKey] a VapidKey instance for the given public and private keys def self.from_keys(public_key, private_key) key = new - key.public_key = public_key - key.private_key = private_key + key.set_keys!(public_key, private_key) key end @@ -20,19 +19,14 @@ def self.from_keys(public_key, private_key) # # @return [WebPush::VapidKey] a VapidKey instance for the given public and private keys def self.from_pem(pem) - key = new - src = OpenSSL::PKey.read pem - key.curve.public_key = src.public_key - key.curve.private_key = src.private_key - - key + new(OpenSSL::PKey.read pem) end attr_reader :curve - def initialize - @curve = OpenSSL::PKey::EC.new('prime256v1') - @curve.generate_key + def initialize(pkey = nil) + @curve = pkey + @curve = OpenSSL::PKey::EC.generate('prime256v1') if @curve.nil? end # Retrieve the encoded elliptic curve public key for VAPID protocol @@ -57,11 +51,11 @@ def private_key end def public_key=(key) - curve.public_key = OpenSSL::PKey::EC::Point.new(group, to_big_num(key)) + set_keys!(key, nil) end def private_key=(key) - curve.private_key = to_big_num(key) + set_keys!(nil, key) end def curve_name @@ -78,7 +72,7 @@ def to_h alias to_hash to_h def to_pem - private_key_to_pem + public_key_to_pem + curve.to_pem + curve.public_to_pem end def private_key_to_pem @@ -93,6 +87,32 @@ def inspect "#<#{self.class}:#{object_id.to_s(16)} #{to_h.map { |k, v| ":#{k}=#{v}" }.join(' ')}>" end + def set_keys!(public_key = nil, private_key = nil) + if public_key.nil? + public_key = curve.public_key + else + public_key = OpenSSL::PKey::EC::Point.new(group, to_big_num(public_key)) + end + + if private_key.nil? + private_key = curve.private_key + else + private_key = to_big_num(private_key) + end + + asn1 = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Integer.new(1), + # Not properly padded but OpenSSL doesn't mind + OpenSSL::ASN1::OctetString(private_key.to_s(2)), + OpenSSL::ASN1::ObjectId('prime256v1', 0, :EXPLICIT), + OpenSSL::ASN1::BitString(public_key.to_octet_string(:uncompressed), 1, :EXPLICIT), + ]) + + der = asn1.to_der + + @curve = OpenSSL::PKey::EC.new(der) + end + private def to_big_num(key) diff --git a/spec/web_push/encryption_spec.rb b/spec/web_push/encryption_spec.rb index 19ee27e..3aed2ac 100644 --- a/spec/web_push/encryption_spec.rb +++ b/spec/web_push/encryption_spec.rb @@ -4,9 +4,7 @@ describe '#encrypt' do let(:curve) do group = 'prime256v1' - curve = OpenSSL::PKey::EC.new(group) - curve.generate_key - curve + OpenSSL::PKey::EC.generate(group) end let(:p256dh) do diff --git a/web-push.gemspec b/web-push.gemspec index 4f8e21d..75c9cab 100644 --- a/web-push.gemspec +++ b/web-push.gemspec @@ -12,7 +12,7 @@ Gem::Specification.new do |spec| spec.files = `git ls-files`.split("\n") - spec.required_ruby_version = '>= 3.0' + spec.required_ruby_version = '>= 2.7' spec.add_dependency 'hkdf', '~> 1.0' spec.add_dependency 'jwt', '~> 2.0'