jwt 2.7.1 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +84 -27
  3. data/README.md +37 -19
  4. data/lib/jwt/base64.rb +16 -2
  5. data/lib/jwt/claims/audience.rb +20 -0
  6. data/lib/jwt/claims/expiration.rb +22 -0
  7. data/lib/jwt/claims/issued_at.rb +15 -0
  8. data/lib/jwt/claims/issuer.rb +24 -0
  9. data/lib/jwt/claims/jwt_id.rb +25 -0
  10. data/lib/jwt/claims/not_before.rb +22 -0
  11. data/lib/jwt/claims/numeric.rb +43 -0
  12. data/lib/jwt/claims/required.rb +23 -0
  13. data/lib/jwt/claims/subject.rb +20 -0
  14. data/lib/jwt/claims.rb +38 -0
  15. data/lib/jwt/configuration/container.rb +14 -3
  16. data/lib/jwt/configuration/jwk_configuration.rb +1 -1
  17. data/lib/jwt/decode.rb +12 -21
  18. data/lib/jwt/deprecations.rb +48 -0
  19. data/lib/jwt/encode.rb +4 -14
  20. data/lib/jwt/error.rb +1 -0
  21. data/lib/jwt/{algos → jwa}/ecdsa.rb +39 -26
  22. data/lib/jwt/jwa/eddsa.rb +34 -0
  23. data/lib/jwt/{algos → jwa}/hmac.rb +25 -19
  24. data/lib/jwt/jwa/hmac_rbnacl.rb +45 -0
  25. data/lib/jwt/jwa/hmac_rbnacl_fixed.rb +42 -0
  26. data/lib/jwt/jwa/none.rb +23 -0
  27. data/lib/jwt/jwa/ps.rb +36 -0
  28. data/lib/jwt/jwa/rsa.rb +36 -0
  29. data/lib/jwt/jwa/signing_algorithm.rb +59 -0
  30. data/lib/jwt/jwa/unsupported.rb +19 -0
  31. data/lib/jwt/jwa/wrapper.rb +43 -0
  32. data/lib/jwt/jwa.rb +45 -0
  33. data/lib/jwt/jwk/ec.rb +42 -27
  34. data/lib/jwt/jwk/key_base.rb +3 -1
  35. data/lib/jwt/jwk/key_finder.rb +4 -4
  36. data/lib/jwt/jwk/set.rb +1 -1
  37. data/lib/jwt/jwk.rb +1 -1
  38. data/lib/jwt/version.rb +4 -3
  39. data/lib/jwt/x5c_key_finder.rb +2 -5
  40. data/lib/jwt.rb +5 -1
  41. data/ruby-jwt.gemspec +3 -0
  42. metadata +58 -20
  43. data/lib/jwt/algos/algo_wrapper.rb +0 -26
  44. data/lib/jwt/algos/eddsa.rb +0 -33
  45. data/lib/jwt/algos/hmac_rbnacl.rb +0 -53
  46. data/lib/jwt/algos/hmac_rbnacl_fixed.rb +0 -52
  47. data/lib/jwt/algos/none.rb +0 -19
  48. data/lib/jwt/algos/ps.rb +0 -41
  49. data/lib/jwt/algos/rsa.rb +0 -23
  50. data/lib/jwt/algos/unsupported.rb +0 -19
  51. data/lib/jwt/algos.rb +0 -66
  52. data/lib/jwt/claims_validator.rb +0 -37
  53. data/lib/jwt/verify.rb +0 -113
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ module JWA
5
+ class Wrapper
6
+ include SigningAlgorithm
7
+
8
+ def initialize(algorithm)
9
+ @algorithm = algorithm
10
+ end
11
+
12
+ def alg
13
+ return @algorithm.alg if @algorithm.respond_to?(:alg)
14
+
15
+ super
16
+ end
17
+
18
+ def valid_alg?(alg_to_check)
19
+ return @algorithm.valid_alg?(alg_to_check) if @algorithm.respond_to?(:valid_alg?)
20
+
21
+ super
22
+ end
23
+
24
+ def header(*args, **kwargs)
25
+ return @algorithm.header(*args, **kwargs) if @algorithm.respond_to?(:header)
26
+
27
+ super
28
+ end
29
+
30
+ def sign(*args, **kwargs)
31
+ return @algorithm.sign(*args, **kwargs) if @algorithm.respond_to?(:sign)
32
+
33
+ super
34
+ end
35
+
36
+ def verify(*args, **kwargs)
37
+ return @algorithm.verify(*args, **kwargs) if @algorithm.respond_to?(:verify)
38
+
39
+ super
40
+ end
41
+ end
42
+ end
43
+ end
data/lib/jwt/jwa.rb ADDED
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
4
+
5
+ begin
6
+ require 'rbnacl'
7
+ rescue LoadError
8
+ raise if defined?(RbNaCl)
9
+ end
10
+
11
+ require_relative 'jwa/signing_algorithm'
12
+ require_relative 'jwa/ecdsa'
13
+ require_relative 'jwa/hmac'
14
+ require_relative 'jwa/none'
15
+ require_relative 'jwa/ps'
16
+ require_relative 'jwa/rsa'
17
+ require_relative 'jwa/unsupported'
18
+ require_relative 'jwa/wrapper'
19
+
20
+ if JWT.rbnacl?
21
+ require_relative 'jwa/eddsa'
22
+ end
23
+
24
+ if JWT.rbnacl_6_or_greater?
25
+ require_relative 'jwa/hmac_rbnacl'
26
+ elsif JWT.rbnacl?
27
+ require_relative 'jwa/hmac_rbnacl_fixed'
28
+ end
29
+
30
+ module JWT
31
+ module JWA
32
+ class << self
33
+ def resolve(algorithm)
34
+ return find(algorithm) if algorithm.is_a?(String) || algorithm.is_a?(Symbol)
35
+
36
+ unless algorithm.is_a?(SigningAlgorithm)
37
+ Deprecations.warning('Custom algorithms are required to include JWT::JWA::SigningAlgorithm')
38
+ return Wrapper.new(algorithm)
39
+ end
40
+
41
+ algorithm
42
+ end
43
+ end
44
+ end
45
+ end
data/lib/jwt/jwk/ec.rb CHANGED
@@ -11,6 +11,7 @@ module JWT
11
11
  EC_PUBLIC_KEY_ELEMENTS = %i[kty crv x y].freeze
