json-jwt 0.1.5 → 0.1.6

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.

Potentially problematic release.


This version of json-jwt might be problematic. Click here for more details.

@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- json-jwt (0.1.4)
4
+ json-jwt (0.1.5)
5
5
  activesupport (>= 2.3)
6
6
  i18n
7
7
  json (>= 1.4.3)
@@ -24,14 +24,14 @@ GEM
24
24
  json (1.7.3)
25
25
  multi_json (1.3.6)
26
26
  rake (0.9.2.2)
27
- rspec (2.10.0)
28
- rspec-core (~> 2.10.0)
29
- rspec-expectations (~> 2.10.0)
30
- rspec-mocks (~> 2.10.0)
31
- rspec-core (2.10.1)
32
- rspec-expectations (2.10.0)
27
+ rspec (2.11.0)
28
+ rspec-core (~> 2.11.0)
29
+ rspec-expectations (~> 2.11.0)
30
+ rspec-mocks (~> 2.11.0)
31
+ rspec-core (2.11.1)
32
+ rspec-expectations (2.11.1)
33
33
  diff-lcs (~> 1.1.3)
34
- rspec-mocks (2.10.1)
34
+ rspec-mocks (2.11.1)
35
35
  url_safe_base64 (0.2.1)
36
36
  yamler (0.1.0)
37
37
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.5
1
+ 0.1.6
@@ -1,11 +1,41 @@
1
1
  module JSON
2
2
  class JWK < Hash
3
+ class UnknownAlgorighm < JWT::Exception; end
4
+
3
5
  def initialize(public_key, options = {})
4
6
  replace encode(public_key, options)
5
7
  end
6
8
 
7
9
  private
8
10
 
11
+ def ecdsa_curve_name(ecdsa_key)
12
+ case ecdsa_key.group.curve_name
13
+ when 'secp256k1'
14
+ :'P-256'
15
+ when 'secp384r1'
16
+ :'P-384'
17
+ when 'secp521r1'
18
+ :'P-521'
19
+ else
20
+ raise UnknownAlgorighm.new('Unknown ECDSA Curve')
21
+ end
22
+ end
23
+
24
+ def ecdsa_coodinates(ecdsa_key)
25
+ unless @ecdsa_coodinates
26
+ hex = ecdsa_key.public_key.to_bn.to_s(16)
27
+ data_len = hex.length - 2
28
+ type = hex[0,2]
29
+ hex_x = hex[2, data_len/2]
30
+ hex_y = hex[2+data_len/2, data_len/2]
31
+ @ecdsa_coodinates = {
32
+ :x => hex_x,
33
+ :y => hex_y
34
+ }
35
+ end
36
+ @ecdsa_coodinates
37
+ end
38
+
9
39
  def encode(public_key, options = {})
10
40
  hash = case public_key
11
41
  when OpenSSL::PKey::RSA
@@ -14,8 +44,15 @@ module JSON
14
44
  exp: UrlSafeBase64.encode64(public_key.e.to_s(2)),
15
45
  mod: UrlSafeBase64.encode64(public_key.n.to_s(2))
16
46
  }
47
+ when OpenSSL::PKey::EC
48
+ {
49
+ alg: :EC,
50
+ crv: ecdsa_curve_name(public_key),
51
+ x: UrlSafeBase64.encode64(ecdsa_coodinates(public_key)[:x].to_s),
52
+ y: UrlSafeBase64.encode64(ecdsa_coodinates(public_key)[:y].to_s)
53
+ }
17
54
  else
18
- raise "Only RSA is supported now"
55
+ raise UnknownAlgorighm.new('Unknown Algorithm')
19
56
  end
20
57
  hash.merge(options)
21
58
  end
@@ -58,8 +58,9 @@ module JSON
58
58
  private_key = private_key_or_secret
59
59
  private_key.sign digest, signature_base_string
60
60
  when ecdsa?
