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