jwt 2.7.1 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
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