61
- # TODO
62
- raise NotImplementedError.new
61
+ private_key = private_key_or_secret
62
+ verify_ecdsa_group! private_key
63
+ private_key.dsa_sign_asn1 digest.digest(signature_base_string)
63
64
  else
64
65
  raise InvalidFormat.new('Unknown Signature Algorithm')
65
66
  end
@@ -74,13 +75,27 @@ module JSON
74
75
  public_key = public_key_or_secret
75
76
  public_key.verify digest, signature, signature_base_string
76
77
  when ecdsa?
77
- # TODO
78
- raise NotImplementedError.new
78
+ public_key = public_key_or_secret
79
+ verify_ecdsa_group! public_key
80
+ public_key.dsa_verify_asn1 digest.digest(signature_base_string), signature
79
81
  else
80
82
  raise InvalidFormat.new('Unknown Signature Algorithm')
81
83
  end
82
84
  end
83
85
 
86
+ def verify_ecdsa_group!(key)
87
+ group_name = case digest.digest_length * 8
88
+ when 256
89
+ 'secp256k1'
90
+ when 384
91
+ 'secp384r1'
92
+ when 512
93
+ 'secp521r1'
94
+ end
95
+ key.group = OpenSSL::PKey::EC::Group.new group_name
96
+ key.check_key
97
+ end
98
+
84
99
  def replace(hash_or_jwt)
85
100
  super
86
101
  if hash_or_jwt.is_a? JSON::JWT
@@ -0,0 +1,5 @@
1
+ -----BEGIN EC PRIVATE KEY-----
2
+ MHQCAQEEIAm5+R4izRn6OHBl59IL9ow1txjto6gD21IDdDyhXmOWoAcGBSuBBAAK
3
+ oUQDQgAElSHlYujXQEFMiiuZ1Gb91eXwxTGvTKbBFmzOxTtf0w8CCk1UB6G750Br
4
+ xiIbllGmVmkoiuWKVkxnB9X9nccJtw==
5
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,4 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElSHlYujXQEFMiiuZ1Gb91eXwxTGvTKbB
3
+ FmzOxTtf0w8CCk1UB6G750BrxiIbllGmVmkoiuWKVkxnB9X9nccJtw==
4
+ -----END PUBLIC KEY-----
@@ -0,0 +1,6 @@
1
+ -----BEGIN EC PRIVATE KEY-----
2
+ MIGkAgEBBDB1NRLzYeQa7oRUwWrnQFZOBVqzlyJ9n654/PFjCLJh/A/uGWeECoM2
3
+ 1hXEvp80pqGgBwYFK4EEACKhZANiAASmXMCnIWcrurOGDlechlsWPaFmgfZV2Xj5
4
+ EWbsOew0wb23Kqul+rZHKN8oAFtwVG2LEHN9+GTd9xuZ6KkYuS9AE0LN42bpAveE
5
+ 5RMfogUHM4vRjsewZOik1NOykuOWK9s=
6
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,5 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEplzApyFnK7qzhg5XnIZbFj2hZoH2Vdl4
3
+ +RFm7DnsNMG9tyqrpfq2RyjfKABbcFRtixBzffhk3fcbmeipGLkvQBNCzeNm6QL3
4
+ hOUTH6IFBzOL0Y7HsGTopNTTspLjlivb
5
+ -----END PUBLIC KEY-----
@@ -0,0 +1,7 @@
1
+ -----BEGIN EC PRIVATE KEY-----
2
+ MIHcAgEBBEIBBpwKqvGEZGpE3wX1fDzJjrrM4uXr16WKsijjqjRP8tHdnvr5p2fO
3
+ zrPVyDVbiQDulOhSh9aouunuwmbudKjWvZagBwYFK4EEACOhgYkDgYYABAHDAg/m
4
+ tGuq5xPU7wtJjqhfwxl0YOWN4k2+HhzcE5tpA+oro8fTP3/HfxRh69DoaasxJ+K2
5
+ D2GaLhrGyDxIC9Kv/wFC2BHfJfm1fwSNvPWns4Ui2dUQxdpbYAzxMvWO2LamGuHC
6
+ XKYss1QzKV1sAaenI4Ok1yDZKFa1V2YTeNOIobuCNg==
7
+ -----END EC PRIVATE KEY-----
@@ -0,0 +1,6 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBwwIP5rRrqucT1O8LSY6oX8MZdGDl
3
+ jeJNvh4c3BObaQPqK6PH0z9/x38UYevQ6GmrMSfitg9hmi4axsg8SAvSr/8BQtgR
4
+ 3yX5tX8Ejbz1p7OFItnVEMXaW2AM8TL1jti2phrhwlymLLNUMyldbAGnpyODpNcg
5
+ 2ShWtVdmE3jTiKG7gjY=
6
+ -----END PUBLIC KEY-----
@@ -7,23 +7,36 @@ module SignKeyFixtureHelper
7
7
  File.new(
8
8
  File.join(
9
9
  File.dirname(__FILE__),
10
- '../fixtures/rsa',
11
- "#{file_name}.pem"
10
+ "../fixtures/#{file_name}.pem"
12
11
  )
13
12
  )