12
12
  EC_PRIVATE_KEY_ELEMENTS = %i[d].freeze
13
13
  EC_KEY_ELEMENTS = (EC_PRIVATE_KEY_ELEMENTS + EC_PUBLIC_KEY_ELEMENTS).freeze
14
+ ZERO_BYTE = "\0".b.freeze
14
15
 
15
16
  def initialize(key, params = nil, options = {})
16
17
  params ||= {}
@@ -143,7 +144,6 @@ module JWT
143
144
  if ::JWT.openssl_3?
144
145
  def create_ec_key(jwk_crv, jwk_x, jwk_y, jwk_d) # rubocop:disable Metrics/MethodLength
145
146
  curve = EC.to_openssl_curve(jwk_crv)
146
-
147
147
  x_octets = decode_octets(jwk_x)
148
148
  y_octets = decode_octets(jwk_y)
149
149
 
@@ -153,26 +153,26 @@ module JWT
153
153
  )
154
154
 
155
155
  sequence = if jwk_d
156
- # https://datatracker.ietf.org/doc/html/rfc5915.html
157
- # ECPrivateKey ::= SEQUENCE {
158
- # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
159
- # privateKey OCTET STRING,
160
- # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
161
- # publicKey [1] BIT STRING OPTIONAL
162
- # }
163
-
164
- OpenSSL::ASN1::Sequence([
165
- OpenSSL::ASN1::Integer(1),
166
- OpenSSL::ASN1::OctetString(OpenSSL::BN.new(decode_octets(jwk_d), 2).to_s(2)),
167
- OpenSSL::ASN1::ObjectId(curve, 0, :EXPLICIT),
168
- OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed), 1, :EXPLICIT)
169
- ])
170
- else
171
- OpenSSL::ASN1::Sequence([
172
- OpenSSL::ASN1::Sequence([OpenSSL::ASN1::ObjectId('id-ecPublicKey'), OpenSSL::ASN1::ObjectId(curve)]),
173
- OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed))
174
- ])
175
- end
156
+ # https://datatracker.ietf.org/doc/html/rfc5915.html
157
+ # ECPrivateKey ::= SEQUENCE {
158
+ # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
159
+ # privateKey OCTET STRING,
160
+ # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
161
+ # publicKey [1] BIT STRING OPTIONAL
162
+ # }
163
+
164
+ OpenSSL::ASN1::Sequence([
165
+ OpenSSL::ASN1::Integer(1),
166
+ OpenSSL::ASN1::OctetString(OpenSSL::BN.new(decode_octets(jwk_d), 2).to_s(2)),
167
+ OpenSSL::ASN1::ObjectId(curve, 0, :EXPLICIT),
168
+ OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed), 1, :EXPLICIT)
169
+ ])
170
+ else
171
+ OpenSSL::ASN1::Sequence([
172
+ OpenSSL::ASN1::Sequence([OpenSSL::ASN1::ObjectId('id-ecPublicKey'), OpenSSL::ASN1::ObjectId(curve)]),
173
+ OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed))
174
+ ])
175
+ end
176
176
 
