diff --git a/lib/jwt/jwk/rsa.rb b/lib/jwt/jwk/rsa.rb index b4e763f1..5f6d2288 100644 --- a/lib/jwt/jwk/rsa.rb +++ b/lib/jwt/jwk/rsa.rb @@ -86,28 +86,44 @@ def jwk_attributes(jwk_data, *attributes) def rsa_pkey(rsa_parameters) raise JWT::JWKError, 'Key format is invalid for RSA' unless rsa_parameters[:n] && rsa_parameters[:e] - populate_key(OpenSSL::PKey::RSA.new, rsa_parameters) + create_rsa_key(rsa_parameters) end - if OpenSSL::PKey::RSA.new.respond_to?(:set_key) - def populate_key(rsa_key, rsa_parameters) - rsa_key.set_key(rsa_parameters[:n], rsa_parameters[:e], rsa_parameters[:d]) - rsa_key.set_factors(rsa_parameters[:p], rsa_parameters[:q]) if rsa_parameters[:p] && rsa_parameters[:q] - rsa_key.set_crt_params(rsa_parameters[:dp], rsa_parameters[:dq], rsa_parameters[:qi]) if rsa_parameters[:dp] && rsa_parameters[:dq] && rsa_parameters[:qi] - rsa_key + if ::JWT.openssl_3? + ASN1_SEQUENCE = %i[n e d p q dp dq qi].freeze + def create_rsa_key(rsa_parameters) + sequence = ASN1_SEQUENCE.each_with_object([]) do |key, arr| + next if rsa_parameters[key].nil? + + arr << OpenSSL::ASN1::Integer.new(rsa_parameters[key]) + end + + if sequence.size > 2 # For a private key + sequence.unshift(OpenSSL::ASN1::Integer.new(0)) + end + + OpenSSL::PKey::RSA.new(OpenSSL::ASN1::Sequence(sequence).to_der) + end + elsif OpenSSL::PKey::RSA.new.respond_to?(:set_key) + def create_rsa_key(rsa_parameters) + OpenSSL::PKey::RSA.new.tap do |rsa_key| + rsa_key.set_key(rsa_parameters[:n], rsa_parameters[:e], rsa_parameters[:d]) + rsa_key.set_factors(rsa_parameters[:p], rsa_parameters[:q]) if rsa_parameters[:p] && rsa_parameters[:q] + rsa_key.set_crt_params(rsa_parameters[:dp], rsa_parameters[:dq], rsa_parameters[:qi]) if rsa_parameters[:dp] && rsa_parameters[:dq] && rsa_parameters[:qi] + end end else - def populate_key(rsa_key, rsa_parameters) - rsa_key.n = rsa_parameters[:n] - rsa_key.e = rsa_parameters[:e] - rsa_key.d = rsa_parameters[:d] if rsa_parameters[:d] - rsa_key.p = rsa_parameters[:p] if rsa_parameters[:p] - rsa_key.q = rsa_parameters[:q] if rsa_parameters[:q] - rsa_key.dmp1 = rsa_parameters[:dp] if rsa_parameters[:dp] - rsa_key.dmq1 = rsa_parameters[:dq] if rsa_parameters[:dq] - rsa_key.iqmp = rsa_parameters[:qi] if rsa_parameters[:qi] - - rsa_key + def create_rsa_key(rsa_parameters) # rubocop:disable Metrics/AbcSize + OpenSSL::PKey::RSA.new.tap do |rsa_key| + rsa_key.n = rsa_parameters[:n] + rsa_key.e = rsa_parameters[:e] + rsa_key.d = rsa_parameters[:d] if rsa_parameters[:d] + rsa_key.p = rsa_parameters[:p] if rsa_parameters[:p] + rsa_key.q = rsa_parameters[:q] if rsa_parameters[:q] + rsa_key.dmp1 = rsa_parameters[:dp] if rsa_parameters[:dp] + rsa_key.dmq1 = rsa_parameters[:dq] if rsa_parameters[:dq] + rsa_key.iqmp = rsa_parameters[:qi] if rsa_parameters[:qi] + end end end diff --git a/lib/jwt/version.rb b/lib/jwt/version.rb index 360e8d56..222af076 100644 --- a/lib/jwt/version.rb +++ b/lib/jwt/version.rb @@ -20,4 +20,9 @@ module VERSION # Build version string STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end + + def self.openssl_3? + return false if OpenSSL::OPENSSL_VERSION.include?('LibreSSL') + return true if OpenSSL::OPENSSL_VERSION_NUMBER >= 3 * 0x10000000 + end end diff --git a/spec/jwk/decode_with_jwk_spec.rb b/spec/jwk/decode_with_jwk_spec.rb index 0caf3028..fe90a092 100644 --- a/spec/jwk/decode_with_jwk_spec.rb +++ b/spec/jwk/decode_with_jwk_spec.rb @@ -82,8 +82,8 @@ context 'mixing algorithms using kid header' do let(:hmac_jwk) { JWT::JWK.new('secret') } let(:rsa_jwk) { JWT::JWK.new(OpenSSL::PKey::RSA.new(2048)) } - let(:ec_jwk_secp384r1) { JWT::JWK.new(OpenSSL::PKey::EC.new('secp384r1').generate_key) } - let(:ec_jwk_secp521r1) { JWT::JWK.new(OpenSSL::PKey::EC.new('secp521r1').generate_key) } + let(:ec_jwk_secp384r1) { JWT::JWK.new(OpenSSL::PKey::EC.generate('secp384r1')) } + let(:ec_jwk_secp521r1) { JWT::JWK.new(OpenSSL::PKey::EC.generate('secp521r1')) } let(:jwks) { { keys: [hmac_jwk.export(include_private: true), rsa_jwk.export, ec_jwk_secp384r1.export, ec_jwk_secp521r1.export] } } context 'when RSA key is pointed to as HMAC secret' do diff --git a/spec/jwk_spec.rb b/spec/jwk_spec.rb index 5b4fca79..3d3543f0 100644 --- a/spec/jwk_spec.rb +++ b/spec/jwk_spec.rb @@ -2,7 +2,7 @@ RSpec.describe JWT::JWK do let(:rsa_key) { OpenSSL::PKey::RSA.new(2048) } - let(:ec_key) { OpenSSL::PKey::EC.new('secp384r1').generate_key } + let(:ec_key) { OpenSSL::PKey::EC.generate('secp384r1') } describe '.import' do let(:keypair) { rsa_key.public_key }