14
13
  end
15
14
 
16
- def private_key
17
- OpenSSL::PKey::RSA.new(
18
- pem_file('private_key'),
19
- 'pass-phrase'
20
- )
15
+ def private_key(algorithm = :rsa, options = {})
16
+ case algorithm
17
+ when :rsa
18
+ OpenSSL::PKey::RSA.new(
19
+ pem_file("#{algorithm}/private_key"),
20
+ 'pass-phrase'
21
+ )
22
+ when :ecdsa
23
+ OpenSSL::PKey::EC.new(
24
+ pem_file("#{algorithm}/#{options[:digest_length]}/private_key")
25
+ )
26
+ end
21
27
  end
22
28
 
23
- def public_key
24
- OpenSSL::PKey::RSA.new(
25
- pem_file('public_key')
26
- )
29
+ def public_key(algorithm = :rsa, options = {})
30
+ case algorithm
31
+ when :rsa
32
+ OpenSSL::PKey::RSA.new(
33
+ pem_file("#{algorithm}/public_key")
34
+ )
35
+ when :ecdsa
36
+ OpenSSL::PKey::EC.new(
37
+ pem_file("#{algorithm}/#{options[:digest_length]}/public_key")
38
+ )
39
+ end
27
40
  end
28
41
  end
29
42
 
@@ -1,20 +1,64 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JSON::JWK do
4
- let(:rsa_public_key) { public_key }
5
-
6
4
  context 'when RSA public key given' do
7
- let(:jwk) { JSON::JWK.new rsa_public_key }
5
+ let(:jwk) { JSON::JWK.new public_key }
8
6
  it { jwk.should include :alg, :exp, :mod }
9
7
  its(:alg) { jwk[:alg].should == :RSA }
10
- its(:exp) { jwk[:exp].should == UrlSafeBase64.encode64(rsa_public_key.e.to_s(2)) }
11
- its(:mod) { jwk[:mod].should == UrlSafeBase64.encode64(rsa_public_key.n.to_s(2)) }
8
+ its(:exp) { jwk[:exp].should == UrlSafeBase64.encode64(public_key.e.to_s(2)) }
9
+ its(:mod) { jwk[:mod].should == UrlSafeBase64.encode64(public_key.n.to_s(2)) }
12
10
 
13
11
  context 'when kid/use options given' do
14
- let(:jwk) { JSON::JWK.new rsa_public_key, :kid => '12345', :use => :sig }
12
+ let(:jwk) { JSON::JWK.new public_key, :kid => '12345', :use => :sig }
15
13
  it { jwk.should include :kid, :use }
16
14
  its(:kid) { jwk[:kid].should == '12345' }
17
15
  its(:use) { jwk[:use].should == :sig }
18
16
  end
19
17
  end
