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

Support exporting RSA private keys #373

Closed
wants to merge 1 commit into from

Conversation

anakinj
Copy link
Member

@anakinj anakinj commented Sep 25, 2020

@phlegx @richardlarocque Got inspired by your work so made this thing that would allow the inclusion of the private key in the JWK.

end

key
end
def rsa_pkey(jwk_n, jwk_e, jwk_d, jwk_p, jwk_q, jwk_dp, jwk_dq, jwk_qi)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perceived complexity for rsa_pkey is too high. [16/7]

end

key
end
def rsa_pkey(jwk_n, jwk_e, jwk_d, jwk_p, jwk_q, jwk_dp, jwk_dq, jwk_qi)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid parameter lists longer than 5 parameters. [8/5]

end

key
end
def rsa_pkey(jwk_n, jwk_e, jwk_d, jwk_p, jwk_q, jwk_dp, jwk_dq, jwk_qi)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method has too many lines. [17/15]

You might want to extract some of this method lines into new methods inside its current class or isolate it on a class of its own and make it a collaborator instead.

@@ -28,45 +28,68 @@ def kid
OpenSSL::Digest::SHA256.hexdigest(sequence.to_der)
end

def export
{
def export(options = {})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assignment Branch Condition size for export is too high. [28.04/20]

end

key
end
def rsa_pkey(jwk_n, jwk_e, jwk_d, jwk_p, jwk_q, jwk_dp, jwk_dq, jwk_qi)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cyclomatic complexity for rsa_pkey is too high. [15/6]

end

key
end
def rsa_pkey(jwk_n, jwk_e, jwk_d, jwk_p, jwk_q, jwk_dp, jwk_dq, jwk_qi)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JWT::JWK::RSA#rsa_pkey has approx 14 statements

Read more about it here.

def self.decode_open_ssl_bn(jwk_data)
OpenSSL::BN.new(::Base64.urlsafe_decode64(jwk_data), BINARY)
def decode_open_ssl_bn(jwk_data)
return nil if jwk_data.nil?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JWT::JWK::RSA#decode_open_ssl_bn performs a nil-check

Read more about it here.


key = OpenSSL::PKey::RSA.new

if key.respond_to?(:set_key)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JWT::JWK::RSA#rsa_pkey manually dispatches method call

@sourcelevel-bot
Copy link

SourceLevel has finished reviewing this Pull Request and has found:

  • 7 possible new issues (including those that may have been commented here).

See more details about this review.

@anakinj
Copy link
Member Author

anakinj commented Sep 25, 2020

Will look at those robot comments later. The amount of parameters is a little problematic for these complexity metrics

Copy link
Contributor

@phlegx phlegx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I also apply this changes (option include_private) to HMAC JWK?

kty: KTY,
n: encode_open_ssl_bn(public_key.n),
e: encode_open_ssl_bn(public_key.e),
kid: kid
}

return ret if options[:include_private] != true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also check if the keypair has a private key.

return ret unless private? && options[:include_private] == true

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Will get back to this when I have the time.

@anakinj
Copy link
Member Author

anakinj commented Sep 25, 2020

Should I also apply this changes (option include_private) to HMAC JWK?

If we can agree on the public export method API to be like this it could be already implemented for the new JWKs.

I went with the options hash to be able to maybe add/override something on the export easier in the future, dunno if that was necessary.

@phlegx
Copy link
Contributor

phlegx commented Sep 25, 2020

Options with a hash for export is the right way! It is better to handle and change. Method export(options = {}) remains intact in the code for all developers when new options come in the future. I agree.

dp: encode_open_ssl_bn(keypair.dmp1),
dq: encode_open_ssl_bn(keypair.dmq1),
qi: encode_open_ssl_bn(keypair.iqmp)
)
end

def encode_open_ssl_bn(key_part)
Copy link
Contributor

@phlegx phlegx Sep 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this method private. Also method kid. So, we can expose the same set of methods in all other JWKs.

@phlegx
Copy link
Contributor

phlegx commented Sep 25, 2020

I propose to expose only a defined set of methods for all JWKs. All other methods should be private. An abstract class could help.

module JWT
  module JWK
    class [NAME]
      attr_reader :keypair
      attr_reader :kid

      def initialize(keypair, kid = nil)
        # ...
      end

      def private?
        # ...
      end

      def public_key
        # ...
      end

      def export(options = {})
        # ...
      end

      class << self
        def import(jwk_data)
        end
      end
    end
  end
end

@phlegx
Copy link
Contributor

phlegx commented Sep 25, 2020

@anakinj and @richardlarocque please review my code on PR #372. I have added a factory class that can be used by RSA and EC JWKs.

Copy link
Contributor

@richardlarocque richardlarocque left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me.

I don't pretend to understand the OpenSSL calls, but they seem fine.

I think there's an API question about what you want to do if someone passes export_private on a public key JWK. You can raise an error or silently return the public key. My preference is to raise an error, but you can argue it either way.

@@ -34,7 +34,7 @@
it 'returns a hash with the public parts of the key' do
expect(subject).to be_a Hash
expect(subject).to include(:kty, :n, :e, :kid)
expect(subject).not_to include(:d)
expect(subject).not_to include(:d, :p, :dp, :dq,:qi)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: whitespace between :dq and :qi.

@@ -43,7 +43,7 @@
it 'returns a hash with the public parts of the key' do
expect(subject).to be_a Hash
expect(subject).to include(:kty, :n, :e, :kid)
expect(subject).not_to include(:d)
expect(subject).not_to include(:d, :p, :dp, :dq,:qi)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: whitespace again.

let(:keypair) { rsa_key }
it 'returns a hash with the public AND private parts of the key' do
expect(subject).to be_a Hash
expect(subject).to include(:kty, :n, :e, :kid, :d, :p, :q, :dp, :dq,:qi)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: also whitespace.

@anakinj
Copy link
Member Author

anakinj commented Sep 28, 2020

Thanks for the comments @richardlarocque. I hope to get back to this in the end of this week.

@phlegx
Copy link
Contributor

phlegx commented Sep 28, 2020

@anakinj @richardlarocque @excpt I suggest to first merge PR #372 that includes the abstract class. Then JWK RSA and EC can merge and adapt own PR to the abstract structure.

@excpt
Copy link
Member

excpt commented Sep 28, 2020

#372 merged.

@anakinj I'd recommend a rebase for this pr.

@anakinj
Copy link
Member Author

anakinj commented Oct 1, 2020

Replaced by #375

@anakinj anakinj closed this Oct 1, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants