jwt 2.9.1 → 2.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/README.md +170 -82
  4. data/lib/jwt/base64.rb +3 -0
  5. data/lib/jwt/claims/audience.rb +10 -0
  6. data/lib/jwt/claims/crit.rb +35 -0
  7. data/lib/jwt/claims/decode_verifier.rb +40 -0
  8. data/lib/jwt/claims/expiration.rb +10 -0
  9. data/lib/jwt/claims/issued_at.rb +7 -0
  10. data/lib/jwt/claims/issuer.rb +10 -0
  11. data/lib/jwt/claims/jwt_id.rb +10 -0
  12. data/lib/jwt/claims/not_before.rb +10 -0
  13. data/lib/jwt/claims/numeric.rb +47 -13
  14. data/lib/jwt/claims/required.rb +10 -0
  15. data/lib/jwt/claims/subject.rb +10 -0
  16. data/lib/jwt/claims/verification_methods.rb +20 -0
  17. data/lib/jwt/claims/verifier.rb +61 -0
  18. data/lib/jwt/claims.rb +52 -16
  19. data/lib/jwt/claims_validator.rb +18 -0
  20. data/lib/jwt/configuration/container.rb +20 -0
  21. data/lib/jwt/configuration/decode_configuration.rb +24 -0
  22. data/lib/jwt/configuration/jwk_configuration.rb +1 -0
  23. data/lib/jwt/configuration.rb +8 -0
  24. data/lib/jwt/decode.rb +28 -67
  25. data/lib/jwt/deprecations.rb +1 -0
  26. data/lib/jwt/encode.rb +17 -56
  27. data/lib/jwt/encoded_token.rb +139 -0
  28. data/lib/jwt/error.rb +34 -0
  29. data/lib/jwt/json.rb +1 -1
  30. data/lib/jwt/jwa/compat.rb +32 -0
  31. data/lib/jwt/jwa/ecdsa.rb +7 -6
  32. data/lib/jwt/jwa/eddsa.rb +7 -6
  33. data/lib/jwt/jwa/hmac.rb +6 -3
  34. data/lib/jwt/jwa/hmac_rbnacl.rb +5 -0
  35. data/lib/jwt/jwa/hmac_rbnacl_fixed.rb +5 -0
  36. data/lib/jwt/jwa/none.rb +1 -0
  37. data/lib/jwt/jwa/ps.rb +2 -3
  38. data/lib/jwt/jwa/rsa.rb +2 -3
  39. data/lib/jwt/jwa/signing_algorithm.rb +4 -0
  40. data/lib/jwt/jwa/unsupported.rb +1 -0
  41. data/lib/jwt/jwa/wrapper.rb +1 -0
  42. data/lib/jwt/jwa.rb +17 -4
  43. data/lib/jwt/jwk/ec.rb +2 -3
  44. data/lib/jwt/jwk/hmac.rb +2 -3
  45. data/lib/jwt/jwk/key_base.rb +1 -0
  46. data/lib/jwt/jwk/key_finder.rb +1 -0
  47. data/lib/jwt/jwk/kid_as_key_digest.rb +1 -0
  48. data/lib/jwt/jwk/okp_rbnacl.rb +3 -4
  49. data/lib/jwt/jwk/rsa.rb +2 -3
  50. data/lib/jwt/jwk/set.rb +2 -0
  51. data/lib/jwt/jwk.rb +1 -0
  52. data/lib/jwt/token.rb +112 -0
  53. data/lib/jwt/verify.rb +40 -0
  54. data/lib/jwt/version.rb +30 -9
  55. data/lib/jwt.rb +19 -0
  56. metadata +13 -7
data/lib/jwt/decode.rb CHANGED
@@ -3,68 +3,67 @@
3
3
  require 'json'
4
4
  require 'jwt/x5c_key_finder'
5
5
 
6
- # JWT::Decode module
7
6
  module JWT
8
- # Decoding logic for JWT
7
+ # The Decode class is responsible for decoding and verifying JWT tokens.
9
8
  class Decode
9
+ # Initializes a new Decode instance.
10
+ #
11
+ # @param jwt [String] the JWT to decode.
12
+ # @param key [String, Array<String>] the key(s) to use for verification.
13
+ # @param verify [Boolean] whether to verify the token's signature.
14
+ # @param options [Hash] additional options for decoding and verification.
15
+ # @param keyfinder [Proc] an optional key finder block to dynamically find the key for verification.
16
+ # @raise [JWT::DecodeError] if decoding or verification fails.
10
17
  def initialize(jwt, key, verify, options, &keyfinder)