18
+
19
+ context 'when ECDSA public key given' do
20
+ let(:expected_coodinates) do
21
+ {
22
+ 256 => {
23
+ :x => 'OTUyMUU1NjJFOEQ3NDA0MTRDOEEyQjk5RDQ2NkZERDVFNUYwQzUzMUFGNENBNkMxMTY2Q0NFQzUzQjVGRDMwRg',
24
+ :y => 'MDIwQTRENTQwN0ExQkJFNzQwNkJDNjIyMUI5NjUxQTY1NjY5Mjg4QUU1OEE1NjRDNjcwN0Q1RkQ5REM3MDlCNw'
25
+ },
26
+ 384 => {
27
+ :x => 'QTY1Q0MwQTcyMTY3MkJCQUIzODYwRTU3OUM4NjVCMTYzREExNjY4MUY2NTVEOTc4RjkxMTY2RUMzOUVDMzRDMUJEQjcyQUFCQTVGQUI2NDcyOERGMjgwMDVCNzA1NDZE',
28
+ :y => 'OEIxMDczN0RGODY0RERGNzFCOTlFOEE5MThCOTJGNDAxMzQyQ0RFMzY2RTkwMkY3ODRFNTEzMUZBMjA1MDczMzhCRDE4RUM3QjA2NEU4QTRENEQzQjI5MkUzOTYyQkRC'
29
+ },
30
+ 512 => {
31
+ :x => 'MDFDMzAyMEZFNkI0NkJBQUU3MTNENEVGMEI0OThFQTg1RkMzMTk3NDYwRTU4REUyNERCRTFFMUNEQzEzOUI2OTAzRUEyQkEzQzdEMzNGN0ZDNzdGMTQ2MUVCRDBFODY5QUIzMTI3RTJCNjBGNjE5QTJFMUFDNkM4M0M0ODBCRDJBRkZG',
32
+ :y => 'MDE0MkQ4MTFERjI1RjlCNTdGMDQ4REJDRjVBN0IzODUyMkQ5RDUxMEM1REE1QjYwMENGMTMyRjU4RUQ4QjZBNjFBRTFDMjVDQTYyQ0IzNTQzMzI5NUQ2QzAxQTdBNzIzODNBNEQ3MjBEOTI4NTZCNTU3NjYxMzc4RDM4OEExQkI4MjM2'
33
+ }
34
+ }
35
+ end
36
+ [256, 384, 512].each do |digest_length|
37
+ describe "EC#{digest_length}" do
38
+ let(:jwk) { JSON::JWK.new public_key(:ecdsa, :digest_length => digest_length) }
39
+ it { jwk.should include :alg, :crv, :x, :y }
40
+ its(:alg) { jwk[:alg].should == :EC }
41
+ its(:x) { jwk[:x].should == expected_coodinates[digest_length][:x] }
42
+ its(:y) { jwk[:y].should == expected_coodinates[digest_length][:y] }
43
+ end
44
+ end
45
+
46
+ describe 'unknown curve' do
47
+ it do
48
+ key = OpenSSL::PKey::EC.new('secp112r2').generate_key
49
+ expect do
50
+ JSON::JWK.new key
51
+ end.to raise_error JSON::JWK::UnknownAlgorighm, 'Unknown ECDSA Curve'
52
+ end
53
+ end
54
+ end
55
+
56
+ describe 'unknown algorithm' do
57
+ it do
58
+ key = OpenSSL::PKey::DSA.generate 256
59
+ expect do
60
+ JSON::JWK.new key
61
+ end.to raise_error JSON::JWK::UnknownAlgorighm, 'Unknown Algorithm'
62
+ end
63
+ end
20
64
  end
@@ -24,10 +24,7 @@ describe JSON::JWS do
24
24
  :HS512 => 'ce-GlHDaNwaHfmAFRGp3QPPKvrpruTug2hC1bf6yNlbuvkMwJw2jFZgq_4wmIPetRdiBy7XFq7rrtmw1Im7tmQ',