177
177
  OpenSSL::PKey::EC.new(sequence.to_der)
178
178
  end
@@ -205,12 +205,27 @@ module JWT
205
205
  end
206
206
  end
207
207
 
208
- def decode_octets(jwk_data)
209
- ::JWT::Base64.url_decode(jwk_data)
210
- end
211
-
212
- def decode_open_ssl_bn(jwk_data)
213
- OpenSSL::BN.new(::JWT::Base64.url_decode(jwk_data), BINARY)
208
+ def decode_octets(base64_encoded_coordinate)
209
+ bytes = ::JWT::Base64.url_decode(base64_encoded_coordinate)
210
+ # Some base64 encoders on some platform omit a single 0-byte at
211
+ # the start of either Y or X coordinate of the elliptic curve point.
212
+ # This leads to an encoding error when data is passed to OpenSSL BN.
213
+ # It is know to have happend to exported JWKs on a Java application and
214
+ # on a Flutter/Dart application (both iOS and Android). All that is
215
+ # needed to fix the problem is adding a leading 0-byte. We know the
216
+ # required byte is 0 because with any other byte the point is no longer
217
+ # on the curve - and OpenSSL will actually communicate this via another
218
+ # exception. The indication of a stripped byte will be the fact that the
219
+ # coordinates - once decoded into bytes - should always be an even
220
+ # bytesize. For example, with a P-521 curve, both x and y must be 66 bytes.
221
+ # With a P-256 curve, both x and y must be 32 and so on. The simplest way
222
+ # to check for this truncation is thus to check whether the number of bytes
223
+ # is odd, and restore the leading 0-byte if it is.
224
+ if bytes.bytesize.odd?
225
+ ZERO_BYTE + bytes
226
+ else
227
+ bytes
228
+ end
214
229
  end
215
230
 
216
231
  class << self
@@ -38,12 +38,14 @@ module JWT
38
38
  end
39
39
 
40
40
  def ==(other)
41
- self[:kid] == other[:kid]
41
+ other.is_a?(::JWT::JWK::KeyBase) && self[:kid] == other[:kid]
42
42
  end
43
43
 
44
44
  alias eql? ==
45
45
 
