json-jwt 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.

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