11
18
  raise JWT::DecodeError, 'Nil JSON web token' unless jwt
12
19
 
13
- @jwt = jwt
20
+ @token = EncodedToken.new(jwt)
14
21
  @key = key
15
22
  @options = options
16
- @segments = jwt.split('.')
17
23
  @verify = verify
18
- @signature = ''
19
24
  @keyfinder = keyfinder
20
25
  end
21
26
 
27
+ # Decodes the JWT token and verifies its segments if verification is enabled.
28
+ #
29
+ # @return [Array<Hash>] an array containing the decoded payload and header.
22
30
  def decode_segments
23
31
  validate_segment_count!
24
32
  if @verify
25
- decode_signature
26
33
  verify_algo
27
34
  set_key
28
35
  verify_signature
29
- verify_claims
36
+ Claims::DecodeVerifier.verify!(token.payload, @options)
30
37
  end
31
- raise JWT::DecodeError, 'Not enough or too many segments' unless header && payload
32
38
 
33
- [payload, header]
39
+ [token.payload, token.header]
34
40
  end
35
41
 
36
42
  private
37
43
 
38
- def verify_signature
39
- return unless @key || @verify
44
+ attr_reader :token
40
45
 
46
+ def verify_signature
41
47
  return if none_algorithm?
42
48
 
43
49
  raise JWT::DecodeError, 'No verification key available' unless @key
44
50
 
45
- return if Array(@key).any? { |key| verify_signature_for?(key) }
46
-
47
- raise JWT::VerificationError, 'Signature verification failed'
51
+ token.verify_signature!(algorithm: allowed_and_valid_algorithms, key: @key)
48
52
  end
49
53
 
50
54
  def verify_algo
51
55
  raise JWT::IncorrectAlgorithm, 'An algorithm must be specified' if allowed_algorithms.empty?
56
+ raise JWT::DecodeError, 'Token header not a JSON object' unless token.header.is_a?(Hash)
52
57
  raise JWT::IncorrectAlgorithm, 'Token is missing alg header' unless alg_in_header
53
58
  raise JWT::IncorrectAlgorithm, 'Expected a different algorithm' if allowed_and_valid_algorithms.empty?
54
59
  end
55
60
 
56
61
  def set_key
57
62
  @key = find_key(&@keyfinder) if @keyfinder
58
- @key = ::JWT::JWK::KeyFinder.new(jwks: @options[:jwks], allow_nil_kid: @options[:allow_nil_kid]).key_for(header['kid']) if @options[:jwks]
63
+ @key = ::JWT::JWK::KeyFinder.new(jwks: @options[:jwks], allow_nil_kid: @options[:allow_nil_kid]).key_for(token.header['kid']) if @options[:jwks]
59
64
  return unless (x5c_options = @options[:x5c])
60
65
 
61
- @key = X5cKeyFinder.new(x5c_options[:root_certificates], x5c_options[:crls]).from(header['x5c'])
62
- end
63
-
64
- def verify_signature_for?(key)
65
- allowed_and_valid_algorithms.any? do |alg|
66
- alg.verify(data: signing_input, signature: @signature, verification_key: key)
67
- end
66
+ @key = X5cKeyFinder.new(x5c_options[:root_certificates], x5c_options[:crls]).from(token.header['x5c'])
68
67
  end
69
68
 
70
69
  def allowed_and_valid_algorithms
@@ -90,70 +89,32 @@ module JWT
90
89
  end
91
90
 
92
91
  def resolve_allowed_algorithms
93
- algs = given_algorithms.map { |alg| JWA.resolve(alg) }
94
-
95
- sort_by_alg_header(algs)
96
- end
97
-
98
- # Move algorithms matching the JWT alg header to the beginning of the list
99
- def sort_by_alg_header(algs)
100
- return algs if algs.size <= 1
101
-
102
- algs.partition { |alg| alg.valid_alg?(alg_in_header) }.flatten
92
+ given_algorithms.map { |alg| JWA.resolve(alg) }
103
93
  end
104
94
 
105
95
  def find_key(&keyfinder)
106
- key = (keyfinder.arity == 2 ? yield(header, payload) : yield(header))
96
+ key = (keyfinder.arity == 2 ? yield(token.header, token.payload) : yield(token.header))
107
97
  # key can be of type [string, nil, OpenSSL::PKey, Array]