46
46
  def <=>(other)
47
+ return nil unless other.is_a?(::JWT::JWK::KeyBase)
48
+
47
49
  self[:kid] <=> other[:kid]
48
50
  end
49
51
 
@@ -8,10 +8,10 @@ module JWT
8
8
  jwks_or_loader = options[:jwks]
9
9
 
10
10
  @jwks_loader = if jwks_or_loader.respond_to?(:call)
11
- jwks_or_loader
12
- else
13
- ->(_options) { jwks_or_loader }
14
- end
11
+ jwks_or_loader
12
+ else
13
+ ->(_options) { jwks_or_loader }
14
+ end
15
15
  end
16
16
 
17
17
  def key_for(kid)
data/lib/jwt/jwk/set.rb CHANGED
@@ -25,7 +25,7 @@ module JWT
25
25
  jwks.map { |k| JWT::JWK.new(k, nil, options) }
26
26
  else
27
27
  raise ArgumentError, 'Can only create new JWKS from Hash, Array and JWK'
28
- end
28
+ end
29
29
  end
30
30
 
31
31
  def export(options = {})
data/lib/jwt/jwk.rb CHANGED
@@ -52,4 +52,4 @@ require_relative 'jwk/key_base'
52
52
  require_relative 'jwk/ec'
53
53
  require_relative 'jwk/rsa'
54
54
  require_relative 'jwk/hmac'
55
- require_relative 'jwk/okp_rbnacl' if ::JWT.rbnacl?
55
+ require_relative 'jwk/okp_rbnacl' if JWT.rbnacl?
data/lib/jwt/version.rb CHANGED
@@ -11,9 +11,9 @@ module JWT
11
11
  # major version
12
12
  MAJOR = 2
13
13
  # minor version
14
- MINOR = 7
14
+ MINOR = 9
15
15
  # tiny version
16
- TINY = 1
16
+ TINY = 0
17
17
  # alpha, beta, etc. tag
18
18
  PRE = nil
19
19
 
@@ -23,7 +23,8 @@ module JWT
23
23
 
24
24
  def self.openssl_3?
25
25
  return false if OpenSSL::OPENSSL_VERSION.include?('LibreSSL')
26
- return true if OpenSSL::OPENSSL_VERSION_NUMBER >= 3 * 0x10000000
26
+
27
+ true if 3 * 0x10000000 <= OpenSSL::OPENSSL_VERSION_NUMBER
27
28
  end
28
29
 
29
30
  def self.rbnacl?
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'base64'
4
- require 'jwt/error'
5
-
6
3
  module JWT
7
4
  # If the x5c header certificate chain can be validated by trusted root
8
5
  # certificates, and none of the certificates are revoked, returns the public
@@ -10,7 +7,7 @@ module JWT
10
7
  # See https://tools.ietf.org/html/rfc7515#section-4.1.6
11
8
  class X5cKeyFinder
12
9
  def initialize(root_certificates, crls = nil)
13
- raise(ArgumentError, 'Root certificates must be specified') unless root_certificates
10
+ raise ArgumentError, 'Root certificates must be specified' unless root_certificates
14
11
 
15
12
  @store = build_store(root_certificates, crls)
16
13
  end
@@ -27,7 +24,7 @@ module JWT
27
24
  error = "#{error} Certificate subject: #{current_cert.subject}."
28
25
  end
29
26
 
30
- raise(JWT::VerificationError, error)
27
+ raise JWT::VerificationError, error
31
28
  end
32
29
  end
33
30
 
data/lib/jwt.rb CHANGED
@@ -5,9 +5,11 @@ require 'jwt/base64'
5
5
  require 'jwt/json'
6
6
  require 'jwt/decode'
7
7
  require 'jwt/configuration'
8
+ require 'jwt/deprecations'
8
9
  require 'jwt/encode'
9
10
  require 'jwt/error'
10
11
  require 'jwt/jwk'