25
25
  :RS256 => 'E5VELqAdla2Bx1axc9KFxO0EiCr0Mw6HPYX070qGQ8zA_XmyxGPUZLyyWU_6Cn399W-oYBWO2ynLlr8pqqjP3jXevyCeYeGRVN0HzLYiBebEugNnc3hevr7WV2UzfksWRA-Ux2bDv2sz9p_LGbL33wWNxGDvIlpDyZUul_a48nCipS0riBjkTLTSE8dfBxQTXEF5GEUUu99ot6aBLzUhc25nHXSXogXF6MHK-hAcE7f4v-vJ0lbPbHLVGUopIoxoqe4XjoBpzE5UvhrVl5LYbdjbyJhu5ZIA8GLsgwtUFh3dfdIechORoR3k5NSFSv8157bAEa8t4iwgWD2MSNSQnw',
26
26
  :RS384 => 'lT5JbytGKgG9QrwkJuxgw7UjmN9tjkEQW9pVGR2XnKEdC0_wLNIzAmT-jTwyMDGBLUkWO7opDOP6Xy6_DOTg58k9PwVkyQzrLnmxJMEng2Q-aMqcitRSIvUk3DPy8kemp8yUPls9NzWmByM2GoUVHbDsR0r-tZN-g_9QYev32mvMhjMr30JI5S2xiRjc9m2GAaXMOQmNTovJgV4bgCp4UjruCrA0BD1JJwDqKYoR_YYr_ALcVjD_LUgy80udJvbi8MAYJVUf0QYtQDrX2wnT_-eiiWjD5XafLuXEQVDRh-v2MKAwdvtXMq5cZ08Zjl2SyHxJ3OqhEeWPvYGltxZh_A',
27
- :RS512 => 'EHeGM2Mo3ghhUfSB99AlREehrbC6OPE-nYL_rwf88ysTnJ8L1QQ0UuCrXq4SpRutGLK_bYTK3ZALvFRPoOgK_g0QWmqv6qjQRU_QTxoq8y8APP-IgKKDuIiGH6daBV2rAPLDReqYNKsKjmTvZJo2c0a0e_WZkkj_ZwpgjTG3v0gW9lbDAzLJDz18eqtR4ZO7JTu_fyNrUrNk-w2_wpxSsn9sygIMp0lKE0_pt0b01fz3gjTDjlltU0cKSalUp4geaBDH7QRcexrolIctdQFbNKTXQxoigxD3NLNkKGH7f6A8KZdcOm8AnEjullcZs8_OWGnW43p1qrxoBRSivb9pqQ',
28
- :ES256 => :TODO,
29
- :ES384 => :TODO,
30
- :ES512 => :TODO
27
+ :RS512 => 'EHeGM2Mo3ghhUfSB99AlREehrbC6OPE-nYL_rwf88ysTnJ8L1QQ0UuCrXq4SpRutGLK_bYTK3ZALvFRPoOgK_g0QWmqv6qjQRU_QTxoq8y8APP-IgKKDuIiGH6daBV2rAPLDReqYNKsKjmTvZJo2c0a0e_WZkkj_ZwpgjTG3v0gW9lbDAzLJDz18eqtR4ZO7JTu_fyNrUrNk-w2_wpxSsn9sygIMp0lKE0_pt0b01fz3gjTDjlltU0cKSalUp4geaBDH7QRcexrolIctdQFbNKTXQxoigxD3NLNkKGH7f6A8KZdcOm8AnEjullcZs8_OWGnW43p1qrxoBRSivb9pqQ'
31
28
  }
32
29
  }
33
30
 
@@ -68,16 +65,18 @@ describe JSON::JWS do
68
65
  end
69
66
  end
70
67
 
71
- [:ES256, :ES384, :ES512].each do |algorithm|
72
- describe algorithm do
73
- let(:alg) { algorithm }
74
- it :TODO
68
+ describe 'unknown algorithm' do
69
+ let(:alg) { :unknown }
70
+ it do
71
+ expect do
72
+ jws.sign! 'key'
73
+ end.to raise_error JSON::JWS::InvalidFormat
75
74
  end
76
75
  end
77
76
  end