108
98
  return key if key && !Array(key).empty?
109
99
 
110
100
  raise JWT::DecodeError, 'No verification key available'
111
101
  end
112
102
 
113
- def verify_claims
114
- Claims.verify!(payload, @options)
115
- end
116
-
117
103
  def validate_segment_count!
118
- return if segment_length == 3
119
- return if !@verify && segment_length == 2 # If no verifying required, the signature is not needed
120
- return if segment_length == 2 && none_algorithm?
104
+ segment_count = token.jwt.count('.') + 1
105
+ return if segment_count == 3
106
+ return if !@verify && segment_count == 2 # If no verifying required, the signature is not needed
107
+ return if segment_count == 2 && none_algorithm?
121
108
 
122
109
  raise JWT::DecodeError, 'Not enough or too many segments'
123
110
  end
124
111
 
125
- def segment_length
126
- @segments.count
127
- end
128
-
129
112
  def none_algorithm?
130
113
  alg_in_header == 'none'
131
114
  end
132
115
 
133
- def decode_signature
134
- @signature = ::JWT::Base64.url_decode(@segments[2] || '')
135
- end
136
-
137
116
  def alg_in_header
138
- header['alg']
139
- end
140
-
141
- def header
142
- @header ||= parse_and_decode @segments[0]
143
- end
144
-
145
- def payload
146
- @payload ||= parse_and_decode @segments[1]
147
- end
148
-
149
- def signing_input
150
- @segments.first(2).join('.')
151
- end
152
-
153
- def parse_and_decode(segment)
154
- JWT::JSON.parse(::JWT::Base64.url_decode(segment))
155
- rescue ::JSON::ParserError
156
- raise JWT::DecodeError, 'Invalid segment encoding'
117
+ token.header['alg']
157
118
  end
158
119
  end
159
120
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  # Deprecations module to handle deprecation warnings in the gem
5
+ # @api private
5
6
  module Deprecations
6
7
  class << self
7
8
  def context
data/lib/jwt/encode.rb CHANGED
@@ -2,68 +2,29 @@
2
2
 
3
3
  require_relative 'jwa'
4
4
 
5
- # JWT::Encode module
6
5
  module JWT
7
- # Encoding logic for JWT
6
+ # The Encode class is responsible for encoding JWT tokens.
8
7
  class Encode
8
+ # Initializes a new Encode instance.
9
+ #
10
+ # @param options [Hash] the options for encoding the JWT token.
11
+ # @option options [Hash] :payload the payload of the JWT token.
12
+ # @option options [Hash] :headers the headers of the JWT token.
13
+ # @option options [String] :key the key used to sign the JWT token.
14
+ # @option options [String] :algorithm the algorithm used to sign the JWT token.
9
15
  def initialize(options)
10
- @payload = options[:payload]
11
- @key = options[:key]
12
- @algorithm = JWA.resolve(options[:algorithm])
13
- @headers = options[:headers].transform_keys(&:to_s)
16
+ @token = Token.new(payload: options[:payload], header: options[:headers])
17
+ @key = options[:key]
18
+ @algorithm = options[:algorithm]
14
19
  end
15
20
 
21
+ # Encodes the JWT token and returns its segments.
22
+ #
23
+ # @return [String] the encoded JWT token.
16
24
  def segments
17
- validate_claims!
18
- combine(encoded_header_and_payload, encoded_signature)
19
- end
20
-
21
- private
22
-
23
- def encoded_header
24
- @encoded_header ||= encode_header
25
- end
26
-
27
- def encoded_payload
28
- @encoded_payload ||= encode_payload
29
- end
30
-
31
- def encoded_signature
32
- @encoded_signature ||= encode_signature
33
- end
34
-
35
- def encoded_header_and_payload
36
- @encoded_header_and_payload ||= combine(encoded_header, encoded_payload)
37
- end
38
-
39
- def encode_header
40
- encode_data(@headers.merge(@algorithm.header(signing_key: @key)))
41
- end
42
-
43
- def encode_payload
44
- encode_data(@payload)
45
- end
46
-
47
- def signature
48
- @algorithm.sign(data: encoded_header_and_payload, signing_key: @key)
49
- end
50
-
51
- def validate_claims!
52
- return unless @payload.is_a?(Hash)
53
-
54
- Claims::Numeric.new(@payload).verify!
55
- end
56
-
57
- def encode_signature
58
- ::JWT::Base64.url_encode(signature)
59
- end
60
-
61
- def encode_data(data)
62
- ::JWT::Base64.url_encode(JWT::JSON.generate(data))
63
- end
64
-
65
- def combine(*parts)
66
- parts.join('.')
25
+ @token.verify_claims!(:numeric)
26
+ @token.sign!(algorithm: @algorithm, key: @key)
27
+ @token.jwt
67
28
  end