12
+ require 'jwt/claims'
11
13
 
12
14
  # JSON Web Token implementation
13
15
  #
@@ -26,6 +28,8 @@ module JWT
26
28
  end
27
29
 
28
30
  def decode(jwt, key = nil, verify = true, options = {}, &keyfinder) # rubocop:disable Style/OptionalBooleanParameter
29
- Decode.new(jwt, key, verify, configuration.decode.to_h.merge(options), &keyfinder).decode_segments
31
+ Deprecations.context do
32
+ Decode.new(jwt, key, verify, configuration.decode.to_h.merge(options), &keyfinder).decode_segments
33
+ end
30
34
  end
31
35
  end
data/ruby-jwt.gemspec CHANGED
@@ -31,9 +31,12 @@ Gem::Specification.new do |spec|
31
31
  spec.executables = []
32
32
  spec.require_paths = %w[lib]
33
33
 
34
+ spec.add_dependency 'base64'
35
+
34
36
  spec.add_development_dependency 'appraisal'
35
37
  spec.add_development_dependency 'bundler'
36
38
  spec.add_development_dependency 'rake'
37
39
  spec.add_development_dependency 'rspec'
40
+ spec.add_development_dependency 'rubocop'
38
41
  spec.add_development_dependency 'simplecov'
39
42
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.1
4
+ version: 2.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Rudat
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-09 00:00:00.000000000 Z
11
+ date: 2024-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: base64
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: appraisal
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +80,20 @@ dependencies:
66
80
  - - ">="
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: simplecov
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -94,27 +122,38 @@ files:
94
122
  - LICENSE
95
123
  - README.md
96
124
  - lib/jwt.rb
97
- - lib/jwt/algos.rb
98
- - lib/jwt/algos/algo_wrapper.rb
99
- - lib/jwt/algos/ecdsa.rb
100
- - lib/jwt/algos/eddsa.rb
101
- - lib/jwt/algos/hmac.rb
102
- - lib/jwt/algos/hmac_rbnacl.rb
103
- - lib/jwt/algos/hmac_rbnacl_fixed.rb
104
- - lib/jwt/algos/none.rb
105
- - lib/jwt/algos/ps.rb
106
- - lib/jwt/algos/rsa.rb
107
- - lib/jwt/algos/unsupported.rb
108
125
  - lib/jwt/base64.rb
109
- - lib/jwt/claims_validator.rb
126
+ - lib/jwt/claims.rb
127
+ - lib/jwt/claims/audience.rb
128
+ - lib/jwt/claims/expiration.rb
129
+ - lib/jwt/claims/issued_at.rb
130
+ - lib/jwt/claims/issuer.rb
131
+ - lib/jwt/claims/jwt_id.rb
132
+ - lib/jwt/claims/not_before.rb
133
+ - lib/jwt/claims/numeric.rb
134
+ - lib/jwt/claims/required.rb
135
+ - lib/jwt/claims/subject.rb
110
136
  - lib/jwt/configuration.rb
111
137
  - lib/jwt/configuration/container.rb
112
138
  - lib/jwt/configuration/decode_configuration.rb
113
139
  - lib/jwt/configuration/jwk_configuration.rb
114
140
  - lib/jwt/decode.rb
141
+ - lib/jwt/deprecations.rb
115
142
  - lib/jwt/encode.rb
116
143
  - lib/jwt/error.rb
117
144
  - lib/jwt/json.rb
145
+ - lib/jwt/jwa.rb
146
+ - lib/jwt/jwa/ecdsa.rb
147
+ - lib/jwt/jwa/eddsa.rb
148
+ - lib/jwt/jwa/hmac.rb
149
+ - lib/jwt/jwa/hmac_rbnacl.rb
150
+ - lib/jwt/jwa/hmac_rbnacl_fixed.rb
151
+ - lib/jwt/jwa/none.rb
152
+ - lib/jwt/jwa/ps.rb
153
+ - lib/jwt/jwa/rsa.rb
154
+ - lib/jwt/jwa/signing_algorithm.rb
155
+ - lib/jwt/jwa/unsupported.rb
156
+ - lib/jwt/jwa/wrapper.rb
118
157
  - lib/jwt/jwk.rb
