From b791f6adbcaa26cc8e3f1342430750a01fe00830 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 17 May 2022 17:40:06 +0200 Subject: [PATCH 1/4] Fix compatibility with OpenSSL 3 --- lib/webpush/vapid_key.rb | 57 +++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/lib/webpush/vapid_key.rb b/lib/webpush/vapid_key.rb index d2b953c..67d240d 100644 --- a/lib/webpush/vapid_key.rb +++ b/lib/webpush/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,8 +72,15 @@ def to_h alias to_hash to_h def to_pem - public_key = OpenSSL::PKey::EC.new curve - public_key.private_key = nil + asn1 = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::ObjectId('id-ecPublicKey'), + OpenSSL::ASN1::ObjectId(curve_name), + ]), + OpenSSL::ASN1::BitString(curve.public_key.to_octet_string(:uncompressed)) + ]) + + public_key = OpenSSL::PKey::EC.new(asn1.to_der) curve.to_pem + public_key.to_pem end @@ -88,6 +89,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) From 305e35003f6c772203f4aadd57200fdbe9361cf8 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 17 May 2022 17:44:14 +0200 Subject: [PATCH 2/4] Fix tests --- spec/webpush/encryption_spec.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/webpush/encryption_spec.rb b/spec/webpush/encryption_spec.rb index fc61910..fb320ab 100644 --- a/spec/webpush/encryption_spec.rb +++ b/spec/webpush/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 From 878a6bd70cbc46c26ce369759ffc4332de71e02b Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 17 May 2022 17:45:23 +0200 Subject: [PATCH 3/4] Further OpenSSL 3 fixes --- lib/webpush/encryption.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/webpush/encryption.rb b/lib/webpush/encryption.rb index 099e42e..02de18c 100644 --- a/lib/webpush/encryption.rb +++ b/lib/webpush/encryption.rb @@ -11,8 +11,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) @@ -74,4 +73,4 @@ def blank?(value) value.nil? || value.empty? end end -end \ No newline at end of file +end From 409b5148b6af06366b15781d17992a6b4658c992 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 29 Nov 2022 18:43:25 +0100 Subject: [PATCH 4/4] Use public_to_pem instead of lower-level ASN1 representation --- lib/webpush/vapid_key.rb | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/webpush/vapid_key.rb b/lib/webpush/vapid_key.rb index 67d240d..ab02056 100644 --- a/lib/webpush/vapid_key.rb +++ b/lib/webpush/vapid_key.rb @@ -72,17 +72,7 @@ def to_h alias to_hash to_h def to_pem - asn1 = OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::Sequence([ - OpenSSL::ASN1::ObjectId('id-ecPublicKey'), - OpenSSL::ASN1::ObjectId(curve_name), - ]), - OpenSSL::ASN1::BitString(curve.public_key.to_octet_string(:uncompressed)) - ]) - - public_key = OpenSSL::PKey::EC.new(asn1.to_der) - - curve.to_pem + public_key.to_pem + curve.to_pem + curve.public_to_pem end def inspect