-
Notifications
You must be signed in to change notification settings - Fork 376
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
Add RSASSA-PSS signature signing support #285
Conversation
…lude RSASSA-PSS support
…t's own variables.
@@ -20,6 +20,12 @@ def verify_rsa(algorithm, public_key, signing_input, signature) | |||
public_key.verify(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), signature, signing_input) | |||
end | |||
|
|||
def verify_ps(algorithm, public_key, signing_input, signature) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JWT::SecurityUtils#verify_ps has 4 parameters
@@ -0,0 +1,25 @@ | |||
module JWT | |||
module Algos | |||
module Ps |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JWT::Algos::Ps has no descriptive comment
Hi folks, A little context on this. Credit Kudos (the company myself and @oliver-hohn work for) are one of many working in the Open Banking space. This set of specifications is aligned to the OpenID foundation's FAPI standards, which is a structured international means of communicating with a bank. As part of FAPI R&W section
As these are requirements from the standards body and as for various technical reasons many banks are unwilling to adopt Myself and @oliver-hohn recognise the shortcomings of an approach dependent on OpenSSL in this manner. Our aim with raising this PR is to start the conversation and signal our intent to help in this area. If OpenSSL is to be used, we defer to the project maintainers to discuss how best to introduce the |
Thank you for the great contribution. Ruby 2.2 reached end of life this year. (Source) I think it is fine to drop ruby 2.2 support entirely. |
Thanks for your response. We will probably workshop this into a format where the On the ebert issues - Documenting the classes is something we can certainly introduce but the method signature issues seem to come from existing design patterns in the |
@tobypinder That sounds great. An optional dependency would be the best way to tackle the openssl version issue. Currently we have an optional dependency on EDDSA algos. You need the Please ignore the ebert issues I'm currently (re)tuning the linter settings. |
lib/jwt/error.rb
Outdated
DecodeError = Class.new(StandardError) | ||
EncodeError = Class.new(StandardError) | ||
DecodeError = Class.new(StandardError) | ||
RequiredGemError = Class.new(StandardError) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JWT::RequiredGemError has no descriptive comment
lib/jwt/error.rb
Outdated
@@ -1,8 +1,9 @@ | |||
# frozen_string_literal: true | |||
|
|||
module JWT | |||
EncodeError = Class.new(StandardError) | |||
DecodeError = Class.new(StandardError) | |||
EncodeError = Class.new(StandardError) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JWT::EncodeError has no descriptive comment
lib/jwt/error.rb
Outdated
EncodeError = Class.new(StandardError) | ||
DecodeError = Class.new(StandardError) | ||
EncodeError = Class.new(StandardError) | ||
DecodeError = Class.new(StandardError) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JWT::DecodeError has no descriptive comment
|
||
SUPPORTED = %w[PS256 PS384 PS512].freeze | ||
|
||
def sign(to_sign) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JWT::Algos::Ps#sign has approx 6 statements
lib/jwt/algos/ps.rb
Outdated
end | ||
|
||
def require_openssl! | ||
unless Gem.loaded_specs['openssl'] && Gem.loaded_specs['openssl'].version.release >= Gem::Version.new('2.1') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JWT::Algos::Ps#require_openssl! calls 'Gem.loaded_specs['openssl']' 2 times
lib/jwt/algos/ps.rb
Outdated
end | ||
|
||
def require_openssl! | ||
unless Gem.loaded_specs['openssl'] && Gem.loaded_specs['openssl'].version.release >= Gem::Version.new('2.1') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JWT::Algos::Ps#require_openssl! calls 'Gem.loaded_specs' 2 times
Ebert has finished reviewing this Pull Request and has found:
You can see more details about this review at https://ebertapp.io/github/jwt/ruby-jwt/pulls/285. |
@excpt, I've just pushed a few code style changes and made It seems that Ebert is still not happy with the code style changes. As you mentioned that you are revising the linter settings, could you mark which code style changes you want to be made and which can be omitted, so that I can make the corrections in the PR? For the EDDSA algos, we were thinking of making similar changes to it's dependency management in a separate PR. |
I'd like to add a couple of cents here on behalf of those of us who use this library in Ruby environments that do not support Gems. I am one - I use this library specifically (as opposed to https://github.com/nov/json-jwt) in a hybrid mobile application built with the Rhodes framework. Rhodes has an embedded Ruby 2.4.1, and allows mobile development to be done in Ruby. In this environment, it is possible to use many pure-Ruby Gems, so long as they are compatible with the environment. One simply extracts the /lib directory, which is then placed under an "extensions" directory in the project. It's even possible to adapt Gems that have some native C code, with a little bit of work writing a build file. This library is especially easy to use in the Rhodes environment, because (currently) it is both pure Ruby, and has no external dependencies. (So, I don't have to check every one of a laundry list of dependencies for compatibility.) FWIW, we do have OpenSSL (have to check version) in this environment. What we don't have is support for Gems, as it would make no sense in this environment. (To satisfy Apple requirements on interpretive languages, the ruby code is compiled to MRI bytecode at build time). Loading Gems in this environment is a nonsensical thing. So, I can load OpenSSL. I don't have Gem, and OpenSSL isn't loaded as a Gem. I'd like to ask that some consideration be made toward this usage. Maybe it is no more than providing some documentation on how to stub-off the calls to Gem.whatever, or perhaps providing the stubs. It would be a shame for a library that is currently so robustly stand-alone to now start acquiring Gem baggage. FWIW, in my server environment, I do use the "other" library I mentioned above, because it's already a requirement for the openid-connect Gem I use there. I use THIS library in the mobile client environment specifically because of it's simple purity which makes it easy to use in that environment. P.S. I think that rather than directly stubbing out any calls on the Gem module, it would be better to abstract it. I'd rather be overriding some methods in this library, than providing a "fake" Gem module. |
@jtara Am I correct in understanding that the issue is with the usage of the Another solution for this, so as to not rely on the # in algos/ps.rb
def require_openssl!
require 'openssl'
rescue LoadError
raise JWT::RequiredGemError, 'OpenSSL +2.1 is required to support RSASSA-PSS algorithms'
end And then similarly in the # in algos/ps.rb
def sign(to_sign)
...
begin
key.sign_pss(translated_algorithm, msg, salt_length: :max, mgf1_hash: translated_algorithm)
rescue NoMethodError
raise JWT::RequiredGemError, 'OpenSSL +2.1 is required to support RSASSA-PSS algorithms'
end
end # in security_utils.rb
def verify_ps(algorithm, public_key, signing_input, signature)
...
begin
public_key.verify_pss(formatted_algorithm, signature, signing_input, salt_length: :auto, mgf1_hash: formatted_algorithm)
rescue NoMethodError
raise JWT::RequiredGemError, 'OpenSSL +2.1 is required to support RSASSA-PSS algorithms'
end
end Thoughts on this approach? |
@oliver-hohn rescue NoMethodError looks like a good approach to me, as it keep the library dependency-free (with OPTIONAL OpenSSL dependency) and no rubygems dependency. FYI, Ruby in Rhodes is a specialized environment, and omits RubyGems. It also omits (most uses of) eval(), and the ability to load This is partly for efficiently, but more importantly to satisfy Apple requirements for apps in the App Store that use interpretive languages (other than Javascript running in either UIWebView or WKWebView. It is not allowed to use an interpretive language implement that permits source code to be loaded in the execution environment. So, the mobile app includes a modified build of Ruby MRI that is tailored to the requirements of the execution environment. It is similar to how precompiling ruby works on Heroku presented here: http://www.atdot.net/~ko1/activities/2016_railsconf_pub.pdf with the additional caveat that it is not possible to compile code in the execution environment. What Heroku does during "boot" time is done instead at "build" time. Rhodes is not a well-publicized mobile platform, but is very much quietly in use by a number of large enterprises. http://tau-technologies.com/products/rhomobile/ I am not a user of RubyMotion, but it works similarly, and for the same reasons. There are probably additional Ruby environments that do not permit compilation in the execution environment. I think it is valuable to maintain the ability to use ruby-jwt in these and similar environments (without having to fork a small change), and only takes the small difference in approach that you have proposed above. |
@jtara the feedback and explanations of these use cases is really helpful, we're keen to introduce this in a way that works for everyone. |
…ire OpenSSL +2.1. Replaces RequiredGemError with RequiredDependencyError
end | ||
|
||
def require_openssl! | ||
if Object.const_defined?('OpenSSL') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jtara Thoughts on this approach of using Object#const_defined?
over catching NoMethodError
s?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this belt-and-suspenders approach even better.
- It uses a check for constant def rather than using a Gem function
- It's ALSO easy to monkey-patch for those who have some other special requirement. While in MY use case, OpenSSL would have already been loaded, perhaps others need to load dynamically, so they can monkey-patch.
I will ask the Rhodes maintainers to comment as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I see you already had the belt-and-suspenders (def require_openssl! method) in the previous proposed solution as well.
I've asked the Rhodes developers to comment on the two two proposals.
Thanks for your willingness to keep the library as pure as possible to make it easily usable in strange execution environments!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have this preliminary feedback from the Rhodes team:
Tau Technologies Inc. Wednesday at 16:20
Jon,Team is investigating what preference is more suitable for Rhodes.
We'll post an update to ruby-jwt github issue thread as we get results.Regards,
Tau Technologies Team.
Tau Technologies Inc. Thursday at 16:54
Jon,We assume the both methods are well.
What about another possible approach on the application level: to create stub Gem object with stub method loaded_specs?
Regards,
Tau Technologies Team.
Thanks for taking this into consideration. Of course, they are right, Gem object could be stubbed in application. But it invites further creeping of dependencies. Since the library is currently dependency-free, it's a worthy goal, I think, to keep it that way, i think we are agreed.
I think we are good with whatever method you deem best, so please don't hold anything up on account of this.
@excpt Since there has been inactivity in the past days on this PR, can it be reviewed for merging? If the Rhodes maintainers require changes to be made, I suggest they are introduced in a separate PR. |
@oliver-hohn I start reviewing the code and merge the PR when I am done. @oliver-hohn, @tobypinder, @jtara |
@excpt Is there any plans for a release in the near future? We are having to fork until the next release for our purposes. |
Release is in the works. Will happen on the weekend.
…On Wed 13. Feb 2019 at 12:18, Oliver Höhn ***@***.***> wrote:
@excpt <https://github.com/excpt> Is there any plans for a release in the
near future? We are having to fork until the next release for our purposes.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#285 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAOBmrtMNaQAw40B5tVUCKWtiypqRxQjks5vM_SKgaJpZM4WhmmE>
.
|
Changes
PS256
,PS384
, andPS512
signing algorithms. Note As can be seen from the changes in thegemspec
, a requirement forOpenSSL
+2.1
is made, as older versions do not include the native support for RSASSA-PSS. We understand that there can be pushback on this requirement, and are thus open to ways of making the dependency optional or removing it and leaving it up to the client of the gem to handle this dependecy.README
with examples ofPS*
signing.PS*
signing of JWTs.