68
29
  end
69
30
  end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ # Represents an encoded JWT token
5
+ #
6
+ # Processing an encoded and signed token:
7
+ #
8
+ # token = JWT::Token.new(payload: {pay: 'load'})
9
+ # token.sign!(algorithm: 'HS256', key: 'secret')
10
+ #
11
+ # encoded_token = JWT::EncodedToken.new(token.jwt)
12
+ # encoded_token.verify_signature!(algorithm: 'HS256', key: 'secret')
13
+ # encoded_token.payload # => {'pay' => 'load'}
14
+ class EncodedToken
15
+ include Claims::VerificationMethods
16
+
17
+ # Returns the original token provided to the class.
18
+ # @return [String] The JWT token.
19
+ attr_reader :jwt
20
+
21
+ # Initializes a new EncodedToken instance.
22
+ #
23
+ # @param jwt [String] the encoded JWT token.
24
+ # @raise [ArgumentError] if the provided JWT is not a String.
25
+ def initialize(jwt)
26
+ raise ArgumentError, 'Provided JWT must be a String' unless jwt.is_a?(String)
27
+
28
+ @jwt = jwt
29
+ @encoded_header, @encoded_payload, @encoded_signature = jwt.split('.')
30
+ end
31
+
32
+ # Returns the decoded signature of the JWT token.
33
+ #
34
+ # @return [String] the decoded signature.
35
+ def signature
36
+ @signature ||= ::JWT::Base64.url_decode(encoded_signature || '')
37
+ end
38
+
39
+ # Returns the encoded signature of the JWT token.
40
+ #
41
+ # @return [String] the encoded signature.
42
+ attr_reader :encoded_signature
43
+
44
+ # Returns the decoded header of the JWT token.
45
+ #
46
+ # @return [Hash] the header.
47
+ def header
48
+ @header ||= parse_and_decode(@encoded_header)
49
+ end
50
+
51
+ # Returns the encoded header of the JWT token.
52
+ #
53
+ # @return [String] the encoded header.
54
+ attr_reader :encoded_header
55
+
56
+ # Returns the payload of the JWT token.
57
+ #
58
+ # @return [Hash] the payload.
59
+ def payload
60
+ @payload ||= decode_payload
61
+ end
62
+
63
+ # Sets or returns the encoded payload of the JWT token.
64
+ #
65
+ # @return [String] the encoded payload.
66
+ attr_accessor :encoded_payload
67
+
68
+ # Returns the signing input of the JWT token.
69
+ #
70
+ # @return [String] the signing input.
71
+ def signing_input
72
+ [encoded_header, encoded_payload].join('.')
73
+ end
74
+
75
+ # Verifies the signature of the JWT token.
76
+ #
77
+ # @param algorithm [String, Array<String>, Object, Array<Object>] the algorithm(s) to use for verification.
78
+ # @param key [String, Array<String>] the key(s) to use for verification.
79
+ # @param key_finder [#call] an object responding to `call` to find the key for verification.
80
+ # @return [nil]
81
+ # @raise [JWT::VerificationError] if the signature verification fails.
82
+ # @raise [ArgumentError] if neither key nor key_finder is provided, or if both are provided.
83
+ def verify_signature!(algorithm:, key: nil, key_finder: nil)
84
+ raise ArgumentError, 'Provide either key or key_finder, not both or neither' if key.nil? == key_finder.nil?
85
+
86
+ key ||= key_finder.call(self)
87
+
88
+ return if valid_signature?(algorithm: algorithm, key: key)
89
+
90
+ raise JWT::VerificationError, 'Signature verification failed'
91
+ end
92
+
93
+ # Checks if the signature of the JWT token is valid.
94
+ #
95
+ # @param algorithm [String, Array<String>, Object, Array<Object>] the algorithm(s) to use for verification.
96
+ # @param key [String, Array<String>] the key(s) to use for verification.
97
+ # @return [Boolean] true if the signature is valid, false otherwise.
98
+ def valid_signature?(algorithm:, key:)
99
+ Array(JWA.resolve_and_sort(algorithms: algorithm, preferred_algorithm: header['alg'])).any? do |algo|
100
+ Array(key).any? do |one_key|
101
+ algo.verify(data: signing_input, signature: signature, verification_key: one_key)
102
+ end
103
+ end
104
+ end
105
+
106
+ alias to_s jwt
107
+
108
+ private
109
+
110
+ def decode_payload
111
+ raise JWT::DecodeError, 'Encoded payload is empty' if encoded_payload == ''
112
+
113
+ if unencoded_payload?
114
+ verify_claims!(crit: ['b64'])
115
+ return parse_unencoded(encoded_payload)
116
+ end
117
+
118
+ parse_and_decode(encoded_payload)
119
+ end
120
+
121
+ def unencoded_payload?
122
+ header['b64'] == false
123
+ end
124
+
125
+ def parse_and_decode(segment)
126
+ parse(::JWT::Base64.url_decode(segment || ''))
127
+ end
128
+
129
+ def parse_unencoded(segment)
130
+ parse(segment)
131
+ end
132
+
133
+ def parse(segment)
134
+ JWT::JSON.parse(segment)
135
+ rescue ::JSON::ParserError
136
+ raise JWT::DecodeError, 'Invalid segment encoding'
137
+ end
138
+ end
139
+ end
data/lib/jwt/error.rb CHANGED
@@ -1,23 +1,57 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JWT
4
+ # The EncodeError class is raised when there is an error encoding a JWT.
4
5
  class EncodeError < StandardError; end
