jose 0.2.0 → 0.3.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/.ruby-version +1 -1
- data/.travis.yml +2 -2
- data/CHANGELOG.md +42 -0
- data/README.md +19 -2
- data/jose.gemspec +2 -2
- data/lib/jose.rb +13 -0
- data/lib/jose/jwa/curve25519.rb +5 -4
- data/lib/jose/jwa/curve448.rb +5 -4
- data/lib/jose/jwe.rb +27 -1
- data/lib/jose/jwe/alg.rb +8 -0
- data/lib/jose/jwe/alg_aes_gcm_kw.rb +22 -10
- data/lib/jose/jwe/alg_aes_kw.rb +20 -11
- data/lib/jose/jwe/alg_dir.rb +4 -0
- data/lib/jose/jwe/alg_ecdh_es.rb +8 -0
- data/lib/jose/jwe/alg_pbes2.rb +51 -16
- data/lib/jose/jwe/alg_rsa.rb +23 -15
- data/lib/jose/jwe/enc_aes_cbc_hmac.rb +6 -4
- data/lib/jose/jwe/enc_aes_gcm.rb +2 -0
- data/lib/jose/jwk.rb +37 -3
- data/lib/jose/jwk/kty_ec.rb +47 -8
- data/lib/jose/jwk/kty_oct.rb +45 -19
- data/lib/jose/jwk/kty_okp_ed25519.rb +8 -2
- data/lib/jose/jwk/kty_okp_ed25519ph.rb +8 -2
- data/lib/jose/jwk/kty_okp_ed448.rb +8 -2
- data/lib/jose/jwk/kty_okp_ed448ph.rb +8 -2
- data/lib/jose/jwk/kty_okp_x25519.rb +22 -5
- data/lib/jose/jwk/kty_okp_x448.rb +22 -5
- data/lib/jose/jwk/kty_rsa.rb +16 -7
- data/lib/jose/jws.rb +27 -3
- data/lib/jose/jws/alg.rb +8 -0
- data/lib/jose/jws/alg_ecdsa.rb +13 -0
- data/lib/jose/jws/alg_eddsa.rb +4 -0
- data/lib/jose/jws/alg_hmac.rb +13 -0
- data/lib/jose/jws/alg_none.rb +44 -0
- data/lib/jose/jws/alg_rsa_pkcs1_v1_5.rb +13 -0
- data/lib/jose/jws/alg_rsa_pss.rb +13 -0
- data/lib/jose/jwt.rb +20 -2
- data/lib/jose/version.rb +1 -1
- metadata +7 -6
data/lib/jose/jwk/kty_rsa.rb
CHANGED
@@ -67,11 +67,18 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key)
|
|
67
67
|
|
68
68
|
# JOSE::JWK::KTY callbacks
|
69
69
|
|
70
|
-
def block_encryptor(fields
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
70
|
+
def block_encryptor(fields = nil)
|
71
|
+
if fields and fields['use'] == 'enc' and not fields['alg'].nil? and not fields['enc'].nil?
|
72
|
+
return JOSE::Map[
|
73
|
+
'alg' => fields['alg'],
|
74
|
+
'enc' => fields['enc']
|
75
|
+
]
|
76
|
+
else
|
77
|
+
return JOSE::Map[
|
78
|
+
'alg' => 'RSA-OAEP',
|
79
|
+
'enc' => 'A128GCM'
|
80
|
+
]
|
81
|
+
end
|
75
82
|
end
|
76
83
|
|
77
84
|
def decrypt_private(cipher_text, rsa_padding: :rsa_pkcs1_padding, rsa_oaep_md: nil)
|
@@ -146,8 +153,10 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key)
|
|
146
153
|
end
|
147
154
|
end
|
148
155
|
|
149
|
-
def signer(fields = nil
|
150
|
-
if key.private?
|
156
|
+
def signer(fields = nil)
|
157
|
+
if key.private? and fields and fields['use'] == 'sig' and not fields['alg'].nil?
|
158
|
+
return JOSE::Map['alg' => fields['alg']]
|
159
|
+
elsif key.private?
|
151
160
|
return JOSE::Map['alg' => 'RS256']
|
152
161
|
else
|
153
162
|
raise ArgumentError, "signing not supported for public keys"
|
data/lib/jose/jws.rb
CHANGED
@@ -95,8 +95,7 @@ module JOSE
|
|
95
95
|
|
96
96
|
def self.expand(binary)
|
97
97
|
if binary.is_a?(String)
|
98
|
-
parts = binary.split('.')
|
99
|
-
if parts.length == 3
|
98
|
+
if binary.count('.') == 2 and (parts = binary.split('.', 3)).length == 3
|
100
99
|
protected_binary, payload, signature = parts
|
101
100
|
return JOSE::SignedMap[
|
102
101
|
'payload' => payload,
|
@@ -111,6 +110,32 @@ module JOSE
|
|
111
110
|
end
|
112
111
|
end
|
113
112
|
|
113
|
+
def self.generate_key(object, modules = {})
|
114
|
+
return from(object, modules).generate_key
|
115
|
+
end
|
116
|
+
|
117
|
+
def generate_key
|
118
|
+
return alg.generate_key(fields)
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.merge(left, right)
|
122
|
+
return from(left).merge(right)
|
123
|
+
end
|
124
|
+
|
125
|
+
def merge(object)
|
126
|
+
object = case object
|
127
|
+
when JOSE::Map, Hash
|
128
|
+
object
|
129
|
+
when String
|
130
|
+
JOSE.decode(object)
|
131
|
+
when JOSE::JWS
|
132
|
+
object.to_map
|
133
|
+
else
|
134
|
+
raise ArgumentError, "'object' must be a Hash, String, or JOSE::JWS"
|
135
|
+
end
|
136
|
+
return JOSE::JWS.from_map(self.to_map.merge(object))
|
137
|
+
end
|
138
|
+
|
114
139
|
def self.peek_payload(signed)
|
115
140
|
if signed.is_a?(String)
|
116
141
|
signed = expand(signed)
|
@@ -163,7 +188,6 @@ module JOSE
|
|
163
188
|
end
|
164
189
|
|
165
190
|
def verify(key, plain_text, signature, protected_binary = JOSE.urlsafe_encode64(to_binary))
|
166
|
-
payload = JOSE.urlsafe_encode64(plain_text)
|
167
191
|
signing_input = signing_input(plain_text, protected_binary)
|
168
192
|
return alg.verify(key, signing_input, signature), plain_text, self
|
169
193
|
end
|
data/lib/jose/jws/alg.rb
CHANGED
@@ -2,10 +2,18 @@ module JOSE::JWS::ALG
|
|
2
2
|
|
3
3
|
extend self
|
4
4
|
|
5
|
+
def generate_key(parameters, algorithm)
|
6
|
+
return JOSE::JWK.generate_key(parameters).merge({
|
7
|
+
'alg' => algorithm,
|
8
|
+
'use' => 'sig'
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
5
12
|
end
|
6
13
|
|
7
14
|
require 'jose/jws/alg_ecdsa'
|
8
15
|
require 'jose/jws/alg_eddsa'
|
9
16
|
require 'jose/jws/alg_hmac'
|
17
|
+
require 'jose/jws/alg_none'
|
10
18
|
require 'jose/jws/alg_rsa_pkcs1_v1_5'
|
11
19
|
require 'jose/jws/alg_rsa_pss'
|
data/lib/jose/jws/alg_ecdsa.rb
CHANGED
@@ -30,6 +30,19 @@ class JOSE::JWS::ALG_ECDSA < Struct.new(:digest)
|
|
30
30
|
|
31
31
|
# JOSE::JWS::ALG callbacks
|
32
32
|
|
33
|
+
def generate_key(fields)
|
34
|
+
crv, alg = if digest == OpenSSL::Digest::SHA256
|
35
|
+
['P-256', 'ES256']
|
36
|
+
elsif digest == OpenSSL::Digest::SHA384
|
37
|
+
['P-384', 'ES384']
|
38
|
+
elsif digest == OpenSSL::Digest::SHA512
|
39
|
+
['P-521', 'ES512']
|
40
|
+
else
|
41
|
+
raise ArgumentError, "unhandled ECDSA digest type: #{digest.inspect}"
|
42
|
+
end
|
43
|
+
return JOSE::JWS::ALG.generate_key([:ec, crv], alg)
|
44
|
+
end
|
45
|
+
|
33
46
|
def sign(jwk, message)
|
34
47
|
return jwk.kty.sign(message, digest)
|
35
48
|
end
|
data/lib/jose/jws/alg_eddsa.rb
CHANGED
@@ -24,6 +24,10 @@ class JOSE::JWS::ALG_EDDSA < Struct.new(:sign_type)
|
|
24
24
|
|
25
25
|
# JOSE::JWS::ALG callbacks
|
26
26
|
|
27
|
+
def generate_key(fields)
|
28
|
+
return JOSE::JWS::ALG.generate_key([:okp, sign_type], sign_type.to_s)
|
29
|
+
end
|
30
|
+
|
27
31
|
def sign(jwk, message)
|
28
32
|
return jwk.kty.sign(message, sign_type)
|
29
33
|
end
|
data/lib/jose/jws/alg_hmac.rb
CHANGED
@@ -30,6 +30,19 @@ class JOSE::JWS::ALG_HMAC < Struct.new(:hmac)
|
|
30
30
|
|
31
31
|
# JOSE::JWS::ALG callbacks
|
32
32
|
|
33
|
+
def generate_key(fields)
|
34
|
+
bytesize, alg = if hmac == OpenSSL::Digest::SHA256
|
35
|
+
[32, 'HS256']
|
36
|
+
elsif hmac == OpenSSL::Digest::SHA384
|
37
|
+
[48, 'HS384']
|
38
|
+
elsif hmac == OpenSSL::Digest::SHA512
|
39
|
+
[64, 'HS512']
|
40
|
+
else
|
41
|
+
raise ArgumentError, "unhandled HMAC digest type: #{hmac.inspect}"
|
42
|
+
end
|
43
|
+
return JOSE::JWS::ALG.generate_key([:oct, bytesize], alg)
|
44
|
+
end
|
45
|
+
|
33
46
|
def sign(jwk, message)
|
34
47
|
return jwk.kty.sign(message, hmac)
|
35
48
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class JOSE::JWS::ALG_none < Struct.new(:none)
|
2
|
+
|
3
|
+
# JOSE::JWS callbacks
|
4
|
+
|
5
|
+
def self.from_map(fields)
|
6
|
+
case fields['alg']
|
7
|
+
when 'none'
|
8
|
+
return new(true), fields.delete('alg')
|
9
|
+
else
|
10
|
+
raise ArgumentError, "invalid 'alg' for JWS: #{fields['alg'].inspect}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_map(fields)
|
15
|
+
return fields.put('alg', 'none')
|
16
|
+
end
|
17
|
+
|
18
|
+
# JOSE::JWS::ALG callbacks
|
19
|
+
|
20
|
+
def generate_key(fields)
|
21
|
+
raise NotImplementedError
|
22
|
+
end
|
23
|
+
|
24
|
+
def sign(jwk, message)
|
25
|
+
if JOSE.__unsecured_signing__
|
26
|
+
return ''
|
27
|
+
else
|
28
|
+
raise NotImplementedError
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def verify(jwk, message, signature)
|
33
|
+
if JOSE.__unsecured_signing__
|
34
|
+
if signature == ''
|
35
|
+
return true
|
36
|
+
else
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
else
|
40
|
+
raise NotImplementedError
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -30,6 +30,19 @@ class JOSE::JWS::ALG_RSA_PKCS1_V1_5 < Struct.new(:digest)
|
|
30
30
|
|
31
31
|
# JOSE::JWS::ALG callbacks
|
32
32
|
|
33
|
+
def generate_key(fields)
|
34
|
+
bitsize, alg = if digest == OpenSSL::Digest::SHA256
|
35
|
+
[2048, 'RS256']
|
36
|
+
elsif digest == OpenSSL::Digest::SHA384
|
37
|
+
[3072, 'RS384']
|
38
|
+
elsif digest == OpenSSL::Digest::SHA512
|
39
|
+
[4096, 'RS512']
|
40
|
+
else
|
41
|
+
raise ArgumentError, "unhandled RSA_PKCS1_v1_5 digest type: #{digest.inspect}"
|
42
|
+
end
|
43
|
+
return JOSE::JWS::ALG.generate_key([:rsa, bitsize], alg)
|
44
|
+
end
|
45
|
+
|
33
46
|
def sign(jwk, message)
|
34
47
|
return jwk.kty.sign(message, digest, padding: :rsa_pkcs1_padding)
|
35
48
|
end
|
data/lib/jose/jws/alg_rsa_pss.rb
CHANGED
@@ -30,6 +30,19 @@ class JOSE::JWS::ALG_RSA_PSS < Struct.new(:digest)
|
|
30
30
|
|
31
31
|
# JOSE::JWS::ALG callbacks
|
32
32
|
|
33
|
+
def generate_key(fields)
|
34
|
+
bitsize, alg = if digest == OpenSSL::Digest::SHA256
|
35
|
+
[2048, 'PS256']
|
36
|
+
elsif digest == OpenSSL::Digest::SHA384
|
37
|
+
[3072, 'PS384']
|
38
|
+
elsif digest == OpenSSL::Digest::SHA512
|
39
|
+
[4096, 'PS512']
|
40
|
+
else
|
41
|
+
raise ArgumentError, "unhandled RSA_PSS digest type: #{digest.inspect}"
|
42
|
+
end
|
43
|
+
return JOSE::JWS::ALG.generate_key([:rsa, bitsize], alg)
|
44
|
+
end
|
45
|
+
|
33
46
|
def sign(jwk, message)
|
34
47
|
return jwk.kty.sign(message, digest, padding: :rsa_pkcs1_pss_padding)
|
35
48
|
end
|
data/lib/jose/jwt.rb
CHANGED
@@ -80,7 +80,7 @@ module JOSE
|
|
80
80
|
plain_text = to_binary
|
81
81
|
if jwe.nil?
|
82
82
|
jwk = JOSE::JWK.from(jwk)
|
83
|
-
jwe = jwk.
|
83
|
+
jwe = jwk.block_encryptor
|
84
84
|
end
|
85
85
|
if jwe.is_a?(Hash)
|
86
86
|
jwe = JOSE::Map.new(jwe)
|
@@ -91,6 +91,24 @@ module JOSE
|
|
91
91
|
return JOSE::JWK.block_encrypt(jwk, plain_text, jwe)
|
92
92
|
end
|
93
93
|
|
94
|
+
def self.merge(left, right)
|
95
|
+
return from(left).merge(right)
|
96
|
+
end
|
97
|
+
|
98
|
+
def merge(object)
|
99
|
+
object = case object
|
100
|
+
when JOSE::Map, Hash
|
101
|
+
object
|
102
|
+
when String
|
103
|
+
JOSE.decode(object)
|
104
|
+
when JOSE::JWT
|
105
|
+
object.to_map
|
106
|
+
else
|
107
|
+
raise ArgumentError, "'object' must be a Hash, String, or JOSE::JWT"
|
108
|
+
end
|
109
|
+
return JOSE::JWT.from_map(self.to_map.merge(object))
|
110
|
+
end
|
111
|
+
|
94
112
|
def self.peek_payload(signed)
|
95
113
|
return JOSE::Map.new(JOSE.decode(JOSE::JWS.peek_payload(signed)))
|
96
114
|
end
|
@@ -107,7 +125,7 @@ module JOSE
|
|
107
125
|
plain_text = to_binary
|
108
126
|
if jws.nil?
|
109
127
|
jwk = JOSE::JWK.from(jwk)
|
110
|
-
jws = jwk.
|
128
|
+
jws = jwk.signer
|
111
129
|
end
|
112
130
|
if jws.is_a?(Hash)
|
113
131
|
jws = JOSE::Map.new(jws)
|
data/lib/jose/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jose
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Bennett
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hamster
|
@@ -30,28 +30,28 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.12'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
40
|
+
version: '1.12'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '11.1'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '11.1'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: minitest
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -168,6 +168,7 @@ files:
|
|
168
168
|
- lib/jose/jws/alg_ecdsa.rb
|
169
169
|
- lib/jose/jws/alg_eddsa.rb
|
170
170
|
- lib/jose/jws/alg_hmac.rb
|
171
|
+
- lib/jose/jws/alg_none.rb
|
171
172
|
- lib/jose/jws/alg_rsa_pkcs1_v1_5.rb
|
172
173
|
- lib/jose/jws/alg_rsa_pss.rb
|
173
174
|
- lib/jose/jwt.rb
|