jose 0.3.1 → 1.0.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/.travis.yml +5 -0
- data/.yardopts +4 -0
- data/CHANGELOG.md +7 -0
- data/{LICENSE.txt → LICENSE.md} +0 -0
- data/README.md +10 -3
- data/docs/EncryptionAlgorithms.md +55 -0
- data/docs/GettingStarted.md +137 -0
- data/docs/KeyGeneration.md +263 -0
- data/docs/SignatureAlgorithms.md +35 -0
- data/lib/jose.rb +86 -22
- data/lib/jose/jwa.rb +293 -0
- data/lib/jose/jwa/concat_kdf.rb +2 -0
- data/lib/jose/jwa/curve25519_ruby.rb +1 -1
- data/lib/jose/jwa/curve448_ruby.rb +1 -1
- data/lib/jose/jwa/ed448.rb +8 -8
- data/lib/jose/jwe.rb +819 -11
- data/lib/jose/jwe/alg_aes_gcm_kw.rb +1 -1
- data/lib/jose/jwe/alg_aes_kw.rb +1 -1
- data/lib/jose/jwe/alg_dir.rb +4 -4
- data/lib/jose/jwe/alg_ecdh_es.rb +45 -18
- data/lib/jose/jwe/alg_pbes2.rb +3 -3
- data/lib/jose/jwe/alg_rsa.rb +1 -1
- data/lib/jose/jwk.rb +639 -48
- data/lib/jose/jwk/kty_ec.rb +22 -4
- data/lib/jose/jwk/kty_oct.rb +16 -0
- data/lib/jose/jwk/kty_okp_ed25519.rb +36 -0
- data/lib/jose/jwk/kty_okp_ed25519ph.rb +36 -0
- data/lib/jose/jwk/kty_okp_ed448.rb +36 -0
- data/lib/jose/jwk/kty_okp_ed448ph.rb +36 -0
- data/lib/jose/jwk/kty_okp_x25519.rb +28 -0
- data/lib/jose/jwk/kty_okp_x448.rb +28 -0
- data/lib/jose/jwk/kty_rsa.rb +8 -0
- data/lib/jose/jwk/openssh_key.rb +278 -0
- data/lib/jose/jws.rb +486 -21
- data/lib/jose/jws/alg_none.rb +2 -2
- data/lib/jose/jwt.rb +208 -14
- data/lib/jose/version.rb +1 -1
- metadata +9 -3
@@ -0,0 +1,35 @@
|
|
1
|
+
# @title Signature Algorithms
|
2
|
+
|
3
|
+
# Signature Algorithms
|
4
|
+
|
5
|
+
The basic parameters for a {JOSE::JWS JOSE::JWS} header are:
|
6
|
+
|
7
|
+
- `"alg"` **(required)** - Cryptographic Algorithm used to secure the JWS.
|
8
|
+
|
9
|
+
See [RFC 7515](https://tools.ietf.org/html/rfc7515#section-4.1) for more information about other header parameters.
|
10
|
+
|
11
|
+
### `alg` Header Parameter
|
12
|
+
|
13
|
+
Here are the supported options for the `alg` parameter, grouped by similar funcionality:
|
14
|
+
|
15
|
+
- Elliptic Curve Digital Signature Algorithm (ECDSA)
|
16
|
+
- [`ES256`](http://www.rubydoc.info/gems/jose/JOSE/JWS#ECDSA-group)
|
17
|
+
- [`ES384`](http://www.rubydoc.info/gems/jose/JOSE/JWS#ECDSA-group)
|
18
|
+
- [`ES512`](http://www.rubydoc.info/gems/jose/JOSE/JWS#ECDSA-group)
|
19
|
+
- Edwards-curve Digital Signature Algorithm (EdDSA)
|
20
|
+
- [`Ed25519`](http://www.rubydoc.info/gems/jose/JOSE/JWS#EdDSA-25519-group)
|
21
|
+
- [`Ed25519ph`](http://www.rubydoc.info/gems/jose/JOSE/JWS#EdDSA-25519-group)
|
22
|
+
- [`Ed448`](http://www.rubydoc.info/gems/jose/JOSE/JWS#EdDSA-448-group)
|
23
|
+
- [`Ed448ph`](http://www.rubydoc.info/gems/jose/JOSE/JWS#EdDSA-448-group)
|
24
|
+
- HMAC using SHA-2
|
25
|
+
- [`HS256`](http://www.rubydoc.info/gems/jose/JOSE/JWS#HMACSHA2-group)
|
26
|
+
- [`HS384`](http://www.rubydoc.info/gems/jose/JOSE/JWS#HMACSHA2-group)
|
27
|
+
- [`HS512`](http://www.rubydoc.info/gems/jose/JOSE/JWS#HMACSHA2-group)
|
28
|
+
- RSASSA PSS using SHA-2 and MGF1 with SHA-2
|
29
|
+
- [`PS256`](http://www.rubydoc.info/gems/jose/JOSE/JWS#RSASSAPSS-group)
|
30
|
+
- [`PS384`](http://www.rubydoc.info/gems/jose/JOSE/JWS#RSASSAPSS-group)
|
31
|
+
- [`PS512`](http://www.rubydoc.info/gems/jose/JOSE/JWS#RSASSAPSS-group)
|
32
|
+
- RSASSA PKCS#1.5 using SHA-2
|
33
|
+
- [`RS256`](http://www.rubydoc.info/gems/jose/JOSE/JWS#RSASSAPKCS1_5-group)
|
34
|
+
- [`RS384`](http://www.rubydoc.info/gems/jose/JOSE/JWS#RSASSAPKCS1_5-group)
|
35
|
+
- [`RS512`](http://www.rubydoc.info/gems/jose/JOSE/JWS#RSASSAPKCS1_5-group)
|
data/lib/jose.rb
CHANGED
@@ -6,68 +6,129 @@ require 'json'
|
|
6
6
|
require 'openssl'
|
7
7
|
require 'thread'
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
# JOSE stands for JSON Object Signing and Encryption which is a is a set of
|
10
|
+
# standards established by the [JOSE Working Group](https://datatracker.ietf.org/wg/jose).
|
11
|
+
#
|
12
|
+
# JOSE is split into 5 main components:
|
13
|
+
#
|
14
|
+
# * {JOSE::JWA JOSE::JWA} - JSON Web Algorithms (JWA) {https://tools.ietf.org/html/rfc7518 RFC 7518}
|
15
|
+
# * {JOSE::JWE JOSE::JWE} - JSON Web Encryption (JWE) {https://tools.ietf.org/html/rfc7516 RFC 7516}
|
16
|
+
# * {JOSE::JWK JOSE::JWK} - JSON Web Key (JWK) {https://tools.ietf.org/html/rfc7517 RFC 7517}
|
17
|
+
# * {JOSE::JWS JOSE::JWS} - JSON Web Signature (JWS) {https://tools.ietf.org/html/rfc7515 RFC 7515}
|
18
|
+
# * {JOSE::JWT JOSE::JWT} - JSON Web Token (JWT) {https://tools.ietf.org/html/rfc7519 RFC 7519}
|
19
|
+
#
|
20
|
+
# Additional specifications and drafts implemented:
|
21
|
+
#
|
22
|
+
# * JSON Web Key (JWK) Thumbprint [RFC 7638](https://tools.ietf.org/html/rfc7638)
|
23
|
+
# * JWS Unencoded Payload Option [draft-ietf-jose-jws-signing-input-options-04](https://tools.ietf.org/html/draft-ietf-jose-jws-signing-input-options-04)
|
13
24
|
module JOSE
|
14
25
|
|
15
|
-
|
16
|
-
|
26
|
+
# @!visibility private
|
17
27
|
MUTEX = Mutex.new
|
18
28
|
|
29
|
+
# Immutable Map structure based on `Hamster::Hash`.
|
30
|
+
class Map < Hamster::Hash; end
|
31
|
+
|
19
32
|
@__crypto_fallback__ = ENV['JOSE_CRYPTO_FALLBACK'] ? true : false
|
20
33
|
@__unsecured_signing__ = ENV['JOSE_UNSECURED_SIGNING'] ? true : false
|
21
34
|
|
22
|
-
|
35
|
+
# Gets the current Cryptographic Algorithm Fallback state, defaults to `false`.
|
36
|
+
# @return [Boolean]
|
37
|
+
def self.crypto_fallback
|
23
38
|
return @__crypto_fallback__
|
24
39
|
end
|
25
40
|
|
26
|
-
|
41
|
+
# Sets the current Cryptographic Algorithm Fallback state.
|
42
|
+
# @param [Boolean] boolean
|
43
|
+
# @return [Boolean]
|
44
|
+
def self.crypto_fallback=(boolean)
|
27
45
|
boolean = !!boolean
|
28
46
|
MUTEX.synchronize {
|
29
47
|
@__crypto_fallback__ = boolean
|
30
48
|
__config_change__
|
31
49
|
}
|
50
|
+
return boolean
|
32
51
|
end
|
33
52
|
|
34
|
-
|
53
|
+
# Gets the current Curve25519 module used by {JOSE::JWA::Curve25519 JOSE::JWA::Curve25519}, see {.curve25519_module=} for default.
|
54
|
+
# @return [Module]
|
55
|
+
def self.curve25519_module
|
35
56
|
return JOSE::JWA::Curve25519.__implementation__
|
36
57
|
end
|
37
58
|
|
38
|
-
|
39
|
-
|
59
|
+
# Sets the current Curve25519 module used by {JOSE::JWA::Curve25519 JOSE::JWA::Curve25519}.
|
60
|
+
#
|
61
|
+
# Currently supported Curve25519 modules (first found is used as default):
|
62
|
+
#
|
63
|
+
# * {https://github.com/cryptosphere/rbnacl `RbNaCl`}
|
64
|
+
# * {JOSE::JWA::Curve25519_Ruby JOSE::JWA::Curve25519_Ruby} - only supported when {.crypto_fallback} is `true`
|
65
|
+
#
|
66
|
+
# Additional modules that implement the functions specified in {JOSE::JWA::Curve25519 JOSE::JWA::Curve25519} may also be used.
|
67
|
+
# @param [Module] mod
|
68
|
+
# @return [Module]
|
69
|
+
def self.curve25519_module=(mod)
|
70
|
+
JOSE::JWA::Curve25519.__implementation__ = mod
|
40
71
|
end
|
41
72
|
|
42
|
-
|
73
|
+
# Gets the current Curve448 module used by {JOSE::JWA::Curve448 JOSE::JWA::Curve448}, see {.curve25519_module=} for default.
|
74
|
+
# @return [Module]
|
75
|
+
def self.curve448_module
|
43
76
|
return JOSE::JWA::Curve448.__implementation__
|
44
77
|
end
|
45
78
|
|
46
|
-
|
47
|
-
|
79
|
+
# Sets the current Curve448 module used by {JOSE::JWA::Curve448 JOSE::JWA::Curve448}.
|
80
|
+
#
|
81
|
+
# Currently supported Curve448 modules (first found is used as default):
|
82
|
+
#
|
83
|
+
# * {JOSE::JWA::Curve448_Ruby JOSE::JWA::Curve448_Ruby} - only supported when {.crypto_fallback} is `true`
|
84
|
+
#
|
85
|
+
# Additional modules that implement the functions specified in {JOSE::JWA::Curve448 JOSE::JWA::Curve448} may also be used.
|
86
|
+
# @param [Module] mod
|
87
|
+
# @return [Module]
|
88
|
+
def self.curve448_module=(mod)
|
89
|
+
JOSE::JWA::Curve448.__implementation__ = mod
|
48
90
|
end
|
49
91
|
|
50
|
-
|
92
|
+
# Decode JSON binary to a term.
|
93
|
+
# @param [String] binary
|
94
|
+
# @return [Object]
|
95
|
+
def self.decode(binary)
|
51
96
|
return JSON.load(binary)
|
52
97
|
end
|
53
98
|
|
54
|
-
|
99
|
+
# Encode a term to JSON binary and sorts `Hash` and {JOSE::Map JOSE::Map} keys.
|
100
|
+
# @param [Object] term
|
101
|
+
# @return [Object]
|
102
|
+
def self.encode(term)
|
55
103
|
return JSON.dump(sort_maps(term))
|
56
104
|
end
|
57
105
|
|
58
|
-
|
106
|
+
# Gets the current Unsecured Signing state, defaults to `false`.
|
107
|
+
# @return [Boolean]
|
108
|
+
def self.unsecured_signing
|
59
109
|
return @__unsecured_signing__
|
60
110
|
end
|
61
111
|
|
62
|
-
|
112
|
+
# Sets the current Unsecured Signing state.
|
113
|
+
#
|
114
|
+
# Enables/disables the `"none"` algorithm used for signing and verifying.
|
115
|
+
#
|
116
|
+
# See {https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ Critical vulnerabilities in JSON Web Token libraries} for more information.
|
117
|
+
# @param [Boolean] boolean
|
118
|
+
# @return [Boolean]
|
119
|
+
def self.unsecured_signing=(boolean)
|
63
120
|
boolean = !!boolean
|
64
121
|
MUTEX.synchronize {
|
65
122
|
@__unsecured_signing__ = boolean
|
66
123
|
__config_change__
|
67
124
|
}
|
125
|
+
return boolean
|
68
126
|
end
|
69
127
|
|
70
|
-
|
128
|
+
# Returns the Base64Url decoded version of `binary` without padding.
|
129
|
+
# @param [String] binary
|
130
|
+
# @return [String]
|
131
|
+
def self.urlsafe_decode64(binary)
|
71
132
|
case binary.bytesize % 4
|
72
133
|
when 2
|
73
134
|
binary += '=='
|
@@ -77,18 +138,21 @@ module JOSE
|
|
77
138
|
return Base64.urlsafe_decode64(binary)
|
78
139
|
end
|
79
140
|
|
80
|
-
|
141
|
+
# Returns the Base64Url encoded version of `binary` without padding.
|
142
|
+
# @param [String] binary
|
143
|
+
# @return [String]
|
144
|
+
def self.urlsafe_encode64(binary)
|
81
145
|
return Base64.urlsafe_encode64(binary).tr('=', '')
|
82
146
|
end
|
83
147
|
|
84
148
|
private
|
85
149
|
|
86
|
-
def __config_change__
|
150
|
+
def self.__config_change__
|
87
151
|
JOSE::JWA::Curve25519.__config_change__
|
88
152
|
JOSE::JWA::Curve448.__config_change__
|
89
153
|
end
|
90
154
|
|
91
|
-
def sort_maps(term)
|
155
|
+
def self.sort_maps(term)
|
92
156
|
case term
|
93
157
|
when Hash, JOSE::Map
|
94
158
|
return term.keys.sort.each_with_object(Hash.new) do |key, hash|
|
data/lib/jose/jwa.rb
CHANGED
@@ -1,4 +1,19 @@
|
|
1
1
|
module JOSE
|
2
|
+
# JWA stands for JSON Web Algorithms which is defined in [RFC 7518](https://tools.ietf.org/html/rfc7518).
|
3
|
+
#
|
4
|
+
# ## Cryptographic Algorithm Fallback
|
5
|
+
#
|
6
|
+
# Native implementations of all cryptographic and public key algorithms
|
7
|
+
# required by the JWA specifications are not present in current versions
|
8
|
+
# of Ruby.
|
9
|
+
#
|
10
|
+
# JOSE will detect whether a specific algorithm is natively supported or not
|
11
|
+
# and, by default, it will mark the algorithm as unsupported if a native
|
12
|
+
# implementation is not found.
|
13
|
+
#
|
14
|
+
# However, JOSE also has pure Ruby versions of many of the missing algorithms
|
15
|
+
# which can be used as a fallback by calling {JOSE.crypto_fallback= JOSE.crypto_fallback=} and
|
16
|
+
# passing `true`.
|
2
17
|
module JWA
|
3
18
|
|
4
19
|
extend self
|
@@ -6,6 +21,10 @@ module JOSE
|
|
6
21
|
UCHAR_PACK = 'C*'.freeze
|
7
22
|
ZERO_PAD = [0].pack('C').force_encoding('BINARY').freeze
|
8
23
|
|
24
|
+
# Performs a constant time comparison between two binaries to help avoid [timing attacks](https://en.wikipedia.org/wiki/Timing_attack).
|
25
|
+
# @param [String] a
|
26
|
+
# @param [String] b
|
27
|
+
# @return [Boolean]
|
9
28
|
def constant_time_compare(a, b)
|
10
29
|
return false if a.empty? || b.empty? || a.bytesize != b.bytesize
|
11
30
|
l = a.unpack "C#{a.bytesize}"
|
@@ -15,6 +34,7 @@ module JOSE
|
|
15
34
|
return res == 0
|
16
35
|
end
|
17
36
|
|
37
|
+
# @!visibility private
|
18
38
|
def exor(a, b)
|
19
39
|
a = a.to_bn if a.respond_to?(:to_bn)
|
20
40
|
b = b.to_bn if b.respond_to?(:to_bn)
|
@@ -29,6 +49,279 @@ module JOSE
|
|
29
49
|
end.reverse.pack(UCHAR_PACK), 2)
|
30
50
|
end
|
31
51
|
|
52
|
+
# Returns the current listing of supported JOSE algorithms.
|
53
|
+
#
|
54
|
+
# !!!ruby
|
55
|
+
# JOSE::JWA.supports
|
56
|
+
# # => {:jwe=>
|
57
|
+
# # {:alg=>
|
58
|
+
# # ["A128GCMKW",
|
59
|
+
# # "A192GCMKW",
|
60
|
+
# # "A256GCMKW",
|
61
|
+
# # "A128KW",
|
62
|
+
# # "A192KW",
|
63
|
+
# # "A256KW",
|
64
|
+
# # "ECDH-ES",
|
65
|
+
# # "ECDH-ES+A128KW",
|
66
|
+
# # "ECDH-ES+A192KW",
|
67
|
+
# # "ECDH-ES+A256KW",
|
68
|
+
# # "PBES2-HS256+A128KW",
|
69
|
+
# # "PBES2-HS384+A192KW",
|
70
|
+
# # "PBES2-HS512+A256KW",
|
71
|
+
# # "RSA1_5",
|
72
|
+
# # "RSA-OAEP",
|
73
|
+
# # "RSA-OAEP-256",
|
74
|
+
# # "dir"],
|
75
|
+
# # :enc=>
|
76
|
+
# # ["A128GCM",
|
77
|
+
# # "A192GCM",
|
78
|
+
# # "A256GCM",
|
79
|
+
# # "A128CBC-HS256",
|
80
|
+
# # "A192CBC-HS384",
|
81
|
+
# # "A256CBC-HS512"],
|
82
|
+
# # :zip=>
|
83
|
+
# # ["DEF"]},
|
84
|
+
# # :jwk=>
|
85
|
+
# # {:kty=>
|
86
|
+
# # ["EC",
|
87
|
+
# # "OKP",
|
88
|
+
# # "RSA",
|
89
|
+
# # "oct"],
|
90
|
+
# # :kty_EC_crv=>
|
91
|
+
# # ["P-256",
|
92
|
+
# # "P-384",
|
93
|
+
# # "P-521"],
|
94
|
+
# # :kty_OKP_crv=>
|
95
|
+
# # ["Ed25519",
|
96
|
+
# # "Ed25519ph",
|
97
|
+
# # "Ed448",
|
98
|
+
# # "Ed448ph",
|
99
|
+
# # "X25519",
|
100
|
+
# # "X448"]},
|
101
|
+
# # :jws=>
|
102
|
+
# # {:alg=>
|
103
|
+
# # ["Ed25519",
|
104
|
+
# # "Ed25519ph",
|
105
|
+
# # "Ed448",
|
106
|
+
# # "Ed448ph",
|
107
|
+
# # "ES256",
|
108
|
+
# # "ES384",
|
109
|
+
# # "ES512",
|
110
|
+
# # "HS256",
|
111
|
+
# # "HS384",
|
112
|
+
# # "HS512",
|
113
|
+
# # "PS256",
|
114
|
+
# # "PS384",
|
115
|
+
# # "PS512",
|
116
|
+
# # "RS256",
|
117
|
+
# # "RS384",
|
118
|
+
# # "RS512",
|
119
|
+
# # "none"]}}
|
120
|
+
#
|
121
|
+
# @return [Hash]
|
122
|
+
def supports
|
123
|
+
jwe_enc = __jwe_enc_support_check__([
|
124
|
+
'A128GCM',
|
125
|
+
'A192GCM',
|
126
|
+
'A256GCM',
|
127
|
+
'A128CBC-HS256',
|
128
|
+
'A192CBC-HS384',
|
129
|
+
'A256CBC-HS512'
|
130
|
+
])
|
131
|
+
jwe_alg = __jwe_alg_support_check__([
|
132
|
+
['A128GCMKW', :block],
|
133
|
+
['A192GCMKW', :block],
|
134
|
+
['A256GCMKW', :block],
|
135
|
+
['A128KW', :block],
|
136
|
+
['A192KW', :block],
|
137
|
+
['A256KW', :block],
|
138
|
+
['ECDH-ES', :box],
|
139
|
+
['ECDH-ES+A128KW', :box],
|
140
|
+
['ECDH-ES+A192KW', :box],
|
141
|
+
['ECDH-ES+A256KW', :box],
|
142
|
+
['PBES2-HS256+A128KW', :block],
|
143
|
+
['PBES2-HS384+A192KW', :block],
|
144
|
+
['PBES2-HS512+A256KW', :block],
|
145
|
+
['RSA1_5', :rsa],
|
146
|
+
['RSA-OAEP', :rsa],
|
147
|
+
['RSA-OAEP-256', :rsa],
|
148
|
+
['dir', :direct]
|
149
|
+
], jwe_enc)
|
150
|
+
jwe_zip = __jwe_zip_support_check__([
|
151
|
+
'DEF'
|
152
|
+
], jwe_enc)
|
153
|
+
jwk_kty, jwk_kty_EC_crv, jwk_kty_OKP_crv = __jwk_kty_support_check__([
|
154
|
+
['EC', ['P-256', 'P-384', 'P-521']],
|
155
|
+
['OKP', ['Ed25519', 'Ed25519ph', 'Ed448', 'Ed448ph', 'X25519', 'X448']],
|
156
|
+
'RSA',
|
157
|
+
'oct'
|
158
|
+
])
|
159
|
+
jws_alg = __jws_alg_support_check__([
|
160
|
+
'Ed25519',
|
161
|
+
'Ed25519ph',
|
162
|
+
'Ed448',
|
163
|
+
'Ed448ph',
|
164
|
+
'ES256',
|
165
|
+
'ES384',
|
166
|
+
'ES512',
|
167
|
+
'HS256',
|
168
|
+
'HS384',
|
169
|
+
'HS512',
|
170
|
+
'PS256',
|
171
|
+
'PS384',
|
172
|
+
'PS512',
|
173
|
+
'RS256',
|
174
|
+
'RS384',
|
175
|
+
'RS512',
|
176
|
+
'X25519',
|
177
|
+
'X448',
|
178
|
+
'none'
|
179
|
+
])
|
180
|
+
return {
|
181
|
+
jwe: {
|
182
|
+
alg: jwe_alg,
|
183
|
+
enc: jwe_enc,
|
184
|
+
zip: jwe_zip
|
185
|
+
},
|
186
|
+
jwk: {
|
187
|
+
kty: jwk_kty,
|
188
|
+
kty_EC_crv: jwk_kty_EC_crv,
|
189
|
+
kty_OKP_crv: jwk_kty_OKP_crv
|
190
|
+
},
|
191
|
+
jws: {
|
192
|
+
alg: jws_alg
|
193
|
+
}
|
194
|
+
}
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
def __jwe_enc_support_check__(encryption_algorithms)
|
200
|
+
plain_text = SecureRandom.random_bytes(16)
|
201
|
+
return encryption_algorithms.select do |enc|
|
202
|
+
begin
|
203
|
+
jwe = JOSE::JWE.from({ 'alg' => 'dir', 'enc' => enc })
|
204
|
+
jwk = jwe.generate_key
|
205
|
+
cipher_text = jwk.block_encrypt(plain_text).compact
|
206
|
+
next jwk.block_decrypt(cipher_text).first == plain_text
|
207
|
+
rescue StandardError, NotImplementedError
|
208
|
+
next false
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def __jwe_alg_support_check__(key_algorithms, encryption_algorithms)
|
214
|
+
return [] if encryption_algorithms.empty?
|
215
|
+
plain_text = SecureRandom.random_bytes(16)
|
216
|
+
enc = encryption_algorithms[0]
|
217
|
+
rsa = nil
|
218
|
+
return key_algorithms.select do |(alg, strategy)|
|
219
|
+
begin
|
220
|
+
if strategy == :block
|
221
|
+
jwe = JOSE::JWE.from({ 'alg' => alg, 'enc' => enc })
|
222
|
+
jwk = jwe.generate_key
|
223
|
+
cipher_text = jwk.block_encrypt(plain_text).compact
|
224
|
+
next jwk.block_decrypt(cipher_text).first == plain_text
|
225
|
+
elsif strategy == :box
|
226
|
+
jwe = JOSE::JWE.from({ 'alg' => alg, 'enc' => enc })
|
227
|
+
send_jwk = jwe.generate_key
|
228
|
+
recv_jwk = jwe.generate_key
|
229
|
+
cipher_text = recv_jwk.box_encrypt(plain_text, send_jwk).compact
|
230
|
+
next recv_jwk.box_decrypt(cipher_text).first == plain_text
|
231
|
+
elsif strategy == :rsa
|
232
|
+
rsa ||= JOSE::JWK.generate_key([:rsa, 1024])
|
233
|
+
cipher_text = rsa.block_encrypt(plain_text, { 'alg' => alg, 'enc' => enc }).compact
|
234
|
+
next rsa.block_decrypt(cipher_text).first == plain_text
|
235
|
+
elsif strategy == :direct
|
236
|
+
next true
|
237
|
+
else
|
238
|
+
next false
|
239
|
+
end
|
240
|
+
rescue StandardError, NotImplementedError
|
241
|
+
next false
|
242
|
+
end
|
243
|
+
end.transpose.first
|
244
|
+
end
|
245
|
+
|
246
|
+
def __jwe_zip_support_check__(zip_algorithms, encryption_algorithms)
|
247
|
+
return [] if encryption_algorithms.empty?
|
248
|
+
plain_text = SecureRandom.random_bytes(16)
|
249
|
+
alg = 'dir'
|
250
|
+
enc = encryption_algorithms[0]
|
251
|
+
return zip_algorithms.select do |zip|
|
252
|
+
begin
|
253
|
+
jwe = JOSE::JWE.from({ 'alg' => alg, 'enc' => enc, 'zip' => zip })
|
254
|
+
jwk = jwe.generate_key
|
255
|
+
cipher_text = jwk.block_encrypt(plain_text, jwe).compact
|
256
|
+
next jwk.block_decrypt(cipher_text).first == plain_text
|
257
|
+
rescue StandardError, NotImplementedError
|
258
|
+
next false
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def __jwk_kty_support_check__(key_types)
|
264
|
+
kty = []
|
265
|
+
kty_EC_crv = []
|
266
|
+
kty_OKP_crv = []
|
267
|
+
key_types.each do |(key_type, curves)|
|
268
|
+
case key_type
|
269
|
+
when 'EC'
|
270
|
+
curves.each do |curve|
|
271
|
+
begin
|
272
|
+
JOSE::JWK.generate_key([:ec, curve])
|
273
|
+
kty_EC_crv.push(curve)
|
274
|
+
rescue StandardError, NotImplementedError
|
275
|
+
next
|
276
|
+
end
|
277
|
+
end
|
278
|
+
kty.push(key_type) if not kty_EC_crv.empty?
|
279
|
+
when 'OKP'
|
280
|
+
curves.each do |curve|
|
281
|
+
begin
|
282
|
+
JOSE::JWK.generate_key([:okp, curve.to_sym])
|
283
|
+
kty_OKP_crv.push(curve)
|
284
|
+
rescue StandardError, NotImplementedError
|
285
|
+
next
|
286
|
+
end
|
287
|
+
end
|
288
|
+
kty.push(key_type) if not kty_OKP_crv.empty?
|
289
|
+
when 'RSA'
|
290
|
+
begin
|
291
|
+
JOSE::JWK.generate_key([:rsa, 256])
|
292
|
+
kty.push(key_type)
|
293
|
+
rescue StandardError, NotImplementedError
|
294
|
+
# do nothing
|
295
|
+
end
|
296
|
+
when 'oct'
|
297
|
+
begin
|
298
|
+
JOSE::JWK.generate_key([:oct, 8])
|
299
|
+
kty.push(key_type)
|
300
|
+
rescue StandardError, NotImplementedError
|
301
|
+
# do nothing
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
return kty, kty_EC_crv, kty_OKP_crv
|
306
|
+
end
|
307
|
+
|
308
|
+
def __jws_alg_support_check__(signature_algorithms)
|
309
|
+
plain_text = SecureRandom.random_bytes(16)
|
310
|
+
rsa = nil
|
311
|
+
return signature_algorithms.select do |alg|
|
312
|
+
begin
|
313
|
+
jwk = nil
|
314
|
+
jwk ||= JOSE::JWK.generate_key([:oct, 0]).merge({ 'alg' => alg, 'use' => 'sig' }) if alg == 'none'
|
315
|
+
jwk ||= (rsa ||= JOSE::JWK.generate_key([:rsa, 1024])).merge({ 'alg' => alg, 'use' => 'sig' }) if alg.start_with?('RS') or alg.start_with?('PS')
|
316
|
+
jwk ||= JOSE::JWS.generate_key({ 'alg' => alg })
|
317
|
+
signed_text = jwk.sign(plain_text).compact
|
318
|
+
next jwk.verify_strict(signed_text, [alg]).first
|
319
|
+
rescue StandardError, NotImplementedError
|
320
|
+
next false
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
32
325
|
end
|
33
326
|
end
|
34
327
|
|