6
+
7
+ # The DecodeError class is raised when there is an error decoding a JWT.
5
8
  class DecodeError < StandardError; end
9
+
10
+ # The RequiredDependencyError class is raised when a required dependency is missing.
6
11
  class RequiredDependencyError < StandardError; end
7
12
 
13
+ # The VerificationError class is raised when there is an error verifying a JWT.
8
14
  class VerificationError < DecodeError; end
15
+
16
+ # The ExpiredSignature class is raised when the JWT signature has expired.
9
17
  class ExpiredSignature < DecodeError; end
18
+
19
+ # The IncorrectAlgorithm class is raised when the JWT algorithm is incorrect.
10
20
  class IncorrectAlgorithm < DecodeError; end
21
+
22
+ # The ImmatureSignature class is raised when the JWT signature is immature.
11
23
  class ImmatureSignature < DecodeError; end
24
+
25
+ # The InvalidIssuerError class is raised when the JWT issuer is invalid.
12
26
  class InvalidIssuerError < DecodeError; end
27
+
28
+ # The UnsupportedEcdsaCurve class is raised when the ECDSA curve is unsupported.
13
29
  class UnsupportedEcdsaCurve < IncorrectAlgorithm; end
30
+
31
+ # The InvalidIatError class is raised when the JWT issued at (iat) claim is invalid.
14
32
  class InvalidIatError < DecodeError; end
33
+
34
+ # The InvalidAudError class is raised when the JWT audience (aud) claim is invalid.
15
35
  class InvalidAudError < DecodeError; end
36
+
37
+ # The InvalidSubError class is raised when the JWT subject (sub) claim is invalid.
16
38
  class InvalidSubError < DecodeError; end
39
+
40
+ # The InvalidCritError class is raised when the JWT crit header is invalid.
41
+ class InvalidCritError < DecodeError; end
42
+
43
+ # The InvalidJtiError class is raised when the JWT ID (jti) claim is invalid.
17
44
  class InvalidJtiError < DecodeError; end
45
+
46
+ # The InvalidPayload class is raised when the JWT payload is invalid.
18
47
  class InvalidPayload < DecodeError; end
48
+
49
+ # The MissingRequiredClaim class is raised when a required claim is missing from the JWT.
19
50
  class MissingRequiredClaim < DecodeError; end
51
+
52
+ # The Base64DecodeError class is raised when there is an error decoding a Base64-encoded string.
20
53
  class Base64DecodeError < DecodeError; end
21
54
 
55
+ # The JWKError class is raised when there is an error with the JSON Web Key (JWK).
22
56
  class JWKError < DecodeError; end
23
57
  end
data/lib/jwt/json.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require 'json'
4
4
 
5
5
  module JWT
6
- # JSON wrapper
6
+ # @api private
7
7
  class JSON