119
158
  - lib/jwt/jwk/ec.rb
120
159
  - lib/jwt/jwk/hmac.rb
@@ -125,7 +164,6 @@ files:
125
164
  - lib/jwt/jwk/rsa.rb
126
165
  - lib/jwt/jwk/set.rb
127
166
  - lib/jwt/jwk/thumbprint.rb
128
- - lib/jwt/verify.rb
129
167
  - lib/jwt/version.rb
130
168
  - lib/jwt/x5c_key_finder.rb
131
169
  - ruby-jwt.gemspec
@@ -134,9 +172,9 @@ licenses:
134
172
  - MIT
135
173
  metadata:
136
174
  bug_tracker_uri: https://github.com/jwt/ruby-jwt/issues
137
- changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.7.1/CHANGELOG.md
175
+ changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.9.0/CHANGELOG.md
138
176
  rubygems_mfa_required: 'true'
139
- post_install_message:
177
+ post_install_message:
140
178
  rdoc_options: []
141
179
  require_paths:
142
180
  - lib
@@ -151,8 +189,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
189
  - !ruby/object:Gem::Version
152
190
  version: '0'
153
191
  requirements: []
154
- rubygems_version: 3.3.7
155
- signing_key:
192
+ rubygems_version: 3.5.16
193
+ signing_key:
156
194
  specification_version: 4
157
195
  summary: JSON Web Token implementation in Ruby