78
77
 
79
78
  describe '#verify' do
80
- shared_examples_for :succes_signature_verification do
79
+ shared_examples_for :success_signature_verification do
81
80
  it do
82
81
  expect { decoded }.not_to raise_error
83
82
  decoded.should be_a JSON::JWT
@@ -106,7 +105,7 @@ describe JSON::JWS do
106
105
  let(:private_key_or_secret) { shared_secret }
107
106
  let(:public_key_or_secret) { shared_secret }
108
107
  let(:alg) { algorithm }
109
- it_behaves_like :succes_signature_verification
108
+ it_behaves_like :success_signature_verification
110
109
  end
111
110
  end
112
111
 
@@ -115,14 +114,25 @@ describe JSON::JWS do
115
114
  let(:private_key_or_secret) { private_key }
116
115
  let(:public_key_or_secret) { public_key }
117
116
  let(:alg) { algorithm }
118
- it_behaves_like :succes_signature_verification
117
+ it_behaves_like :success_signature_verification
119
118
  end
120
119
  end
121
120
 
122
121
  [:ES256, :ES384, :ES512].each do |algorithm|
123
122
  describe algorithm do
123
+ let(:private_key_or_secret) { private_key(:ecdsa, :digest_length => algorithm.to_s[2,3].to_i) }
124
+ let(:public_key_or_secret) { public_key(:ecdsa, :digest_length => algorithm.to_s[2,3].to_i) }
124
125
  let(:alg) { algorithm }
125
- it :TODO
126
+ it_behaves_like :success_signature_verification
127
+ end
128
+ end
129
+
130
+ describe 'unknown algorithm' do
131
+ let(:alg) { :unknown }
132
+ it do
133
+ expect do
134
+ jws.verify 'signature_base_string', 'signature', 'key'
135
+ end.to raise_error JSON::JWS::InvalidFormat
126
136
  end
127
137
  end
128
138
  end
@@ -81,5 +81,13 @@ describe JSON::JWT do
81
81
  end
82
82
  end
83
83
  end
84
+
85
+ context 'when JSON parse failed' do
86
+ it do
87
+ expect do
88
+ JSON::JWT.decode('header.payload.signature')
89
+ end.to raise_error JSON::JWT::InvalidFormat
90
+ end
91
+ end
84
92
  end
85
93
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json-jwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-20 00:00:00.000000000 Z
12
+ date: 2012-07-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
@@ -146,6 +146,12 @@ files:
146
146
  - lib/json/jwk/set.rb
147
147
  - lib/json/jws.rb
148
148
  - lib/json/jwt.rb
149
+ - spec/fixtures/ecdsa/256/private_key.pem
150
+ - spec/fixtures/ecdsa/256/public_key.pem
151
+ - spec/fixtures/ecdsa/384/private_key.pem
152
+ - spec/fixtures/ecdsa/384/public_key.pem
153
+ - spec/fixtures/ecdsa/512/private_key.pem
154
+ - spec/fixtures/ecdsa/512/public_key.pem
149
155
  - spec/fixtures/rsa/private_key.pem
150
156
  - spec/fixtures/rsa/public_key.pem
151
157
  - spec/helpers/sign_key_fixture_helper.rb
@@ -180,6 +186,12 @@ specification_version: 3
180
186
  summary: JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and
181
187
  JSON Web Key) in Ruby
182
188
  test_files:
189
+ - spec/fixtures/ecdsa/256/private_key.pem
190
+ - spec/fixtures/ecdsa/256/public_key.pem
191
+ - spec/fixtures/ecdsa/384/private_key.pem
192
+ - spec/fixtures/ecdsa/384/public_key.pem
193
+ - spec/fixtures/ecdsa/512/private_key.pem
194
+ - spec/fixtures/ecdsa/512/public_key.pem
183
195
  - spec/fixtures/rsa/private_key.pem
184
196
  - spec/fixtures/rsa/public_key.pem
185
197
  - spec/helpers/sign_key_fixture_helper.rb