-
Notifications
You must be signed in to change notification settings - Fork 374
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
Changes from all commits
da2ac2d
598be5c
fa92222
0979f73
5d841fa
c14d70b
1d16558
df315b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
module JWT | ||
module Algos | ||
module Ps | ||
# RSASSA-PSS signing algorithms | ||
|
||
module_function | ||
|
||
SUPPORTED = %w[PS256 PS384 PS512].freeze | ||
|
||
def sign(to_sign) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. JWT::Algos::Ps#sign has approx 6 statements |
||
require_openssl! | ||
|
||
algorithm, msg, key = to_sign.values | ||
|
||
key_class = key.class | ||
|
||
raise EncodeError, "The given key is a #{key_class}. It has to be an OpenSSL::PKey::RSA instance." if key_class == String | ||
|
||
translated_algorithm = algorithm.sub('PS', 'sha') | ||
|
||
key.sign_pss(translated_algorithm, msg, salt_length: :max, mgf1_hash: translated_algorithm) | ||
end | ||
|
||
def verify(to_verify) | ||
require_openssl! | ||
|
||
SecurityUtils.verify_ps(to_verify.algorithm, to_verify.public_key, to_verify.signing_input, to_verify.signature) | ||
end | ||
|
||
def require_openssl! | ||
if Object.const_defined?('OpenSSL') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jtara Thoughts on this approach of using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like this belt-and-suspenders approach even better.
I will ask the Rhodes maintainers to comment as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. I have this preliminary feedback from the Rhodes 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. |
||
major, minor = OpenSSL::VERSION.split('.').first(2) | ||
|
||
unless major.to_i >= 2 && minor.to_i >= 1 | ||
raise JWT::RequiredDependencyError, "You currently have OpenSSL #{OpenSSL::VERSION}. PS support requires >= 2.1" | ||
end | ||
else | ||
raise JWT::RequiredDependencyError, 'PS signing requires OpenSSL +2.1' | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 commentThe reason will be displayed to describe this comment to others. Learn more. JWT::SecurityUtils#verify_ps has 4 parameters |
||
formatted_algorithm = algorithm.sub('PS', 'sha') | ||
|
||
public_key.verify_pss(formatted_algorithm, signature, signing_input, salt_length: :auto, mgf1_hash: formatted_algorithm) | ||
end | ||
|
||
def asn1_to_raw(signature, public_key) | ||
byte_size = (public_key.group.degree + 7) / 8 | ||
OpenSSL::ASN1.decode(signature).value.map { |value| value.value.to_s(2).rjust(byte_size, "\x00") }.join | ||
|
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
Read more about it here.