jwt 2.7.0 → 2.10.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +155 -24
- data/README.md +208 -102
- data/lib/jwt/base64.rb +19 -2
- data/lib/jwt/claims/audience.rb +30 -0
- data/lib/jwt/claims/crit.rb +35 -0
- data/lib/jwt/claims/decode_verifier.rb +40 -0
- data/lib/jwt/claims/expiration.rb +32 -0
- data/lib/jwt/claims/issued_at.rb +22 -0
- data/lib/jwt/claims/issuer.rb +34 -0
- data/lib/jwt/claims/jwt_id.rb +35 -0
- data/lib/jwt/claims/not_before.rb +32 -0
- data/lib/jwt/claims/numeric.rb +77 -0
- data/lib/jwt/claims/required.rb +33 -0
- data/lib/jwt/claims/subject.rb +30 -0
- data/lib/jwt/claims/verification_methods.rb +20 -0
- data/lib/jwt/claims/verifier.rb +61 -0
- data/lib/jwt/claims.rb +74 -0
- data/lib/jwt/claims_validator.rb +6 -25
- data/lib/jwt/configuration/container.rb +34 -3
- data/lib/jwt/configuration/decode_configuration.rb +24 -0
- data/lib/jwt/configuration/jwk_configuration.rb +2 -1
- data/lib/jwt/configuration.rb +8 -0
- data/lib/jwt/decode.rb +34 -82
- data/lib/jwt/deprecations.rb +49 -0
- data/lib/jwt/encode.rb +18 -67
- data/lib/jwt/encoded_token.rb +139 -0
- data/lib/jwt/error.rb +35 -0
- data/lib/jwt/json.rb +1 -1
- data/lib/jwt/jwa/compat.rb +32 -0
- data/lib/jwt/jwa/ecdsa.rb +90 -0
- data/lib/jwt/jwa/eddsa.rb +35 -0
- data/lib/jwt/{algos → jwa}/hmac.rb +28 -19
- data/lib/jwt/jwa/hmac_rbnacl.rb +50 -0
- data/lib/jwt/jwa/hmac_rbnacl_fixed.rb +47 -0
- data/lib/jwt/jwa/none.rb +24 -0
- data/lib/jwt/jwa/ps.rb +35 -0
- data/lib/jwt/jwa/rsa.rb +35 -0
- data/lib/jwt/jwa/signing_algorithm.rb +63 -0
- data/lib/jwt/jwa/unsupported.rb +20 -0
- data/lib/jwt/jwa/wrapper.rb +44 -0
- data/lib/jwt/jwa.rb +58 -0
- data/lib/jwt/jwk/ec.rb +44 -30
- data/lib/jwt/jwk/hmac.rb +2 -3
- data/lib/jwt/jwk/key_base.rb +4 -1
- data/lib/jwt/jwk/key_finder.rb +5 -4
- data/lib/jwt/jwk/kid_as_key_digest.rb +1 -0
- data/lib/jwt/jwk/okp_rbnacl.rb +3 -4
- data/lib/jwt/jwk/rsa.rb +2 -3
- data/lib/jwt/jwk/set.rb +3 -1
- data/lib/jwt/jwk.rb +2 -1
- data/lib/jwt/token.rb +112 -0
- data/lib/jwt/verify.rb +16 -89
- data/lib/jwt/version.rb +33 -11
- data/lib/jwt/x5c_key_finder.rb +2 -5
- data/lib/jwt.rb +24 -1
- data/ruby-jwt.gemspec +4 -0
- metadata +76 -19
- data/lib/jwt/algos/algo_wrapper.rb +0 -30
- data/lib/jwt/algos/ecdsa.rb +0 -62
- data/lib/jwt/algos/eddsa.rb +0 -33
- data/lib/jwt/algos/hmac_rbnacl.rb +0 -53
- data/lib/jwt/algos/hmac_rbnacl_fixed.rb +0 -52
- data/lib/jwt/algos/none.rb +0 -19
- data/lib/jwt/algos/ps.rb +0 -41
- data/lib/jwt/algos/rsa.rb +0 -21
- data/lib/jwt/algos/unsupported.rb +0 -19
- data/lib/jwt/algos.rb +0 -67
- data/lib/jwt/security_utils.rb +0 -32
metadata
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jwt
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.10.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tim Rudat
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: base64
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
13
26
|
- !ruby/object:Gem::Dependency
|
|
14
27
|
name: appraisal
|
|
15
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -38,6 +51,20 @@ dependencies:
|
|
|
38
51
|
- - ">="
|
|
39
52
|
- !ruby/object:Gem::Version
|
|
40
53
|
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: logger
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
41
68
|
- !ruby/object:Gem::Dependency
|
|
42
69
|
name: rake
|
|
43
70
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -66,6 +93,20 @@ dependencies:
|
|
|
66
93
|
- - ">="
|
|
67
94
|
- !ruby/object:Gem::Version
|
|
68
95
|
version: '0'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: rubocop
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0'
|
|
103
|
+
type: :development
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - ">="
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
69
110
|
- !ruby/object:Gem::Dependency
|
|
70
111
|
name: simplecov
|
|
71
112
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -94,27 +135,45 @@ files:
|
|
|
94
135
|
- LICENSE
|
|
95
136
|
- README.md
|
|
96
137
|
- 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
138
|
- lib/jwt/base64.rb
|
|
139
|
+
- lib/jwt/claims.rb
|
|
140
|
+
- lib/jwt/claims/audience.rb
|
|
141
|
+
- lib/jwt/claims/crit.rb
|
|
142
|
+
- lib/jwt/claims/decode_verifier.rb
|
|
143
|
+
- lib/jwt/claims/expiration.rb
|
|
144
|
+
- lib/jwt/claims/issued_at.rb
|
|
145
|
+
- lib/jwt/claims/issuer.rb
|
|
146
|
+
- lib/jwt/claims/jwt_id.rb
|
|
147
|
+
- lib/jwt/claims/not_before.rb
|
|
148
|
+
- lib/jwt/claims/numeric.rb
|
|
149
|
+
- lib/jwt/claims/required.rb
|
|
150
|
+
- lib/jwt/claims/subject.rb
|
|
151
|
+
- lib/jwt/claims/verification_methods.rb
|
|
152
|
+
- lib/jwt/claims/verifier.rb
|
|
109
153
|
- lib/jwt/claims_validator.rb
|
|
110
154
|
- lib/jwt/configuration.rb
|
|
111
155
|
- lib/jwt/configuration/container.rb
|
|
112
156
|
- lib/jwt/configuration/decode_configuration.rb
|
|
113
157
|
- lib/jwt/configuration/jwk_configuration.rb
|
|
114
158
|
- lib/jwt/decode.rb
|
|
159
|
+
- lib/jwt/deprecations.rb
|
|
115
160
|
- lib/jwt/encode.rb
|
|
161
|
+
- lib/jwt/encoded_token.rb
|
|
116
162
|
- lib/jwt/error.rb
|
|
117
163
|
- lib/jwt/json.rb
|
|
164
|
+
- lib/jwt/jwa.rb
|
|
165
|
+
- lib/jwt/jwa/compat.rb
|
|
166
|
+
- lib/jwt/jwa/ecdsa.rb
|
|
167
|
+
- lib/jwt/jwa/eddsa.rb
|
|
168
|
+
- lib/jwt/jwa/hmac.rb
|
|
169
|
+
- lib/jwt/jwa/hmac_rbnacl.rb
|
|
170
|
+
- lib/jwt/jwa/hmac_rbnacl_fixed.rb
|
|
171
|
+
- lib/jwt/jwa/none.rb
|
|
172
|
+
- lib/jwt/jwa/ps.rb
|
|
173
|
+
- lib/jwt/jwa/rsa.rb
|
|
174
|
+
- lib/jwt/jwa/signing_algorithm.rb
|
|
175
|
+
- lib/jwt/jwa/unsupported.rb
|
|
176
|
+
- lib/jwt/jwa/wrapper.rb
|
|
118
177
|
- lib/jwt/jwk.rb
|
|
119
178
|
- lib/jwt/jwk/ec.rb
|
|
120
179
|
- lib/jwt/jwk/hmac.rb
|
|
@@ -125,7 +184,7 @@ files:
|
|
|
125
184
|
- lib/jwt/jwk/rsa.rb
|
|
126
185
|
- lib/jwt/jwk/set.rb
|
|
127
186
|
- lib/jwt/jwk/thumbprint.rb
|
|
128
|
-
- lib/jwt/
|
|
187
|
+
- lib/jwt/token.rb
|
|
129
188
|
- lib/jwt/verify.rb
|
|
130
189
|
- lib/jwt/version.rb
|
|
131
190
|
- lib/jwt/x5c_key_finder.rb
|
|
@@ -135,9 +194,8 @@ licenses:
|
|
|
135
194
|
- MIT
|
|
136
195
|
metadata:
|
|
137
196
|
bug_tracker_uri: https://github.com/jwt/ruby-jwt/issues
|
|
138
|
-
changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.
|
|
197
|
+
changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.10.2/CHANGELOG.md
|
|
139
198
|
rubygems_mfa_required: 'true'
|
|
140
|
-
post_install_message:
|
|
141
199
|
rdoc_options: []
|
|
142
200
|
require_paths:
|
|
143
201
|
- lib
|
|
@@ -152,8 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
152
210
|
- !ruby/object:Gem::Version
|
|
153
211
|
version: '0'
|
|
154
212
|
requirements: []
|
|
155
|
-
rubygems_version: 3.
|
|
156
|
-
signing_key:
|
|
213
|
+
rubygems_version: 3.6.7
|
|
157
214
|
specification_version: 4
|
|
158
215
|
summary: JSON Web Token implementation in Ruby
|
|
159
216
|
test_files: []
|
|
@@ -1,30 +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
|
-
rescue OpenSSL::PKey::PKeyError # These should be moved to the algorithms that actually need this, but left here to ensure nothing will break.
|
|
24
|
-
raise JWT::VerificationError, 'Signature verification raised'
|
|
25
|
-
ensure
|
|
26
|
-
OpenSSL.errors.clear
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
data/lib/jwt/algos/ecdsa.rb
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JWT
|
|
4
|
-
module Algos
|
|
5
|
-
module Ecdsa
|
|
6
|
-
module_function
|
|
7
|
-
|
|
8
|
-
NAMED_CURVES = {
|
|
9
|
-
'prime256v1' => {
|
|
10
|
-
algorithm: 'ES256',
|
|
11
|
-
digest: 'sha256'
|
|
12
|
-
},
|
|
13
|
-
'secp256r1' => { # alias for prime256v1
|
|
14
|
-
algorithm: 'ES256',
|
|
15
|
-
digest: 'sha256'
|
|
16
|
-
},
|
|
17
|
-
'secp384r1' => {
|
|
18
|
-
algorithm: 'ES384',
|
|
19
|
-
digest: 'sha384'
|
|
20
|
-
},
|
|
21
|
-
'secp521r1' => {
|
|
22
|
-
algorithm: 'ES512',
|
|
23
|
-
digest: 'sha512'
|
|
24
|
-
},
|
|
25
|
-
'secp256k1' => {
|
|
26
|
-
algorithm: 'ES256K',
|
|
27
|
-
digest: 'sha256'
|
|
28
|
-
}
|
|
29
|
-
}.freeze
|
|
30
|
-
|
|
31
|
-
SUPPORTED = NAMED_CURVES.map { |_, c| c[:algorithm] }.uniq.freeze
|
|
32
|
-
|
|
33
|
-
def sign(algorithm, msg, key)
|
|
34
|
-
curve_definition = curve_by_name(key.group.curve_name)
|
|
35
|
-
key_algorithm = curve_definition[:algorithm]
|
|
36
|
-
if algorithm != key_algorithm
|
|
37
|
-
raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} signing key was provided"
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
digest = OpenSSL::Digest.new(curve_definition[:digest])
|
|
41
|
-
SecurityUtils.asn1_to_raw(key.dsa_sign_asn1(digest.digest(msg)), key)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def verify(algorithm, public_key, signing_input, signature)
|
|
45
|
-
curve_definition = curve_by_name(public_key.group.curve_name)
|
|
46
|
-
key_algorithm = curve_definition[:algorithm]
|
|
47
|
-
if algorithm != key_algorithm
|
|
48
|
-
raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} verification key was provided"
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
digest = OpenSSL::Digest.new(curve_definition[:digest])
|
|
52
|
-
public_key.dsa_verify_asn1(digest.digest(signing_input), SecurityUtils.raw_to_asn1(signature, public_key))
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def curve_by_name(name)
|
|
56
|
-
NAMED_CURVES.fetch(name) do
|
|
57
|
-
raise UnsupportedEcdsaCurve, "The ECDSA curve '#{name}' is not supported"
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
data/lib/jwt/algos/eddsa.rb
DELETED
|
@@ -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
|
|
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
|
|
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
|
data/lib/jwt/algos/none.rb
DELETED
data/lib/jwt/algos/ps.rb
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JWT
|
|
4
|
-
module Algos
|
|
5
|
-
module Ps
|
|
6
|
-
# RSASSA-PSS signing algorithms
|
|
7
|
-
|
|
8
|
-
module_function
|
|
9
|
-
|
|
10
|
-
SUPPORTED = %w[PS256 PS384 PS512].freeze
|
|
11
|
-
|
|
12
|
-
def sign(algorithm, msg, key)
|
|
13
|
-
require_openssl!
|
|
14
|
-
|
|
15
|
-
key_class = key.class
|
|
16
|
-
|
|
17
|
-
raise EncodeError, "The given key is a #{key_class}. It has to be an OpenSSL::PKey::RSA instance." if key_class == String
|
|
18
|
-
|
|
19
|
-
translated_algorithm = algorithm.sub('PS', 'sha')
|
|
20
|
-
|
|
21
|
-
key.sign_pss(translated_algorithm, msg, salt_length: :digest, mgf1_hash: translated_algorithm)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def verify(algorithm, public_key, signing_input, signature)
|
|
25
|
-
require_openssl!
|
|
26
|
-
|
|
27
|
-
SecurityUtils.verify_ps(algorithm, public_key, signing_input, signature)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def require_openssl!
|
|
31
|
-
if Object.const_defined?('OpenSSL')
|
|
32
|
-
if ::Gem::Version.new(OpenSSL::VERSION) < ::Gem::Version.new('2.1')
|
|
33
|
-
raise JWT::RequiredDependencyError, "You currently have OpenSSL #{OpenSSL::VERSION}. PS support requires >= 2.1"
|
|
34
|
-
end
|
|
35
|
-
else
|
|
36
|
-
raise JWT::RequiredDependencyError, 'PS signing requires OpenSSL +2.1'
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
data/lib/jwt/algos/rsa.rb
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JWT
|
|
4
|
-
module Algos
|
|
5
|
-
module Rsa
|
|
6
|
-
module_function
|
|
7
|
-
|
|
8
|
-
SUPPORTED = %w[RS256 RS384 RS512].freeze
|
|
9
|
-
|
|
10
|
-
def sign(algorithm, msg, key)
|
|
11
|
-
raise EncodeError, "The given key is a #{key.class}. It has to be an OpenSSL::PKey::RSA instance." if key.instance_of?(String)
|
|
12
|
-
|
|
13
|
-
key.sign(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), msg)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def verify(algorithm, public_key, signing_input, signature)
|
|
17
|
-
SecurityUtils.verify_rsa(algorithm, public_key, signing_input, signature)
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JWT
|
|
4
|
-
module Algos
|
|
5
|
-
module Unsupported
|
|
6
|
-
module_function
|
|
7
|
-
|
|
8
|
-
SUPPORTED = [].freeze
|
|
9
|
-
|
|
10
|
-
def sign(*)
|
|
11
|
-
raise NotImplementedError, 'Unsupported signing method'
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def verify(*)
|
|
15
|
-
raise JWT::VerificationError, 'Algorithm not supported'
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
data/lib/jwt/algos.rb
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
begin
|
|
4
|
-
require 'rbnacl'
|
|
5
|
-
rescue LoadError
|
|
6
|
-
raise if defined?(RbNaCl)
|
|
7
|
-
end
|
|
8
|
-
require 'openssl'
|
|
9
|
-
|
|
10
|
-
require 'jwt/security_utils'
|
|
11
|
-
require 'jwt/algos/hmac'
|
|
12
|
-
require 'jwt/algos/eddsa'
|
|
13
|
-
require 'jwt/algos/ecdsa'
|
|
14
|
-
require 'jwt/algos/rsa'
|
|
15
|
-
require 'jwt/algos/ps'
|
|
16
|
-
require 'jwt/algos/none'
|
|
17
|
-
require 'jwt/algos/unsupported'
|
|
18
|
-
require 'jwt/algos/algo_wrapper'
|
|
19
|
-
|
|
20
|
-
module JWT
|
|
21
|
-
module Algos
|
|
22
|
-
extend self
|
|
23
|
-
|
|
24
|
-
ALGOS = [Algos::Ecdsa,
|
|
25
|
-
Algos::Rsa,
|
|
26
|
-
Algos::Eddsa,
|
|
27
|
-
Algos::Ps,
|
|
28
|
-
Algos::None,
|
|
29
|
-
Algos::Unsupported].tap do |l|
|
|
30
|
-
if ::JWT.rbnacl_6_or_greater?
|
|
31
|
-
require_relative 'algos/hmac_rbnacl'
|
|
32
|
-
l.unshift(Algos::HmacRbNaCl)
|
|
33
|
-
elsif ::JWT.rbnacl?
|
|
34
|
-
require_relative 'algos/hmac_rbnacl_fixed'
|
|
35
|
-
l.unshift(Algos::HmacRbNaClFixed)
|
|
36
|
-
else
|
|
37
|
-
l.unshift(Algos::Hmac)
|
|
38
|
-
end
|
|
39
|
-
end.freeze
|
|
40
|
-
|
|
41
|
-
def find(algorithm)
|
|
42
|
-
indexed[algorithm && algorithm.downcase]
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def create(algorithm)
|
|
46
|
-
Algos::AlgoWrapper.new(*find(algorithm))
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def implementation?(algorithm)
|
|
50
|
-
(algorithm.respond_to?(:valid_alg?) && algorithm.respond_to?(:verify)) ||
|
|
51
|
-
(algorithm.respond_to?(:alg) && algorithm.respond_to?(:sign))
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
private
|
|
55
|
-
|
|
56
|
-
def indexed
|
|
57
|
-
@indexed ||= begin
|
|
58
|
-
fallback = [nil, Algos::Unsupported]
|
|
59
|
-
ALGOS.each_with_object(Hash.new(fallback)) do |cls, hash|
|
|
60
|
-
cls.const_get(:SUPPORTED).each do |alg|
|
|
61
|
-
hash[alg.downcase] = [alg, cls]
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
data/lib/jwt/security_utils.rb
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JWT
|
|
4
|
-
# Collection of security methods
|
|
5
|
-
#
|
|
6
|
-
# @see: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/security_utils.rb
|
|
7
|
-
module SecurityUtils
|
|
8
|
-
module_function
|
|
9
|
-
|
|
10
|
-
def verify_rsa(algorithm, public_key, signing_input, signature)
|
|
11
|
-
public_key.verify(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), signature, signing_input)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def verify_ps(algorithm, public_key, signing_input, signature)
|
|
15
|
-
formatted_algorithm = algorithm.sub('PS', 'sha')
|
|
16
|
-
|
|
17
|
-
public_key.verify_pss(formatted_algorithm, signature, signing_input, salt_length: :auto, mgf1_hash: formatted_algorithm)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def asn1_to_raw(signature, public_key)
|
|
21
|
-
byte_size = (public_key.group.degree + 7) / 8
|
|
22
|
-
OpenSSL::ASN1.decode(signature).value.map { |value| value.value.to_s(2).rjust(byte_size, "\x00") }.join
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def raw_to_asn1(signature, private_key)
|
|
26
|
-
byte_size = (private_key.group.degree + 7) / 8
|
|
27
|
-
sig_bytes = signature[0..(byte_size - 1)]
|
|
28
|
-
sig_char = signature[byte_size..-1] || ''
|
|
29
|
-
OpenSSL::ASN1::Sequence.new([sig_bytes, sig_char].map { |int| OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(int, 2)) }).to_der
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|