8
8
  class << self
9
9
  def generate(data)
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ module JWA
5
+ # Provides backwards compatibility for algorithms
6
+ # @api private
7
+ module Compat
8
+ # @api private
9
+ module ClassMethods
10
+ def from_algorithm(algorithm)
11
+ new(algorithm)
12
+ end
13
+
14
+ def sign(algorithm, msg, key)
15
+ Deprecations.warning('Support for calling sign with positional arguments will be removed in future ruby-jwt versions')
16
+
17
+ from_algorithm(algorithm).sign(data: msg, signing_key: key)
18
+ end
19
+
20
+ def verify(algorithm, key, signing_input, signature)
21
+ Deprecations.warning('Support for calling verify with positional arguments will be removed in future ruby-jwt versions')
22
+
23
+ from_algorithm(algorithm).verify(data: signing_input, signature: signature, verification_key: key)
24
+ end
25
+ end
26
+
27
+ def self.included(klass)
28
+ klass.extend(ClassMethods)
29
+ end
30
+ end
31
+ end
32
+ end
data/lib/jwt/jwa/ecdsa.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # ECDSA signing algorithm
5
6
  class Ecdsa
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
@@ -13,9 +14,7 @@ module JWT
13
14
  def sign(data:, signing_key:)
14
15
  curve_definition = curve_by_name(signing_key.group.curve_name)
15
16
  key_algorithm = curve_definition[:algorithm]
16
- if alg != key_algorithm
17
- raise IncorrectAlgorithm, "payload algorithm is #{alg} but #{key_algorithm} signing key was provided"
18
- end
17
+ raise IncorrectAlgorithm, "payload algorithm is #{alg} but #{key_algorithm} signing key was provided" if alg != key_algorithm
19
18
 
20
19
  asn1_to_raw(signing_key.dsa_sign_asn1(digest.digest(data)), signing_key)
21
20
  end
@@ -23,9 +22,7 @@ module JWT
23
22
  def verify(data:, signature:, verification_key:)
24
23
  curve_definition = curve_by_name(verification_key.group.curve_name)
25
24
  key_algorithm = curve_definition[:algorithm]
26
- if alg != key_algorithm
27
- raise IncorrectAlgorithm, "payload algorithm is #{alg} but #{key_algorithm} verification key was provided"
28
- end
25
+ raise IncorrectAlgorithm, "payload algorithm is #{alg} but #{key_algorithm} verification key was provided" if alg != key_algorithm
29
26
 
30
27
  verification_key.dsa_verify_asn1(digest.digest(data), raw_to_asn1(signature, verification_key))
31
28
  rescue OpenSSL::PKey::PKeyError
@@ -59,6 +56,10 @@ module JWT
59
56
  register_algorithm(new(v[:algorithm], v[:digest]))
60
57
  end
61
58
 
59
+ def self.from_algorithm(algorithm)
60
+ new(algorithm, algorithm.downcase.gsub('es', 'sha'))
61
+ end
62
+
62
63
  def self.curve_by_name(name)
63
64
  NAMED_CURVES.fetch(name) do
64
65
  raise UnsupportedEcdsaCurve, "The ECDSA curve '#{name}' is not supported"
data/lib/jwt/jwa/eddsa.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the EdDSA family of algorithms
5
6
  class Eddsa
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
@@ -10,17 +11,17 @@ module JWT
10
11
  end
11
12
 
12
13
  def sign(data:, signing_key:)
13
- unless signing_key.is_a?(RbNaCl::Signatures::Ed25519::SigningKey)
14
- raise_encode_error!("Key given is a #{signing_key.class} but has to be an RbNaCl::Signatures::Ed25519::SigningKey")
15
- end
14
+ raise_sign_error!("Key given is a #{signing_key.class} but has to be an RbNaCl::Signatures::Ed25519::SigningKey") unless signing_key.is_a?(RbNaCl::Signatures::Ed25519::SigningKey)
15
+
16
+ Deprecations.warning('Using Ed25519 keys is deprecated and will be removed in a future version of ruby-jwt. Please use the ruby-eddsa gem instead.')
16
17
 
17
18
  signing_key.sign(data)
18
19
  end
19
20
 
20
21
  def verify(data:, signature:, verification_key:)