158
196
  test_files: []
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JWT
4
- module Algos
5
- class AlgoWrapper
6
- attr_reader :alg, :cls
7
-
8
- def initialize(alg, cls)
9
- @alg = alg
10
- @cls = cls
11
- end
12
-
13
- def valid_alg?(alg_to_check)
14
- alg&.casecmp(alg_to_check)&.zero? == true
15
- end
16
-
17
- def sign(data:, signing_key:)
18
- cls.sign(alg, data, signing_key)
19
- end
20
-
21
- def verify(data:, signature:, verification_key:)
22
- cls.verify(alg, verification_key, data, signature)
23
- end
24
- end
25
- end
26
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JWT
4
- module Algos
5
- module Eddsa
6
- module_function
7
-
8
- SUPPORTED = %w[ED25519 EdDSA].freeze
9
-
10
- def sign(algorithm, msg, key)
11
- if key.class != RbNaCl::Signatures::Ed25519::SigningKey
12
- raise EncodeError, "Key given is a #{key.class} but has to be an RbNaCl::Signatures::Ed25519::SigningKey"
13
- end
14
- unless SUPPORTED.map(&:downcase).map(&:to_sym).include?(algorithm.downcase.to_sym)
15
- raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key.primitive} signing key was provided"
16
- end
17
-
18
- key.sign(msg)
19
- end
20
-
21
- def verify(algorithm, public_key, signing_input, signature)
22
- unless SUPPORTED.map(&:downcase).map(&:to_sym).include?(algorithm.downcase.to_sym)
23
- raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key.primitive} signing key was provided"
24
- end
25
- raise DecodeError, "key given is a #{public_key.class} but has to be a RbNaCl::Signatures::Ed25519::VerifyKey" if public_key.class != RbNaCl::Signatures::Ed25519::VerifyKey
26
-
27
- public_key.verify(signature, signing_input)
28
- rescue RbNaCl::CryptoError
29
- false
30
- end
31
- end
32
- end
33
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JWT
4
- module Algos
5
- module HmacRbNaCl
6
- module_function
7
-
8
- MAPPING = {
9
- 'HS256' => ::RbNaCl::HMAC::SHA256,
10
- 'HS512256' => ::RbNaCl::HMAC::SHA512256,
11
- 'HS384' => nil,
12
- 'HS512' => ::RbNaCl::HMAC::SHA512
13
- }.freeze
14
-
15
- SUPPORTED = MAPPING.keys
16
-
17
- def sign(algorithm, msg, key)
18
- if (hmac = resolve_algorithm(algorithm))
19
- hmac.auth(key_for_rbnacl(hmac, key).encode('binary'), msg.encode('binary'))
20
- else
21
- Hmac.sign(algorithm, msg, key)
22
- end
23
- end
24
-
25
- def verify(algorithm, key, signing_input, signature)
26
- if (hmac = resolve_algorithm(algorithm))
27
- hmac.verify(key_for_rbnacl(hmac, key).encode('binary'), signature.encode('binary'), signing_input.encode('binary'))
28
- else
29
- Hmac.verify(algorithm, key, signing_input, signature)
30
- end
31
- rescue ::RbNaCl::BadAuthenticatorError, ::RbNaCl::LengthError
32
- false
33
- end
34
-
35
- def key_for_rbnacl(hmac, key)
36
- key ||= ''
37
- raise JWT::DecodeError, 'HMAC key expected to be a String' unless key.is_a?(String)
38
-
39
- return padded_empty_key(hmac.key_bytes) if key == ''
40
-
41
- key
42
- end
43
-
44
- def resolve_algorithm(algorithm)
45
- MAPPING.fetch(algorithm)
46
- end
47
-
48
- def padded_empty_key(length)
49
- Array.new(length, 0x0).pack('C*').encode('binary')
50
- end
51
- end
52
- end
53
- end
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JWT
4
- module Algos
5
- module HmacRbNaClFixed
6
- module_function
7
-
8
- MAPPING = {
9
- 'HS256' => ::RbNaCl::HMAC::SHA256,
10
- 'HS512256' => ::RbNaCl::HMAC::SHA512256,
11
- 'HS384' => nil,
12
- 'HS512' => ::RbNaCl::HMAC::SHA512
13
- }.freeze
14
-
15
- SUPPORTED = MAPPING.keys
16
-
17
- def sign(algorithm, msg, key)
18
- key ||= ''
19
-
20
- raise JWT::DecodeError, 'HMAC key expected to be a String' unless key.is_a?(String)
21
-
22
- if (hmac = resolve_algorithm(algorithm)) && key.bytesize <= hmac.key_bytes
23
- hmac.auth(padded_key_bytes(key, hmac.key_bytes), msg.encode('binary'))
24
- else
25
- Hmac.sign(algorithm, msg, key)
26
- end
27
- end
28
-
29
- def verify(algorithm, key, signing_input, signature)
30
- key ||= ''
31
-
32
- raise JWT::DecodeError, 'HMAC key expected to be a String' unless key.is_a?(String)
33
-
34
- if (hmac = resolve_algorithm(algorithm)) && key.bytesize <= hmac.key_bytes
35
- hmac.verify(padded_key_bytes(key, hmac.key_bytes), signature.encode('binary'), signing_input.encode('binary'))
36
- else
37
- Hmac.verify(algorithm, key, signing_input, signature)
38
- end
39
- rescue ::RbNaCl::BadAuthenticatorError, ::RbNaCl::LengthError
40
- false
41
- end
42
-
43
- def resolve_algorithm(algorithm)
44
- MAPPING.fetch(algorithm)
45
- end
46
-
47
- def padded_key_bytes(key, bytesize)
48
- key.bytes.fill(0, key.bytesize...bytesize).pack('C*')
49
- end
50
- end
51
- end
52
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JWT
4
- module Algos
5
- module None
6
- module_function
7
-
8
- SUPPORTED = %w[none].freeze
9
-
10
- def sign(*)
11
- ''
12
- end
13
-
14
- def verify(*)
15
- true
16
- end
17
- end
18
- end
19
- end