jwt 2.7.1 → 2.8.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +49 -27
- data/README.md +1 -8
- data/lib/jwt/base64.rb +14 -2
- data/lib/jwt/claims_validator.rb +1 -1
- data/lib/jwt/decode.rb +1 -7
- data/lib/jwt/encode.rb +2 -8
- data/lib/jwt/{algos → jwa}/ecdsa.rb +1 -1
- data/lib/jwt/jwa/eddsa.rb +42 -0
- data/lib/jwt/{algos → jwa}/hmac.rb +3 -1
- data/lib/jwt/jwa/hmac_rbnacl.rb +50 -0
- data/lib/jwt/jwa/hmac_rbnacl_fixed.rb +46 -0
- data/lib/jwt/{algos → jwa}/none.rb +1 -1
- data/lib/jwt/{algos → jwa}/ps.rb +4 -15
- data/lib/jwt/{algos → jwa}/rsa.rb +4 -2
- data/lib/jwt/{algos → jwa}/unsupported.rb +1 -1
- data/lib/jwt/{algos/algo_wrapper.rb → jwa/wrapper.rb} +2 -2
- data/lib/jwt/jwa.rb +62 -0
- data/lib/jwt/jwk/ec.rb +22 -7
- data/lib/jwt/jwk/key_base.rb +3 -1
- data/lib/jwt/jwk.rb +1 -1
- data/lib/jwt/verify.rb +8 -4
- data/lib/jwt/version.rb +4 -3
- data/lib/jwt/x5c_key_finder.rb +0 -3
- data/ruby-jwt.gemspec +3 -0
- metadata +42 -14
- 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.rb +0 -66
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 79758529bec5a1fad3183ee054a2e47e800f6611681f9f9052cbb92ea645b4ef
|
|
4
|
+
data.tar.gz: d9bffb9bb0e855a2da3cc04ec0d3ee82174555b2bc23cceec8901b4c50b9a42a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e9622f261b3a037cfc6dddfdd8f452a123c0c0443a3599565830cc000f7a20eec9f5ad673450bd485a47a8c666e6c9c95729c2d8cc123c984e5d0a255ed41dc4
|
|
7
|
+
data.tar.gz: d0ef0c055249ac588d0cb26bc4ead5b1b607ae738eda5c0775723ca62640a9df092c3e07774c9fcb6545b9946d730f0260d40c2fc9e272fb7ec0ec62aa6f2b80
|
data/CHANGELOG.md
CHANGED
|
@@ -1,13 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [v2.8.0](https://github.com/jwt/ruby-jwt/tree/v2.8.0) (2024-02-17)
|
|
4
|
+
|
|
5
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.7.1...v2.8.0)
|
|
6
|
+
|
|
7
|
+
**Features:**
|
|
8
|
+
|
|
9
|
+
- Updated rubocop to 1.56 [#573](https://github.com/jwt/ruby-jwt/pull/573) ([@anakinj](https://github.com/anakinj))
|
|
10
|
+
- Run CI on Ruby 3.3 [#577](https://github.com/jwt/ruby-jwt/pull/577) ([@anakinj](https://github.com/anakinj))
|
|
11
|
+
- Deprecation warning added for the HMAC algorithm HS512256 (HMAC-SHA-512 truncated to 256-bits) [#575](https://github.com/jwt/ruby-jwt/pull/575) ([@anakinj](https://github.com/anakinj))
|
|
12
|
+
- Stop using RbNaCl for standard HMAC algorithms [#575](https://github.com/jwt/ruby-jwt/pull/575) ([@anakinj](https://github.com/anakinj))
|
|
13
|
+
|
|
14
|
+
**Fixes and enhancements:**
|
|
15
|
+
|
|
16
|
+
- Fix signature has expired error if payload is a string [#555](https://github.com/jwt/ruby-jwt/pull/555) ([@GobinathAL](https://github.com/GobinathAL))
|
|
17
|
+
- Fix key base equality and spaceship operators [#569](https://github.com/jwt/ruby-jwt/pull/569) ([@magneland](https://github.com/magneland))
|
|
18
|
+
- Remove explicit base64 require from x5c_key_finder [#580](https://github.com/jwt/ruby-jwt/pull/580) ([@anakinj](https://github.com/anakinj))
|
|
19
|
+
- Performance improvements and cleanup of tests [#581](https://github.com/jwt/ruby-jwt/pull/581) ([@anakinj](https://github.com/anakinj))
|
|
20
|
+
- Repair EC x/y coordinates when importing JWK [#585](https://github.com/jwt/ruby-jwt/pull/585) ([@julik](https://github.com/julik))
|
|
21
|
+
- Explicit dependency to the base64 gem [#582](https://github.com/jwt/ruby-jwt/pull/582) ([@anakinj](https://github.com/anakinj))
|
|
22
|
+
- Deprecation warning for decoding content not compliant with RFC 4648 [#582](https://github.com/jwt/ruby-jwt/pull/582) ([@anakinj](https://github.com/anakinj))
|
|
23
|
+
- Algorithms moved under the `::JWT::JWA` module ([@anakinj](https://github.com/anakinj))
|
|
24
|
+
|
|
3
25
|
## [v2.7.1](https://github.com/jwt/ruby-jwt/tree/v2.8.0) (2023-06-09)
|
|
4
26
|
|
|
5
|
-
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.7.0...v2.
|
|
27
|
+
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.7.0...v2.7.1)
|
|
6
28
|
|
|
7
29
|
**Fixes and enhancements:**
|
|
8
30
|
|
|
9
|
-
- Handle invalid algorithm when decoding JWT [#559](https://github.com/jwt/ruby-jwt/pull/559)
|
|
10
|
-
- Do not raise error when verifying bad HMAC signature [#563](https://github.com/jwt/ruby-jwt/pull/563)
|
|
31
|
+
- Handle invalid algorithm when decoding JWT [#559](https://github.com/jwt/ruby-jwt/pull/559) ([@nataliastanko](https://github.com/nataliastanko))
|
|
32
|
+
- Do not raise error when verifying bad HMAC signature [#563](https://github.com/jwt/ruby-jwt/pull/563) ([@hieuk09](https://github.com/hieuk09))
|
|
11
33
|
|
|
12
34
|
## [v2.7.0](https://github.com/jwt/ruby-jwt/tree/v2.7.0) (2023-02-01)
|
|
13
35
|
|
|
@@ -29,14 +51,14 @@
|
|
|
29
51
|
|
|
30
52
|
**Features:**
|
|
31
53
|
|
|
32
|
-
- Support custom algorithms by passing algorithm objects[#512](https://github.com/jwt/ruby-jwt/pull/512) ([@anakinj](https://github.com/anakinj))
|
|
33
|
-
- Support descriptive (not key related) JWK parameters[#520](https://github.com/jwt/ruby-jwt/pull/520) ([@bellebaum](https://github.com/bellebaum))
|
|
34
|
-
- Support for JSON Web Key Sets[#525](https://github.com/jwt/ruby-jwt/pull/525) ([@bellebaum](https://github.com/bellebaum))
|
|
35
|
-
- Support HMAC keys over 32 chars when using RbNaCl[#521](https://github.com/jwt/ruby-jwt/pull/521) ([@anakinj](https://github.com/anakinj))
|
|
54
|
+
- Support custom algorithms by passing algorithm objects [#512](https://github.com/jwt/ruby-jwt/pull/512) ([@anakinj](https://github.com/anakinj))
|
|
55
|
+
- Support descriptive (not key related) JWK parameters [#520](https://github.com/jwt/ruby-jwt/pull/520) ([@bellebaum](https://github.com/bellebaum))
|
|
56
|
+
- Support for JSON Web Key Sets [#525](https://github.com/jwt/ruby-jwt/pull/525) ([@bellebaum](https://github.com/bellebaum))
|
|
57
|
+
- Support HMAC keys over 32 chars when using RbNaCl [#521](https://github.com/jwt/ruby-jwt/pull/521) ([@anakinj](https://github.com/anakinj))
|
|
36
58
|
|
|
37
59
|
**Fixes and enhancements:**
|
|
38
60
|
|
|
39
|
-
- Raise descriptive error on empty hmac_secret and OpenSSL 3.0/openssl gem <3.0.1 [#530](https://github.com/jwt/ruby-jwt/pull/530) ([@jonmchan](https://github.com/jonmchan))
|
|
61
|
+
- Raise descriptive error on empty hmac_secret and OpenSSL 3.0/openssl gem <3.0.1 [#530](https://github.com/jwt/ruby-jwt/pull/530) ([@jonmchan](https://github.com/jonmchan))
|
|
40
62
|
|
|
41
63
|
## [v2.5.0](https://github.com/jwt/ruby-jwt/tree/v2.5.0) (2022-08-25)
|
|
42
64
|
|
|
@@ -44,21 +66,21 @@
|
|
|
44
66
|
|
|
45
67
|
**Features:**
|
|
46
68
|
|
|
47
|
-
- Support JWK thumbprints as key ids [#481](https://github.com/jwt/ruby-jwt/pull/481) ([@anakinj](https://github.com/anakinj))
|
|
48
|
-
- Support OpenSSL >= 3.0 [#496](https://github.com/jwt/ruby-jwt/pull/496) ([@anakinj](https://github.com/anakinj))
|
|
69
|
+
- Support JWK thumbprints as key ids [#481](https://github.com/jwt/ruby-jwt/pull/481) ([@anakinj](https://github.com/anakinj))
|
|
70
|
+
- Support OpenSSL >= 3.0 [#496](https://github.com/jwt/ruby-jwt/pull/496) ([@anakinj](https://github.com/anakinj))
|
|
49
71
|
|
|
50
72
|
**Fixes and enhancements:**
|
|
51
|
-
- Bring back the old Base64 (RFC2045) deocode mechanisms [#488](https://github.com/jwt/ruby-jwt/pull/488) ([@anakinj](https://github.com/anakinj))
|
|
52
|
-
- Rescue RbNaCl exception for EdDSA wrong key [#491](https://github.com/jwt/ruby-jwt/pull/491) ([@n-studio](https://github.com/n-studio))
|
|
53
|
-
- New parameter name for cases when kid is not found using JWK key loader proc [#501](https://github.com/jwt/ruby-jwt/pull/501) ([@anakinj](https://github.com/anakinj))
|
|
54
|
-
- Fix NoMethodError when a 2 segment token is missing 'alg' header [#502](https://github.com/jwt/ruby-jwt/pull/502) ([@cmrd-senya](https://github.com/cmrd-senya))
|
|
73
|
+
- Bring back the old Base64 (RFC2045) deocode mechanisms [#488](https://github.com/jwt/ruby-jwt/pull/488) ([@anakinj](https://github.com/anakinj))
|
|
74
|
+
- Rescue RbNaCl exception for EdDSA wrong key [#491](https://github.com/jwt/ruby-jwt/pull/491) ([@n-studio](https://github.com/n-studio))
|
|
75
|
+
- New parameter name for cases when kid is not found using JWK key loader proc [#501](https://github.com/jwt/ruby-jwt/pull/501) ([@anakinj](https://github.com/anakinj))
|
|
76
|
+
- Fix NoMethodError when a 2 segment token is missing 'alg' header [#502](https://github.com/jwt/ruby-jwt/pull/502) ([@cmrd-senya](https://github.com/cmrd-senya))
|
|
55
77
|
|
|
56
78
|
## [v2.4.1](https://github.com/jwt/ruby-jwt/tree/v2.4.1) (2022-06-07)
|
|
57
79
|
|
|
58
80
|
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.4.0...v2.4.1)
|
|
59
81
|
|
|
60
82
|
**Fixes and enhancements:**
|
|
61
|
-
- Raise JWT::DecodeError on invalid signature [\#484](https://github.com/jwt/ruby-jwt/pull/484) ([@freakyfelt!](https://github.com/freakyfelt!))
|
|
83
|
+
- Raise JWT::DecodeError on invalid signature [\#484](https://github.com/jwt/ruby-jwt/pull/484) ([@freakyfelt!](https://github.com/freakyfelt!))
|
|
62
84
|
|
|
63
85
|
## [v2.4.0](https://github.com/jwt/ruby-jwt/tree/v2.4.0) (2022-06-06)
|
|
64
86
|
|
|
@@ -66,20 +88,20 @@
|
|
|
66
88
|
|
|
67
89
|
**Features:**
|
|
68
90
|
|
|
69
|
-
- Dropped support for Ruby 2.5 and older [#453](https://github.com/jwt/ruby-jwt/pull/453) - [@anakinj](https://github.com/anakinj)
|
|
70
|
-
- Use Ruby built-in url-safe base64 methods [#454](https://github.com/jwt/ruby-jwt/pull/454) - [@bdewater](https://github.com/bdewater)
|
|
71
|
-
- Updated rubocop to 1.23.0 [#457](https://github.com/jwt/ruby-jwt/pull/457) - [@anakinj](https://github.com/anakinj)
|
|
72
|
-
- Add x5c header key finder [#338](https://github.com/jwt/ruby-jwt/pull/338) - [@bdewater](https://github.com/bdewater)
|
|
73
|
-
- Author driven changelog process [#463](https://github.com/jwt/ruby-jwt/pull/463) - [@anakinj](https://github.com/anakinj)
|
|
74
|
-
- Allow regular expressions and procs to verify issuer [\#437](https://github.com/jwt/ruby-jwt/pull/437) ([rewritten](https://github.com/rewritten))
|
|
75
|
-
- Add Support to be able to verify from multiple keys [\#425](https://github.com/jwt/ruby-jwt/pull/425) ([ritikesh](https://github.com/ritikesh))
|
|
91
|
+
- Dropped support for Ruby 2.5 and older [#453](https://github.com/jwt/ruby-jwt/pull/453) - ([@anakinj](https://github.com/anakinj))
|
|
92
|
+
- Use Ruby built-in url-safe base64 methods [#454](https://github.com/jwt/ruby-jwt/pull/454) - ([@bdewater](https://github.com/bdewater))
|
|
93
|
+
- Updated rubocop to 1.23.0 [#457](https://github.com/jwt/ruby-jwt/pull/457) - ([@anakinj](https://github.com/anakinj))
|
|
94
|
+
- Add x5c header key finder [#338](https://github.com/jwt/ruby-jwt/pull/338) - ([@bdewater](https://github.com/bdewater))
|
|
95
|
+
- Author driven changelog process [#463](https://github.com/jwt/ruby-jwt/pull/463) - ([@anakinj](https://github.com/anakinj))
|
|
96
|
+
- Allow regular expressions and procs to verify issuer [\#437](https://github.com/jwt/ruby-jwt/pull/437) ([rewritten](https://github.com/rewritten))
|
|
97
|
+
- Add Support to be able to verify from multiple keys [\#425](https://github.com/jwt/ruby-jwt/pull/425) ([ritikesh](https://github.com/ritikesh))
|
|
76
98
|
|
|
77
99
|
**Fixes and enhancements:**
|
|
78
|
-
- Readme: Typo fix re MissingRequiredClaim [\#451](https://github.com/jwt/ruby-jwt/pull/451) ([antonmorant](https://github.com/antonmorant))
|
|
79
|
-
- Fix RuboCop TODOs [\#476](https://github.com/jwt/ruby-jwt/pull/476) ([typhoon2099](https://github.com/typhoon2099))
|
|
80
|
-
- Make specific algorithms in README linkable [\#472](https://github.com/jwt/ruby-jwt/pull/472) ([milieu](https://github.com/milieu))
|
|
81
|
-
- Update note about supported JWK types [\#475](https://github.com/jwt/ruby-jwt/pull/475) ([dpashkevich](https://github.com/dpashkevich))
|
|
82
|
-
- Create CODE\_OF\_CONDUCT.md [\#449](https://github.com/jwt/ruby-jwt/pull/449) ([loic5](https://github.com/loic5))
|
|
100
|
+
- Readme: Typo fix re MissingRequiredClaim [\#451](https://github.com/jwt/ruby-jwt/pull/451) ([antonmorant](https://github.com/antonmorant))
|
|
101
|
+
- Fix RuboCop TODOs [\#476](https://github.com/jwt/ruby-jwt/pull/476) ([typhoon2099](https://github.com/typhoon2099))
|
|
102
|
+
- Make specific algorithms in README linkable [\#472](https://github.com/jwt/ruby-jwt/pull/472) ([milieu](https://github.com/milieu))
|
|
103
|
+
- Update note about supported JWK types [\#475](https://github.com/jwt/ruby-jwt/pull/475) ([dpashkevich](https://github.com/dpashkevich))
|
|
104
|
+
- Create CODE\_OF\_CONDUCT.md [\#449](https://github.com/jwt/ruby-jwt/pull/449) ([loic5](https://github.com/loic5))
|
|
83
105
|
|
|
84
106
|
## [v2.3.0](https://github.com/jwt/ruby-jwt/tree/v2.3.0) (2021-10-03)
|
|
85
107
|
|
data/README.md
CHANGED
|
@@ -72,7 +72,6 @@ puts decoded_token
|
|
|
72
72
|
### **HMAC**
|
|
73
73
|
|
|
74
74
|
* HS256 - HMAC using SHA-256 hash algorithm
|
|
75
|
-
* HS512256 - HMAC using SHA-512-256 hash algorithm (only available with RbNaCl; see note below)
|
|
76
75
|
* HS384 - HMAC using SHA-384 hash algorithm
|
|
77
76
|
* HS512 - HMAC using SHA-512 hash algorithm
|
|
78
77
|
|
|
@@ -95,12 +94,6 @@ decoded_token = JWT.decode token, hmac_secret, true, { algorithm: 'HS256' }
|
|
|
95
94
|
puts decoded_token
|
|
96
95
|
```
|
|
97
96
|
|
|
98
|
-
Note: If [RbNaCl](https://github.com/RubyCrypto/rbnacl) is loadable, ruby-jwt will use it for HMAC-SHA256, HMAC-SHA512-256, and HMAC-SHA512. RbNaCl prior to 6.0.0 only support a maximum key size of 32 bytes for these algorithms.
|
|
99
|
-
|
|
100
|
-
[RbNaCl](https://github.com/RubyCrypto/rbnacl) requires
|
|
101
|
-
[libsodium](https://github.com/jedisct1/libsodium), it can be installed
|
|
102
|
-
on MacOS with `brew install libsodium`.
|
|
103
|
-
|
|
104
97
|
### **RSA**
|
|
105
98
|
|
|
106
99
|
* RS256 - RSA using SHA-256 hash algorithm
|
|
@@ -561,7 +554,7 @@ crls = crl_uris.map do |uri|
|
|
|
561
554
|
end
|
|
562
555
|
|
|
563
556
|
begin
|
|
564
|
-
JWT.decode(token, nil, true, { x5c: { root_certificates: root_certificates, crls: crls })
|
|
557
|
+
JWT.decode(token, nil, true, { x5c: { root_certificates: root_certificates, crls: crls } })
|
|
565
558
|
rescue JWT::DecodeError
|
|
566
559
|
# Handle error, e.g. x5c header certificate revoked or expired
|
|
567
560
|
end
|
data/lib/jwt/base64.rb
CHANGED
|
@@ -3,14 +3,26 @@
|
|
|
3
3
|
require 'base64'
|
|
4
4
|
|
|
5
5
|
module JWT
|
|
6
|
-
# Base64
|
|
6
|
+
# Base64 encoding and decoding
|
|
7
7
|
class Base64
|
|
8
8
|
class << self
|
|
9
|
+
# Encode a string with URL-safe Base64 complying with RFC 4648 (not padded).
|
|
9
10
|
def url_encode(str)
|
|
10
|
-
::Base64.
|
|
11
|
+
::Base64.urlsafe_encode64(str, padding: false)
|
|
11
12
|
end
|
|
12
13
|
|
|
14
|
+
# Decode a string with URL-safe Base64 complying with RFC 4648.
|
|
15
|
+
# Deprecated support for RFC 2045 remains for now. ("All line breaks or other characters not found in Table 1 must be ignored by decoding software")
|
|
13
16
|
def url_decode(str)
|
|
17
|
+
::Base64.urlsafe_decode64(str)
|
|
18
|
+
rescue ArgumentError => e
|
|
19
|
+
raise unless e.message == 'invalid base64'
|
|
20
|
+
|
|
21
|
+
warn('[DEPRECATION] Invalid base64 input detected, could be because of invalid padding, trailing whitespaces or newline chars. Graceful handling of invalid input will be dropped in the next major version of ruby-jwt')
|
|
22
|
+
loose_urlsafe_decode64(str)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def loose_urlsafe_decode64(str)
|
|
14
26
|
str += '=' * (4 - str.length.modulo(4))
|
|
15
27
|
::Base64.decode64(str.tr('-_', '+/'))
|
|
16
28
|
end
|
data/lib/jwt/claims_validator.rb
CHANGED
data/lib/jwt/decode.rb
CHANGED
|
@@ -92,13 +92,7 @@ module JWT
|
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
def resolve_allowed_algorithms
|
|
95
|
-
algs = given_algorithms.map
|
|
96
|
-
if Algos.implementation?(alg)
|
|
97
|
-
alg
|
|
98
|
-
else
|
|
99
|
-
Algos.create(alg)
|
|
100
|
-
end
|
|
101
|
-
end
|
|
95
|
+
algs = given_algorithms.map { |alg| JWA.create(alg) }
|
|
102
96
|
|
|
103
97
|
sort_by_alg_header(algs)
|
|
104
98
|
end
|
data/lib/jwt/encode.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '
|
|
3
|
+
require_relative 'jwa'
|
|
4
4
|
require_relative 'claims_validator'
|
|
5
5
|
|
|
6
6
|
# JWT::Encode module
|
|
@@ -12,7 +12,7 @@ module JWT
|
|
|
12
12
|
def initialize(options)
|
|
13
13
|
@payload = options[:payload]
|
|
14
14
|
@key = options[:key]
|
|
15
|
-
@algorithm =
|
|
15
|
+
@algorithm = JWA.create(options[:algorithm])
|
|
16
16
|
@headers = options[:headers].transform_keys(&:to_s)
|
|
17
17
|
@headers[ALG_KEY] = @algorithm.alg
|
|
18
18
|
end
|
|
@@ -24,12 +24,6 @@ module JWT
|
|
|
24
24
|
|
|
25
25
|
private
|
|
26
26
|
|
|
27
|
-
def resolve_algorithm(algorithm)
|
|
28
|
-
return algorithm if Algos.implementation?(algorithm)
|
|
29
|
-
|
|
30
|
-
Algos.create(algorithm)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
27
|
def encoded_header
|
|
34
28
|
@encoded_header ||= encode_header
|
|
35
29
|
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JWT
|
|
4
|
+
module JWA
|
|
5
|
+
module Eddsa
|
|
6
|
+
SUPPORTED = %w[ED25519 EdDSA].freeze
|
|
7
|
+
SUPPORTED_DOWNCASED = SUPPORTED.map(&:downcase).freeze
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def sign(algorithm, msg, key)
|
|
11
|
+
unless key.is_a?(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
|
+
|
|
15
|
+
validate_algorithm!(algorithm)
|
|
16
|
+
|
|
17
|
+
key.sign(msg)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def verify(algorithm, public_key, signing_input, signature)
|
|
21
|
+
unless public_key.is_a?(RbNaCl::Signatures::Ed25519::VerifyKey)
|
|
22
|
+
raise DecodeError, "key given is a #{public_key.class} but has to be a RbNaCl::Signatures::Ed25519::VerifyKey"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
validate_algorithm!(algorithm)
|
|
26
|
+
|
|
27
|
+
public_key.verify(signature, signing_input)
|
|
28
|
+
rescue RbNaCl::CryptoError
|
|
29
|
+
false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def validate_algorithm!(algorithm)
|
|
35
|
+
return if SUPPORTED_DOWNCASED.include?(algorithm.downcase)
|
|
36
|
+
|
|
37
|
+
raise IncorrectAlgorithm, "Algorithm #{algorithm} not supported. Supported algoritms are #{SUPPORTED.join(', ')}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module JWT
|
|
4
|
-
module
|
|
4
|
+
module JWA
|
|
5
5
|
module Hmac
|
|
6
6
|
module_function
|
|
7
7
|
|
|
@@ -44,6 +44,7 @@ module JWT
|
|
|
44
44
|
OpenSSL.fixed_length_secure_compare(a, b)
|
|
45
45
|
end
|
|
46
46
|
else
|
|
47
|
+
# :nocov:
|
|
47
48
|
def fixed_length_secure_compare(a, b)
|
|
48
49
|
raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
|
|
49
50
|
|
|
@@ -53,6 +54,7 @@ module JWT
|
|
|
53
54
|
b.each_byte { |byte| res |= byte ^ l.shift }
|
|
54
55
|
res == 0
|
|
55
56
|
end
|
|
57
|
+
# :nocov:
|
|
56
58
|
end
|
|
57
59
|
module_function :fixed_length_secure_compare
|
|
58
60
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JWT
|
|
4
|
+
module Algos
|
|
5
|
+
module HmacRbNaCl
|
|
6
|
+
MAPPING = { 'HS512256' => ::RbNaCl::HMAC::SHA512256 }.freeze
|
|
7
|
+
SUPPORTED = MAPPING.keys
|
|
8
|
+
class << self
|
|
9
|
+
def sign(algorithm, msg, key)
|
|
10
|
+
warn("[DEPRECATION] The use of the algorithm #{algorithm} is deprecated and will be removed in the next major version of ruby-jwt")
|
|
11
|
+
if (hmac = resolve_algorithm(algorithm))
|
|
12
|
+
hmac.auth(key_for_rbnacl(hmac, key).encode('binary'), msg.encode('binary'))
|
|
13
|
+
else
|
|
14
|
+
Hmac.sign(algorithm, msg, key)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def verify(algorithm, key, signing_input, signature)
|
|
19
|
+
warn("[DEPRECATION] The use of the algorithm #{algorithm} is deprecated and will be removed in the next major version of ruby-jwt")
|
|
20
|
+
if (hmac = resolve_algorithm(algorithm))
|
|
21
|
+
hmac.verify(key_for_rbnacl(hmac, key).encode('binary'), signature.encode('binary'), signing_input.encode('binary'))
|
|
22
|
+
else
|
|
23
|
+
Hmac.verify(algorithm, key, signing_input, signature)
|
|
24
|
+
end
|
|
25
|
+
rescue ::RbNaCl::BadAuthenticatorError, ::RbNaCl::LengthError
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def key_for_rbnacl(hmac, key)
|
|
32
|
+
key ||= ''
|
|
33
|
+
raise JWT::DecodeError, 'HMAC key expected to be a String' unless key.is_a?(String)
|
|
34
|
+
|
|
35
|
+
return padded_empty_key(hmac.key_bytes) if key == ''
|
|
36
|
+
|
|
37
|
+
key
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def resolve_algorithm(algorithm)
|
|
41
|
+
MAPPING.fetch(algorithm)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def padded_empty_key(length)
|
|
45
|
+
Array.new(length, 0x0).pack('C*').encode('binary')
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JWT
|
|
4
|
+
module Algos
|
|
5
|
+
module HmacRbNaClFixed
|
|
6
|
+
MAPPING = { 'HS512256' => ::RbNaCl::HMAC::SHA512256 }.freeze
|
|
7
|
+
SUPPORTED = MAPPING.keys
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def sign(algorithm, msg, key)
|
|
11
|
+
key ||= ''
|
|
12
|
+
warn("[DEPRECATION] The use of the algorithm #{algorithm} is deprecated and will be removed in the next major version of ruby-jwt")
|
|
13
|
+
raise JWT::DecodeError, 'HMAC key expected to be a String' unless key.is_a?(String)
|
|
14
|
+
|
|
15
|
+
if (hmac = resolve_algorithm(algorithm)) && key.bytesize <= hmac.key_bytes
|
|
16
|
+
hmac.auth(padded_key_bytes(key, hmac.key_bytes), msg.encode('binary'))
|
|
17
|
+
else
|
|
18
|
+
Hmac.sign(algorithm, msg, key)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def verify(algorithm, key, signing_input, signature)
|
|
23
|
+
key ||= ''
|
|
24
|
+
warn("[DEPRECATION] The use of the algorithm #{algorithm} is deprecated and will be removed in the next major version of ruby-jwt")
|
|
25
|
+
raise JWT::DecodeError, 'HMAC key expected to be a String' unless key.is_a?(String)
|
|
26
|
+
|
|
27
|
+
if (hmac = resolve_algorithm(algorithm)) && key.bytesize <= hmac.key_bytes
|
|
28
|
+
hmac.verify(padded_key_bytes(key, hmac.key_bytes), signature.encode('binary'), signing_input.encode('binary'))
|
|
29
|
+
else
|
|
30
|
+
Hmac.verify(algorithm, key, signing_input, signature)
|
|
31
|
+
end
|
|
32
|
+
rescue ::RbNaCl::BadAuthenticatorError, ::RbNaCl::LengthError
|
|
33
|
+
false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def resolve_algorithm(algorithm)
|
|
37
|
+
MAPPING.fetch(algorithm)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def padded_key_bytes(key, bytesize)
|
|
41
|
+
key.bytes.fill(0, key.bytesize...bytesize).pack('C*')
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
data/lib/jwt/{algos → jwa}/ps.rb
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module JWT
|
|
4
|
-
module
|
|
4
|
+
module JWA
|
|
5
5
|
module Ps
|
|
6
6
|
# RSASSA-PSS signing algorithms
|
|
7
7
|
|
|
@@ -10,9 +10,9 @@ module JWT
|
|
|
10
10
|
SUPPORTED = %w[PS256 PS384 PS512].freeze
|
|
11
11
|
|
|
12
12
|
def sign(algorithm, msg, key)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
unless key.is_a?(::OpenSSL::PKey::RSA)
|
|
14
|
+
raise EncodeError, "The given key is a #{key_class}. It has to be an OpenSSL::PKey::RSA instance."
|
|
15
|
+
end
|
|
16
16
|
|
|
17
17
|
translated_algorithm = algorithm.sub('PS', 'sha')
|
|
18
18
|
|
|
@@ -20,22 +20,11 @@ module JWT
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def verify(algorithm, public_key, signing_input, signature)
|
|
23
|
-
require_openssl!
|
|
24
23
|
translated_algorithm = algorithm.sub('PS', 'sha')
|
|
25
24
|
public_key.verify_pss(translated_algorithm, signature, signing_input, salt_length: :auto, mgf1_hash: translated_algorithm)
|
|
26
25
|
rescue OpenSSL::PKey::PKeyError
|
|
27
26
|
raise JWT::VerificationError, 'Signature verification raised'
|
|
28
27
|
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
28
|
end
|
|
40
29
|
end
|
|
41
30
|
end
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module JWT
|
|
4
|
-
module
|
|
4
|
+
module JWA
|
|
5
5
|
module Rsa
|
|
6
6
|
module_function
|
|
7
7
|
|
|
8
8
|
SUPPORTED = %w[RS256 RS384 RS512].freeze
|
|
9
9
|
|
|
10
10
|
def sign(algorithm, msg, key)
|
|
11
|
-
|
|
11
|
+
unless key.is_a?(OpenSSL::PKey::RSA)
|
|
12
|
+
raise EncodeError, "The given key is a #{key.class}. It has to be an OpenSSL::PKey::RSA instance"
|
|
13
|
+
end
|
|
12
14
|
|
|
13
15
|
key.sign(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), msg)
|
|
14
16
|
end
|
data/lib/jwt/jwa.rb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
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/hmac'
|
|
12
|
+
require_relative 'jwa/eddsa'
|
|
13
|
+
require_relative 'jwa/ecdsa'
|
|
14
|
+
require_relative 'jwa/rsa'
|
|
15
|
+
require_relative 'jwa/ps'
|
|
16
|
+
require_relative 'jwa/none'
|
|
17
|
+
require_relative 'jwa/unsupported'
|
|
18
|
+
require_relative 'jwa/wrapper'
|
|
19
|
+
|
|
20
|
+
module JWT
|
|
21
|
+
module JWA
|
|
22
|
+
ALGOS = [Hmac, Ecdsa, Rsa, Eddsa, Ps, None, Unsupported].tap do |l|
|
|
23
|
+
if ::JWT.rbnacl_6_or_greater?
|
|
24
|
+
require_relative 'jwa/hmac_rbnacl'
|
|
25
|
+
l << Algos::HmacRbNaCl
|
|
26
|
+
elsif ::JWT.rbnacl?
|
|
27
|
+
require_relative 'jwa/hmac_rbnacl_fixed'
|
|
28
|
+
l << Algos::HmacRbNaClFixed
|
|
29
|
+
end
|
|
30
|
+
end.freeze
|
|
31
|
+
|
|
32
|
+
class << self
|
|
33
|
+
def find(algorithm)
|
|
34
|
+
indexed[algorithm&.downcase]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def create(algorithm)
|
|
38
|
+
return algorithm if JWA.implementation?(algorithm)
|
|
39
|
+
|
|
40
|
+
Wrapper.new(*find(algorithm))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def implementation?(algorithm)
|
|
44
|
+
(algorithm.respond_to?(:valid_alg?) && algorithm.respond_to?(:verify)) ||
|
|
45
|
+
(algorithm.respond_to?(:alg) && algorithm.respond_to?(:sign))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def indexed
|
|
51
|
+
@indexed ||= begin
|
|
52
|
+
fallback = [nil, Unsupported]
|
|
53
|
+
ALGOS.each_with_object(Hash.new(fallback)) do |cls, hash|
|
|
54
|
+
cls.const_get(:SUPPORTED).each do |alg|
|
|
55
|
+
hash[alg.downcase] = [alg, cls]
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
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
|
|
|
@@ -205,12 +205,27 @@ module JWT
|
|
|
205
205
|
end
|
|
206
206
|
end
|
|
207
207
|
|
|
208
|
-
def decode_octets(
|
|
209
|
-
::JWT::Base64.url_decode(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
data/lib/jwt/jwk/key_base.rb
CHANGED
|
@@ -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
|
|
data/lib/jwt/jwk.rb
CHANGED
data/lib/jwt/verify.rb
CHANGED
|
@@ -38,12 +38,12 @@ module JWT
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def verify_expiration
|
|
41
|
-
return unless @payload
|
|
41
|
+
return unless contains_key?(@payload, 'exp')
|
|
42
42
|
raise(JWT::ExpiredSignature, 'Signature has expired') if @payload['exp'].to_i <= (Time.now.to_i - exp_leeway)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def verify_iat
|
|
46
|
-
return unless @payload
|
|
46
|
+
return unless contains_key?(@payload, 'iat')
|
|
47
47
|
|
|
48
48
|
iat = @payload['iat']
|
|
49
49
|
raise(JWT::InvalidIatError, 'Invalid iat') if !iat.is_a?(Numeric) || iat.to_f > Time.now.to_f
|
|
@@ -77,7 +77,7 @@ module JWT
|
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
def verify_not_before
|
|
80
|
-
return unless @payload
|
|
80
|
+
return unless contains_key?(@payload, 'nbf')
|
|
81
81
|
raise(JWT::ImmatureSignature, 'Signature nbf has not been reached') if @payload['nbf'].to_i > (Time.now.to_i + nbf_leeway)
|
|
82
82
|
end
|
|
83
83
|
|
|
@@ -92,7 +92,7 @@ module JWT
|
|
|
92
92
|
return unless (options_required_claims = @options[:required_claims])
|
|
93
93
|
|
|
94
94
|
options_required_claims.each do |required_claim|
|
|
95
|
-
raise(JWT::MissingRequiredClaim, "Missing required claim #{required_claim}") unless @payload
|
|
95
|
+
raise(JWT::MissingRequiredClaim, "Missing required claim #{required_claim}") unless contains_key?(@payload, required_claim)
|
|
96
96
|
end
|
|
97
97
|
end
|
|
98
98
|
|
|
@@ -109,5 +109,9 @@ module JWT
|
|
|
109
109
|
def nbf_leeway
|
|
110
110
|
@options[:nbf_leeway] || global_leeway
|
|
111
111
|
end
|
|
112
|
+
|
|
113
|
+
def contains_key?(payload, key)
|
|
114
|
+
payload.respond_to?(:key?) && payload.key?(key)
|
|
115
|
+
end
|
|
112
116
|
end
|
|
113
117
|
end
|
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 =
|
|
14
|
+
MINOR = 8
|
|
15
15
|
# tiny version
|
|
16
|
-
TINY =
|
|
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
|
-
|
|
26
|
+
|
|
27
|
+
true if 3 * 0x10000000 <= OpenSSL::OPENSSL_VERSION_NUMBER
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
def self.rbnacl?
|
data/lib/jwt/x5c_key_finder.rb
CHANGED
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.
|
|
4
|
+
version: 2.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tim Rudat
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2024-02-17 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,17 +122,6 @@ 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
126
|
- lib/jwt/claims_validator.rb
|
|
110
127
|
- lib/jwt/configuration.rb
|
|
@@ -115,6 +132,17 @@ files:
|
|
|
115
132
|
- lib/jwt/encode.rb
|
|
116
133
|
- lib/jwt/error.rb
|
|
117
134
|
- lib/jwt/json.rb
|
|
135
|
+
- lib/jwt/jwa.rb
|
|
136
|
+
- lib/jwt/jwa/ecdsa.rb
|
|
137
|
+
- lib/jwt/jwa/eddsa.rb
|
|
138
|
+
- lib/jwt/jwa/hmac.rb
|
|
139
|
+
- lib/jwt/jwa/hmac_rbnacl.rb
|
|
140
|
+
- lib/jwt/jwa/hmac_rbnacl_fixed.rb
|
|
141
|
+
- lib/jwt/jwa/none.rb
|
|
142
|
+
- lib/jwt/jwa/ps.rb
|
|
143
|
+
- lib/jwt/jwa/rsa.rb
|
|
144
|
+
- lib/jwt/jwa/unsupported.rb
|
|
145
|
+
- lib/jwt/jwa/wrapper.rb
|
|
118
146
|
- lib/jwt/jwk.rb
|
|
119
147
|
- lib/jwt/jwk/ec.rb
|
|
120
148
|
- lib/jwt/jwk/hmac.rb
|
|
@@ -134,7 +162,7 @@ licenses:
|
|
|
134
162
|
- MIT
|
|
135
163
|
metadata:
|
|
136
164
|
bug_tracker_uri: https://github.com/jwt/ruby-jwt/issues
|
|
137
|
-
changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.
|
|
165
|
+
changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.8.0/CHANGELOG.md
|
|
138
166
|
rubygems_mfa_required: 'true'
|
|
139
167
|
post_install_message:
|
|
140
168
|
rdoc_options: []
|
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, ::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
|
data/lib/jwt/algos.rb
DELETED
|
@@ -1,66 +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/algos/hmac'
|
|
11
|
-
require 'jwt/algos/eddsa'
|
|
12
|
-
require 'jwt/algos/ecdsa'
|
|
13
|
-
require 'jwt/algos/rsa'
|
|
14
|
-
require 'jwt/algos/ps'
|
|
15
|
-
require 'jwt/algos/none'
|
|
16
|
-
require 'jwt/algos/unsupported'
|
|
17
|
-
require 'jwt/algos/algo_wrapper'
|
|
18
|
-
|
|
19
|
-
module JWT
|
|
20
|
-
module Algos
|
|
21
|
-
extend self
|
|
22
|
-
|
|
23
|
-
ALGOS = [Algos::Ecdsa,
|
|
24
|
-
Algos::Rsa,
|
|
25
|
-
Algos::Eddsa,
|
|
26
|
-
Algos::Ps,
|
|
27
|
-
Algos::None,
|
|
28
|
-
Algos::Unsupported].tap do |l|
|
|
29
|
-
if ::JWT.rbnacl_6_or_greater?
|
|
30
|
-
require_relative 'algos/hmac_rbnacl'
|
|
31
|
-
l.unshift(Algos::HmacRbNaCl)
|
|
32
|
-
elsif ::JWT.rbnacl?
|
|
33
|
-
require_relative 'algos/hmac_rbnacl_fixed'
|
|
34
|
-
l.unshift(Algos::HmacRbNaClFixed)
|
|
35
|
-
else
|
|
36
|
-
l.unshift(Algos::Hmac)
|
|
37
|
-
end
|
|
38
|
-
end.freeze
|
|
39
|
-
|
|
40
|
-
def find(algorithm)
|
|
41
|
-
indexed[algorithm && algorithm.downcase]
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def create(algorithm)
|
|
45
|
-
Algos::AlgoWrapper.new(*find(algorithm))
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def implementation?(algorithm)
|
|
49
|
-
(algorithm.respond_to?(:valid_alg?) && algorithm.respond_to?(:verify)) ||
|
|
50
|
-
(algorithm.respond_to?(:alg) && algorithm.respond_to?(:sign))
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
private
|
|
54
|
-
|
|
55
|
-
def indexed
|
|
56
|
-
@indexed ||= begin
|
|
57
|
-
fallback = [nil, Algos::Unsupported]
|
|
58
|
-
ALGOS.each_with_object(Hash.new(fallback)) do |cls, hash|
|
|
59
|
-
cls.const_get(:SUPPORTED).each do |alg|
|
|
60
|
-
hash[alg.downcase] = [alg, cls]
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|