21
- unless verification_key.is_a?(RbNaCl::Signatures::Ed25519::VerifyKey)
22
- raise_decode_error!("key given is a #{verification_key.class} but has to be a RbNaCl::Signatures::Ed25519::VerifyKey")
23
- end
22
+ raise_verify_error!("key given is a #{verification_key.class} but has to be a RbNaCl::Signatures::Ed25519::VerifyKey") unless verification_key.is_a?(RbNaCl::Signatures::Ed25519::VerifyKey)
23
+
24
+ Deprecations.warning('Using Ed25519 keys is deprecated and will be removed in a future version of ruby-jwt. Please use the ruby-eddsa gem instead.')
24
25
 
25
26
  verification_key.verify(signature, data)
26
27
  rescue RbNaCl::CryptoError
data/lib/jwt/jwa/hmac.rb CHANGED
@@ -2,9 +2,14 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the HMAC family of algorithms
5
6
  class Hmac
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
9
+ def self.from_algorithm(algorithm)
10
+ new(algorithm, OpenSSL::Digest.new(algorithm.downcase.gsub('hs', 'sha')))
11
+ end
12
+
8
13
  def initialize(alg, digest)
9
14
  @alg = alg
10
15
  @digest = digest
@@ -16,9 +21,7 @@ module JWT
16
21
 
17
22
  OpenSSL::HMAC.digest(digest.new, signing_key, data)
18
23
  rescue OpenSSL::HMACError => e
19
- if signing_key == '' && e.message == 'EVP_PKEY_new_mac_key: malloc failure'
20
- raise_verify_error!('OpenSSL 3.0 does not support nil or empty hmac_secret')
21
- end
24
+ raise_verify_error!('OpenSSL 3.0 does not support nil or empty hmac_secret') if signing_key == '' && e.message == 'EVP_PKEY_new_mac_key: malloc failure'
22
25
 
23
26
  raise e
24
27
  end
@@ -2,9 +2,14 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the HMAC family of algorithms (using RbNaCl)
5
6
  class HmacRbNaCl
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
9
+ def self.from_algorithm(algorithm)
10
+ new(algorithm, ::RbNaCl::HMAC.const_get(algorithm.upcase.gsub('HS', 'SHA')))
11
+ end
12
+
8
13
  def initialize(alg, hmac)
9
14
  @alg = alg
10
15
  @hmac = hmac
@@ -2,9 +2,14 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the HMAC family of algorithms (using RbNaCl prior to a certain version)
5
6
  class HmacRbNaClFixed
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
9
+ def self.from_algorithm(algorithm)
10
+ new(algorithm, ::RbNaCl::HMAC.const_get(algorithm.upcase.gsub('HS', 'SHA')))
11
+ end
12
+
8
13
  def initialize(alg, hmac)
9
14
  @alg = alg
10
15
  @hmac = hmac
data/lib/jwt/jwa/none.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the none algorithm
5
6
  class None
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
data/lib/jwt/jwa/ps.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the RSASSA-PSS family of algorithms
5
6
  class Ps
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
@@ -11,9 +12,7 @@ module JWT
11
12
  end
12
13
 
13
14
  def sign(data:, signing_key:)
14
- unless signing_key.is_a?(::OpenSSL::PKey::RSA)
15
- raise_sign_error!("The given key is a #{signing_key.class}. It has to be an OpenSSL::PKey::RSA instance.")
16
- end
15
+ raise_sign_error!("The given key is a #{signing_key.class}. It has to be an OpenSSL::PKey::RSA instance.") unless signing_key.is_a?(::OpenSSL::PKey::RSA)
17
16
 
18
17
  signing_key.sign_pss(digest_algorithm, data, salt_length: :digest, mgf1_hash: digest_algorithm)
19
18
  end
data/lib/jwt/jwa/rsa.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Implementation of the RSA family of algorithms
5
6
  class Rsa
6
7
  include JWT::JWA::SigningAlgorithm
7
8
 
@@ -11,9 +12,7 @@ module JWT
11
12
  end
12
13
 
13
14
  def sign(data:, signing_key:)
14
- unless signing_key.is_a?(OpenSSL::PKey::RSA)
15
- raise_sign_error!("The given key is a #{signing_key.class}. It has to be an OpenSSL::PKey::RSA instance")
16
- end
15
+ raise_sign_error!("The given key is a #{signing_key.class}. It has to be an OpenSSL::PKey::RSA instance") unless signing_key.is_a?(OpenSSL::PKey::RSA)
17
16
 
18
17
  signing_key.sign(digest, data)
19
18
  end