jwk 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/lib/jwk/asn1.rb +2 -19
- data/lib/jwk/ec_key.rb +60 -8
- data/lib/jwk/key.rb +4 -1
- data/lib/jwk/version.rb +1 -1
- data/spec/jwk/asn1_spec.rb +24 -10
- data/spec/jwk/ec_key_spec.rb +39 -0
- data/spec/jwk/key_spec.rb +37 -2
- metadata +15 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd3ca2360c804b73c1dd58937b3d8d2a3fad3f37
|
4
|
+
data.tar.gz: 658fd06146fd198e7a90f08242f0f31455c4025a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d96770d90c1f246c2d3529e78d3db5de57084d280251a6e0595cc025869bdc41f86170c93606a674dd7a0082d60bf3ca394108530078f608f13326ea8ab3c74
|
7
|
+
data.tar.gz: 5656d037ae9e1bd031aea2082b0806f3ecfe3ff7d43c17b7e95ff73bfe63999489dd81b54aca1fd4d099b53dd423eda31932765cb7191b5be9bf5be259ac53ef
|
data/lib/jwk/asn1.rb
CHANGED
@@ -11,20 +11,14 @@ module JWK
|
|
11
11
|
sequence(integer(0), *args.map { |n| integer(n) })
|
12
12
|
end
|
13
13
|
|
14
|
-
def ec_private_key(crv, d,
|
15
|
-
_, raw_x = raw_integer_encoding(x)
|
16
|
-
_, raw_y = raw_integer_encoding(y)
|
17
|
-
|
18
|
-
raw_x = pad_coord_for_crv(crv, raw_x)
|
19
|
-
raw_y = pad_coord_for_crv(crv, raw_y)
|
20
|
-
|
14
|
+
def ec_private_key(crv, d, raw_public_key)
|
21
15
|
object_id = object_id_for_crv(crv)
|
22
16
|
|
23
17
|
sequence(
|
24
18
|
integer(1),
|
25
19
|
integer_octet_string(d),
|
26
20
|
context_specific(true, 0, object_id),
|
27
|
-
context_specific(true, 1, bit_string(
|
21
|
+
context_specific(true, 1, bit_string(raw_public_key))
|
28
22
|
)
|
29
23
|
end
|
30
24
|
|
@@ -41,17 +35,6 @@ module JWK
|
|
41
35
|
end
|
42
36
|
end
|
43
37
|
|
44
|
-
def pad_coord_for_crv(crv, coord)
|
45
|
-
case crv
|
46
|
-
when 'P-256'
|
47
|
-
coord.rjust(32, "\x00")
|
48
|
-
when 'P-384'
|
49
|
-
coord.rjust(48, "\x00")
|
50
|
-
when 'P-521'
|
51
|
-
coord.rjust(64, "\x00")
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
38
|
def rsa_header
|
56
39
|
"\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00".force_encoding('ASCII-8BIT')
|
57
40
|
end
|
data/lib/jwk/ec_key.rb
CHANGED
@@ -2,6 +2,18 @@ require 'jwk/key'
|
|
2
2
|
|
3
3
|
module JWK
|
4
4
|
class ECKey < Key
|
5
|
+
CURVE_NAMES = {
|
6
|
+
'prime256v1' => 'P-256',
|
7
|
+
'secp384r1' => 'P-384',
|
8
|
+
'secp521r1' => 'P-521'
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
COORD_SIZE = {
|
12
|
+
'P-256' => 32,
|
13
|
+
'P-384' => 48,
|
14
|
+
'P-521' => 64
|
15
|
+
}.freeze
|
16
|
+
|
5
17
|
def initialize(key)
|
6
18
|
@key = key
|
7
19
|
validate
|
@@ -24,12 +36,17 @@ module JWK
|
|
24
36
|
def to_pem
|
25
37
|
raise NotImplementedError, 'Cannot convert an EC public key to PEM.' unless private?
|
26
38
|
|
27
|
-
asn = ASN1.ec_private_key(crv, d,
|
39
|
+
asn = ASN1.ec_private_key(crv, d, raw_public_key)
|
28
40
|
generate_pem('EC PRIVATE', asn)
|
29
41
|
end
|
30
42
|
|
31
43
|
def to_openssl_key
|
32
|
-
|
44
|
+
if private?
|
45
|
+
OpenSSL::PKey.read(to_pem)
|
46
|
+
else
|
47
|
+
group = OpenSSL::PKey::EC::Group.new(self.class::CURVE_NAMES.key(crv))
|
48
|
+
OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(raw_public_key.unpack('H*')[0], 16))
|
49
|
+
end
|
33
50
|
end
|
34
51
|
|
35
52
|
def to_s
|
@@ -46,12 +63,31 @@ module JWK
|
|
46
63
|
end
|
47
64
|
end
|
48
65
|
|
66
|
+
def raw_public_key
|
67
|
+
raw_x = Utils.int_to_binary(x)
|
68
|
+
raw_y = Utils.int_to_binary(y)
|
69
|
+
|
70
|
+
raw_x = pad_coord_for_crv(crv, raw_x)
|
71
|
+
raw_y = pad_coord_for_crv(crv, raw_y)
|
72
|
+
|
73
|
+
"\x04#{raw_x}#{raw_y}"
|
74
|
+
end
|
75
|
+
|
49
76
|
class << self
|
50
77
|
def from_openssl(k)
|
51
|
-
|
78
|
+
if k.is_a? OpenSSL::PKey::EC::Point
|
79
|
+
from_openssl_public(k)
|
80
|
+
else
|
81
|
+
from_openssl_private(k)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
52
86
|
|
53
|
-
|
54
|
-
|
87
|
+
def from_openssl_private(k)
|
88
|
+
x, y = coords_from_point(k.public_key)
|
89
|
+
|
90
|
+
crv = CURVE_NAMES[k.group.curve_name]
|
55
91
|
|
56
92
|
raise NotImplementedError, "Unsupported EC curve type #{k.group.curve_name}" unless crv
|
57
93
|
|
@@ -60,10 +96,20 @@ module JWK
|
|
60
96
|
'd' => Utils.encode_ub64_int(k.private_key.to_i), 'x' => x, 'y' => y)
|
61
97
|
end
|
62
98
|
|
63
|
-
|
99
|
+
def from_openssl_public(k)
|
100
|
+
x, y = coords_from_point(k)
|
64
101
|
|
65
|
-
|
66
|
-
|
102
|
+
crv = CURVE_NAMES[k.group.curve_name]
|
103
|
+
|
104
|
+
raise NotImplementedError, "Unsupported EC curve type #{k.group.curve_name}" unless crv
|
105
|
+
|
106
|
+
new('kty' => 'EC',
|
107
|
+
'crv' => crv,
|
108
|
+
'x' => x, 'y' => y)
|
109
|
+
end
|
110
|
+
|
111
|
+
def coords_from_point(point)
|
112
|
+
pb = point.to_bn.to_s(16)
|
67
113
|
|
68
114
|
raise NotImplementedError, 'Cannot convert EC compressed public key' unless pb[0..1] == '04'
|
69
115
|
|
@@ -75,5 +121,11 @@ module JWK
|
|
75
121
|
coords.map { |c| Base64.urlsafe_encode64(Utils.hex_string_to_binary(c)) }
|
76
122
|
end
|
77
123
|
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def pad_coord_for_crv(crv, coord)
|
128
|
+
coord.rjust(self.class::COORD_SIZE[crv], "\x00")
|
129
|
+
end
|
78
130
|
end
|
79
131
|
end
|
data/lib/jwk/key.rb
CHANGED
@@ -3,13 +3,16 @@ module JWK
|
|
3
3
|
class << self
|
4
4
|
def from_pem(pem)
|
5
5
|
key = OpenSSL::PKey.read(pem)
|
6
|
+
if defined?(OpenSSL::PKey::EC) && key.is_a?(OpenSSL::PKey::EC)
|
7
|
+
$stderr.puts('WARNING: EC Keys have bugs on jRuby') if defined?(JRUBY_VERSION)
|
8
|
+
end
|
6
9
|
from_openssl(key)
|
7
10
|
end
|
8
11
|
|
9
12
|
def from_openssl(key)
|
10
13
|
if key.is_a?(OpenSSL::PKey::RSA)
|
11
14
|
RSAKey.from_openssl(key)
|
12
|
-
elsif key.is_a?(OpenSSL::PKey::EC)
|
15
|
+
elsif key.is_a?(OpenSSL::PKey::EC) || key.is_a?(OpenSSL::PKey::EC::Point)
|
13
16
|
ECKey.from_openssl(key)
|
14
17
|
end
|
15
18
|
end
|
data/lib/jwk/version.rb
CHANGED
data/spec/jwk/asn1_spec.rb
CHANGED
@@ -41,36 +41,50 @@ describe JWK::ASN1 do
|
|
41
41
|
|
42
42
|
describe '.ec_private_key' do
|
43
43
|
let(:known_p256_asn) do
|
44
|
-
Base64.decode64('MFgCAQEEAaCgCgYIKoZIzj0DAQehRANCAAQAAAAAAAAAAAAAAAAAAAAA'
|
45
|
-
'AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
|
44
|
+
Base64.decode64('MFgCAQEEAaCgCgYIKoZIzj0DAQehRANCAAQAAAAAAAAAAAAAAAAAAAAA' \
|
45
|
+
'AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' \
|
46
46
|
'AAAAAAAD')
|
47
47
|
end
|
48
48
|
|
49
49
|
let(:known_p384_asn) do
|
50
|
-
Base64.decode64('MHUCAQEEAaCgBwYFK4EEACKhZANiAAQAAAAAAAAAAAAAAAAAAAAAAAAA'
|
51
|
-
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAA'
|
50
|
+
Base64.decode64('MHUCAQEEAaCgBwYFK4EEACKhZANiAAQAAAAAAAAAAAAAAAAAAAAAAAAA' \
|
51
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAA' \
|
52
52
|
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM=')
|
53
53
|
end
|
54
54
|
|
55
55
|
let(:known_p521_asn) do
|
56
|
-
Base64.decode64('MIGXAgEBBAGgoAcGBSuBBAAjoYGFA4GCAAQAAAAAAAAAAAAAAAAAAAAA'
|
57
|
-
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
|
58
|
-
'AAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
|
56
|
+
Base64.decode64('MIGXAgEBBAGgoAcGBSuBBAAjoYGFA4GCAAQAAAAAAAAAAAAAAAAAAAAA' \
|
57
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' \
|
58
|
+
'AAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' \
|
59
59
|
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw==')
|
60
60
|
end
|
61
61
|
|
62
|
+
def pad_coord_for_crv(crv, coord)
|
63
|
+
coord.rjust(JWK::ECKey::COORD_SIZE[crv], "\x00")
|
64
|
+
end
|
65
|
+
|
66
|
+
def raw_public_key(crv, x, y)
|
67
|
+
raw_x = JWK::Utils.int_to_binary(x)
|
68
|
+
raw_y = JWK::Utils.int_to_binary(y)
|
69
|
+
|
70
|
+
raw_x = pad_coord_for_crv(crv, raw_x)
|
71
|
+
raw_y = pad_coord_for_crv(crv, raw_y)
|
72
|
+
|
73
|
+
"\x04#{raw_x}#{raw_y}"
|
74
|
+
end
|
75
|
+
|
62
76
|
it 'generates valid ASN1 for a P-256 EC Private Key' do
|
63
|
-
result = JWK::ASN1.ec_private_key('P-256', 0xA0, 2, 3)
|
77
|
+
result = JWK::ASN1.ec_private_key('P-256', 0xA0, raw_public_key('P-256', 2, 3))
|
64
78
|
expect(result).to eq(known_p256_asn)
|
65
79
|
end
|
66
80
|
|
67
81
|
it 'generates valid ASN1 for a P-384 EC Private Key' do
|
68
|
-
result = JWK::ASN1.ec_private_key('P-384', 0xA0, 2, 3)
|
82
|
+
result = JWK::ASN1.ec_private_key('P-384', 0xA0, raw_public_key('P-384', 2, 3))
|
69
83
|
expect(result).to eq(known_p384_asn)
|
70
84
|
end
|
71
85
|
|
72
86
|
it 'generates valid ASN1 for a P-521 EC Private Key' do
|
73
|
-
result = JWK::ASN1.ec_private_key('P-521', 0xA0, 2, 3)
|
87
|
+
result = JWK::ASN1.ec_private_key('P-521', 0xA0, raw_public_key('P-521', 2, 3))
|
74
88
|
expect(result).to eq(known_p521_asn)
|
75
89
|
end
|
76
90
|
end
|
data/spec/jwk/ec_key_spec.rb
CHANGED
@@ -47,6 +47,45 @@ describe JWK::ECKey do
|
|
47
47
|
raise e unless defined?(JRUBY_VERSION)
|
48
48
|
end
|
49
49
|
end
|
50
|
+
|
51
|
+
it 'converts the public keys to an openssl point' do
|
52
|
+
key = JWK::Key.from_json(public_jwk)
|
53
|
+
|
54
|
+
begin
|
55
|
+
expect(key.to_openssl_key).to be_a OpenSSL::PKey::EC::Point
|
56
|
+
rescue Exception => e
|
57
|
+
# This is expected to fail on old jRuby versions
|
58
|
+
raise e unless defined?(JRUBY_VERSION)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# See: http://blogs.adobe.com/security/2017/03/critical-vulnerability-uncovered-in-json-encryption.html
|
63
|
+
# See: https://github.com/asanso/jwe-sender/blob/master/jwe-sender.js
|
64
|
+
it 'is protected against Invalid Curve Attack' do
|
65
|
+
k1 = {
|
66
|
+
'kty' => 'EC',
|
67
|
+
'x' => 'WJiccv00-OX6udOeWKfiRhZzzkoAnfG9JOIDprQYpH8', 'y' => 'tAjB2i8hs-7i6GLRcgMTtCoPbybmoPRWhS9qUBf2ldc',
|
68
|
+
'crv' => 'P-256'
|
69
|
+
}.to_json
|
70
|
+
|
71
|
+
k2 = {
|
72
|
+
'kty' => 'EC',
|
73
|
+
'x' => 'XOXGQ9_6QCvBg3u8vCI-UdBvICAEcNNBrfqd7tG7oQ4', 'y' => 'hQoWNotnNzKlwiCneJkLIqDnTNw7IsdBC53VUqVjVJc',
|
74
|
+
'crv' => 'P-256'
|
75
|
+
}.to_json
|
76
|
+
|
77
|
+
jwk1 = JWK::Key.from_json(k1)
|
78
|
+
jwk2 = JWK::Key.from_json(k2)
|
79
|
+
|
80
|
+
begin
|
81
|
+
expect { jwk1.to_openssl_key }.to raise_error(OpenSSL::PKey::EC::Point::Error)
|
82
|
+
expect { jwk2.to_openssl_key }.to raise_error(OpenSSL::PKey::EC::Point::Error)
|
83
|
+
rescue NameError => e
|
84
|
+
# This is expected to fail on old jRuby versions
|
85
|
+
# Not because it's unsafe, but because EC were not implemented.
|
86
|
+
raise e unless defined?(JRUBY_VERSION)
|
87
|
+
end
|
88
|
+
end
|
50
89
|
end
|
51
90
|
|
52
91
|
describe '#to_json' do
|
data/spec/jwk/key_spec.rb
CHANGED
@@ -27,7 +27,7 @@ describe JWK::Key do
|
|
27
27
|
expect(jwk.to_pem).to eq key.to_pem
|
28
28
|
end
|
29
29
|
|
30
|
-
it 'creates an ECKey for EC keys' do
|
30
|
+
it 'creates an ECKey for EC private keys' do
|
31
31
|
begin
|
32
32
|
key = OpenSSL::PKey::EC.new('secp384r1')
|
33
33
|
key.generate_key
|
@@ -42,7 +42,7 @@ describe JWK::Key do
|
|
42
42
|
# jRuby 9k OpenSSL generates a bad PEM file with private key only, skipping
|
43
43
|
# the public part. This is in contrast with all other OpenSSL implementations.
|
44
44
|
# And it makes this test fail.
|
45
|
-
it 'creates an ECKey for EC keys that resolves to the same parameters' do
|
45
|
+
it 'creates an ECKey for EC private keys that resolves to the same parameters' do
|
46
46
|
begin
|
47
47
|
key = OpenSSL::PKey::EC.new('secp384r1')
|
48
48
|
key.generate_key
|
@@ -53,6 +53,30 @@ describe JWK::Key do
|
|
53
53
|
raise e unless defined?(JRUBY_VERSION)
|
54
54
|
end
|
55
55
|
end
|
56
|
+
|
57
|
+
it 'creates an ECKey for EC public keys' do
|
58
|
+
begin
|
59
|
+
key = OpenSSL::PKey::EC.new('secp384r1')
|
60
|
+
key.generate_key
|
61
|
+
jwk = JWK::Key.from_openssl(key.public_key)
|
62
|
+
|
63
|
+
expect(jwk).to be_a JWK::ECKey
|
64
|
+
rescue NameError => e
|
65
|
+
raise e unless defined?(JRUBY_VERSION)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'creates an ECKey for EC public keys that resolves to the same parameters' do
|
70
|
+
begin
|
71
|
+
key = OpenSSL::PKey::EC.new('secp384r1')
|
72
|
+
key.generate_key
|
73
|
+
jwk = JWK::Key.from_openssl(key.public_key)
|
74
|
+
|
75
|
+
expect(jwk.to_openssl_key).to eq key.public_key
|
76
|
+
rescue NameError => e
|
77
|
+
raise e unless defined?(JRUBY_VERSION)
|
78
|
+
end
|
79
|
+
end
|
56
80
|
end
|
57
81
|
|
58
82
|
describe '.from_pem' do
|
@@ -62,5 +86,16 @@ describe JWK::Key do
|
|
62
86
|
|
63
87
|
expect(jwk).to be_a JWK::RSAKey
|
64
88
|
end
|
89
|
+
|
90
|
+
it 'generates an ECKey for EC Keys' do
|
91
|
+
begin
|
92
|
+
pem = OpenSSL::PKey::EC.new('prime256v1').generate_key.to_pem
|
93
|
+
jwk = JWK::Key.from_pem(pem)
|
94
|
+
|
95
|
+
expect(jwk).to be_a JWK::ECKey
|
96
|
+
rescue ArgumentError, NameError => e
|
97
|
+
raise e unless defined?(JRUBY_VERSION)
|
98
|
+
end
|
99
|
+
end
|
65
100
|
end
|
66
101
|
end
|
metadata
CHANGED
@@ -1,66 +1,66 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jwk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Francesco Boffa
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-11-
|
11
|
+
date: 2017-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name: rspec
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
16
15
|
requirements:
|
17
16
|
- - ">="
|
18
17
|
- !ruby/object:Gem::Version
|
19
18
|
version: '0'
|
20
|
-
|
19
|
+
name: rspec
|
21
20
|
prerelease: false
|
21
|
+
type: :development
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
30
29
|
requirements:
|
31
30
|
- - ">="
|
32
31
|
- !ruby/object:Gem::Version
|
33
32
|
version: '0'
|
34
|
-
|
33
|
+
name: rake
|
35
34
|
prerelease: false
|
35
|
+
type: :development
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name: simplecov
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
44
43
|
requirements:
|
45
44
|
- - ">="
|
46
45
|
- !ruby/object:Gem::Version
|
47
46
|
version: '0'
|
48
|
-
|
47
|
+
name: simplecov
|
49
48
|
prerelease: false
|
49
|
+
type: :development
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name: codeclimate-test-reporter
|
57
56
|
requirement: !ruby/object:Gem::Requirement
|
58
57
|
requirements:
|
59
58
|
- - ">="
|
60
59
|
- !ruby/object:Gem::Version
|
61
60
|
version: '0'
|
62
|
-
|
61
|
+
name: codeclimate-test-reporter
|
63
62
|
prerelease: false
|
63
|
+
type: :development
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|
@@ -114,7 +114,7 @@ homepage: https://github.com/aomega08/jwk
|
|
114
114
|
licenses:
|
115
115
|
- MIT
|
116
116
|
metadata: {}
|
117
|
-
post_install_message:
|
117
|
+
post_install_message:
|
118
118
|
rdoc_options: []
|
119
119
|
require_paths:
|
120
120
|
- lib
|
@@ -129,9 +129,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
129
|
- !ruby/object:Gem::Version
|
130
130
|
version: '0'
|
131
131
|
requirements: []
|
132
|
-
rubyforge_project:
|
133
|
-
rubygems_version: 2.
|
134
|
-
signing_key:
|
132
|
+
rubyforge_project:
|
133
|
+
rubygems_version: 2.4.8
|
134
|
+
signing_key:
|
135
135
|
specification_version: 4
|
136
136
|
summary: JSON Web Keys implementation in Ruby
|
137
137
|
test_files: []
|