json-jwt 0.4.3 → 0.5.0

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7ceb3e0a69a5e8f2438b047292633deeaed004fc
4
- data.tar.gz: 4ced84fac0f2abcbae8316681396d155bbb77c94
3
+ metadata.gz: 7fc22bebad1c3924998f637b07f91089ba1d365f
4
+ data.tar.gz: 8f969eba9420ffccaeb0053096e039c02fbcfb89
5
5
  SHA512:
6
- metadata.gz: afa51d9f7ee2598ead577a749cfb68eabf40d2cf8a1b1af57bde198cf86685849a734923e1ee42062709bb8721cf2e3ad24b8c14c5b3d1f6e22f34250d94356e
7
- data.tar.gz: e6203a40b7cae834abd3293a377dba377331e15d7fbe69ac87f4a151f96730011b46fbfe5e95986e19cf96f4a7c94b2a484fac647d782fe7f5a1b257d13173fc
6
+ metadata.gz: a32887bed2783fb91c98776c70e6a471a6640f59b336b56d4a5576019ab79cdbdbb25bcf149bf26d4710006f03a0699c4dae0137ab61d3895ded29dbd38cdfa2
7
+ data.tar.gz: 44ee98be92413ef444c90d93529566802a0725a182e55517d5ecea8e8b7b66b5d3386e3dccf7d3b67e728c038ca336f42a2bcf3837ffd2c5c20a2f73b5f0bcfc
data/.gitignore CHANGED
@@ -19,3 +19,4 @@ rdoc
19
19
  pkg
20
20
 
21
21
  ## PROJECT::SPECIFIC
22
+ .class
@@ -0,0 +1,3 @@
1
+ [submodule "spec/helpers/json-jwt-nimbus"]
2
+ path = spec/helpers/json-jwt-nimbus
3
+ url = git://github.com/nov/json-jwt-nimbus.git
@@ -1,3 +1,7 @@
1
1
  rvm:
2
2
  - 1.9.2
3
3
  - 1.9.3
4
+ - 2.0.0
5
+
6
+ before_install:
7
+ - git submodule update --init --recursive
@@ -0,0 +1,44 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ json-jwt (0.4.3)
5
+ activesupport (>= 2.3)
6
+ i18n
7
+ multi_json (>= 1.3)
8
+ url_safe_base64
9
+
10
+ GEM
11
+ remote: http://rubygems.org/
12
+ specs:
13
+ activesupport (3.2.12)
14
+ i18n (~> 0.6)
15
+ multi_json (~> 1.0)
16
+ configatron (2.10.0)
17
+ yamler (>= 0.1.0)
18
+ cover_me (1.2.0)
19
+ configatron
20
+ hashie
21
+ diff-lcs (1.2.1)
22
+ hashie (2.0.2)
23
+ i18n (0.6.4)
24
+ multi_json (1.6.1)
25
+ rake (10.0.3)
26
+ rspec (2.13.0)
27
+ rspec-core (~> 2.13.0)
28
+ rspec-expectations (~> 2.13.0)
29
+ rspec-mocks (~> 2.13.0)
30
+ rspec-core (2.13.0)
31
+ rspec-expectations (2.13.0)
32
+ diff-lcs (>= 1.1.3, < 2.0)
33
+ rspec-mocks (2.13.0)
34
+ url_safe_base64 (0.2.1)
35
+ yamler (0.1.0)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ cover_me (>= 1.2.0)
42
+ json-jwt!
43
+ rake (>= 0.8)
44
+ rspec (>= 2)
@@ -2,6 +2,8 @@
2
2
 
3
3
  JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON Web Key) in Ruby
4
4
 
5
+ {<img src="https://secure.travis-ci.org/nov/json-jwt.png" />}[http://travis-ci.org/nov/json-jwt]
6
+
5
7
  == Installation
6
8
 
7
9
  gem install json-jwt
@@ -24,15 +26,19 @@ JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON
24
26
  }
25
27
 
26
28
  # No signature, no encryption
27
- JSON::JWT.new(claim).to_s
29
+ jwt = JSON::JWT.new(claim).to_s
28
30
 
29
31
  # With signiture, no encryption
30
- JSON::JWT.new(claim).sign(key, algorithm).to_s
32
+ jws = JSON::JWT.new(claim).sign(key, algorithm) # algorithm is optional. default HS256
33
+ jws.to_s # => header.payload.signature
31
34
 
32
35
  # With signature & encryption
33
- JSON::JWT.new(claim).sign(key, algorithm).encrypt(key, algorithm).to_s
36
+ jwe = jws.encrypt(key, algorithm, encryption_method) # algorithm & encryption_method are optional. default RSA1_5 & A128CBC+HS256
37
+ jws.to_s # => header.master_key.iv.cipher_text.integrity_value
34
38
 
35
- For details about <code>key</code> and <code>algorithm</code>, see {JWS Spec}[https://github.com/nov/json-jwt/blob/master/spec/json/jws_spec.rb] and {Sign Key Fixture Generator}[https://github.com/nov/json-jwt/blob/master/spec/helpers/sign_key_fixture_helper.rb].
39
+ For details about <code>key</code> and <code>algorithm</code>, see
40
+ {JWS Spec}[https://github.com/nov/json-jwt/blob/master/spec/json/jws_spec.rb] and
41
+ {Sign Key Fixture Generator}[https://github.com/nov/json-jwt/blob/master/spec/helpers/sign_key_fixture_helper.rb].
36
42
 
37
43
  === Decoding
38
44
 
@@ -41,7 +47,7 @@ For details about <code>key</code> and <code>algorithm</code>, see {JWS Spec}[ht
41
47
  JSON::JWT.decode(jwt_string, key)
42
48
 
43
49
  == Note on Patches/Pull Requests
44
-
50
+
45
51
  * Fork the project.
46
52
  * Make your feature addition or bug fix.
47
53
  * Add tests for it. This is important so I don't break it in a
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.3
1
+ 0.5.0
@@ -14,6 +14,7 @@ Gem::Specification.new do |s|
14
14
  s.add_runtime_dependency "url_safe_base64"
15
15
  s.add_runtime_dependency "activesupport", ">= 2.3"
16
16
  s.add_runtime_dependency "i18n"
17
+ s.add_runtime_dependency "bindata"
17
18
  s.add_development_dependency "rake", ">= 0.8"
18
19
  s.add_development_dependency "cover_me", ">= 1.2.0"
19
20
  s.add_development_dependency "rspec", ">= 2"
@@ -1,5 +1,208 @@
1
+ require 'securerandom'
2
+ require 'bindata'
3
+
1
4
  module JSON
2
5
  class JWE < JWT
3
- # TODO
6
+ class InvalidFormat < JWT::InvalidFormat; end
7
+ class DecryptionFailed < JWT::VerificationFailed; end
8
+ class UnexpectedAlgorithm < JWT::UnexpectedAlgorithm; end
9
+
10
+ attr_accessor :public_key_or_secret, :plain_text, :master_key, :encrypted_master_key, :encryption_key, :integrity_key, :integrity_value, :iv, :cipher_text
11
+
12
+ register_header_keys :enc, :epk, :zip, :jku, :jwk, :x5u, :x5t, :x5c, :kid, :typ, :cty, :apu, :apv, :epu, :epv
13
+ alias_method :encryption_method, :enc
14
+
15
+ def initialize(jwt_or_plain_text)
16
+ self.plain_text = jwt_or_plain_text.to_s
17
+ end
18
+
19
+ def encrypt!(public_key_or_secret)
20
+ self.public_key_or_secret = public_key_or_secret
21
+ cipher.encrypt
22
+ generate_cipher_keys!
23
+ self.cipher_text = cipher.update(plain_text) + cipher.final
24
+ self
25
+ end
26
+
27
+ def decrypt!
28
+ raise NotImplementedError.new('JWE decryption not supported yet')
29
+ end
30
+
31
+ def to_s
32
+ [
33
+ header.to_json,
34
+ encrypted_master_key,
35
+ iv,
36
+ cipher_text,
37
+ integrity_value
38
+ ].collect do |segment|
39
+ UrlSafeBase64.encode64 segment.to_s
40
+ end.join('.')
41
+ end
42
+
43
+ private
44
+
45
+ def gcm_supported?
46
+ RUBY_VERSION >= '2.0.0' && OpenSSL::OPENSSL_VERSION >= 'OpenSSL 1.0.1c'
47
+ end
48
+
49
+ def gcm?
50
+ [:A128GCM, :A256GCM].collect(&:to_s).include? encryption_method.to_s
51
+ end
52
+
53
+ def cbc?
54
+ [:'A128CBC+HS256', :'A256CBC+HS512'].collect(&:to_s).include? encryption_method.to_s
55
+ end
56
+
57
+ def dir?
58
+ :dir.to_s == algorithm.to_s
59
+ end
60
+
61
+ def cipher
62
+ @cipher ||= if gcm? && !gcm_supported?
63
+ raise UnexpectedAlgorithm.new('AEC GCM requires Ruby 2.0+ and OpenSSL 1.0.1c+') if gcm? && !gcm_supported?
64
+ else
65
+ OpenSSL::Cipher.new cipher_name
66
+ end
67
+ end
68
+
69
+ def cipher_name
70
+ case encryption_method.to_s
71
+ when :A128GCM.to_s
72
+ 'aes-128-gcm'
73
+ when :A256GCM.to_s
74
+ 'aes-256-gcm'
75
+ when :'A128CBC+HS256'.to_s
76
+ 'aes-128-cbc'
77
+ when :'A256CBC+HS512'.to_s
78
+ 'aes-256-cbc'
79
+ else
80
+ raise UnexpectedAlgorithm.new('Unknown Encryption Algorithm')
81
+ end
82
+ end
83
+
84
+ def sha_size
85
+ case encryption_method.to_s
86
+ when :'A128CBC+HS256'.to_s
87
+ 256
88
+ when :'A256CBC+HS512'.to_s
89
+ 512
90
+ else
91
+ raise UnexpectedAlgorithm.new('Unknown Hash Size')
92
+ end
93
+ end
94
+
95
+ def sha_digest
96
+ OpenSSL::Digest::Digest.new "SHA#{sha_size}"
97
+ end
98
+
99
+ def encrypted_master_key
100
+ @encrypted_master_key ||= case algorithm.to_s
101
+ when :RSA1_5.to_s
102
+ public_key_or_secret.public_encrypt master_key
103
+ when :'RSA-OAEP'.to_s
104
+ public_key_or_secret.public_encrypt master_key, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
105
+ when :A128KW .to_s
106
+ raise NotImplementedError.new('A128KW not supported yet')
107
+ when :A256KW.to_s
108
+ raise NotImplementedError.new('A256KW not supported yet')
109
+ when :dir.to_s
110
+ ''
111
+ when :'ECDH-ES'.to_s
112
+ raise NotImplementedError.new('ECDH-ES not supported yet')
113
+ when :'ECDH-ES+A128KW'.to_s
114
+ raise NotImplementedError.new('ECDH-ES+A128KW not supported yet')
115
+ when :'ECDH-ES+A256KW'.to_s
116
+ raise NotImplementedError.new('ECDH-ES+A256KW not supported yet')
117
+ else
118
+ raise UnexpectedAlgorithm.new('Unknown Encryption Algorithm')
119
+ end
120
+ end
121
+
122
+ def generate_cipher_keys!
123
+ case
124
+ when gcm?
125
+ generate_gcm_keys!
126
+ when cbc?
127
+ generate_cbc_keys!
128
+ end
129
+ @cipher.key = encryption_key
130
+ self.iv = @cipher.random_iv
131
+ if gcm?
132
+ cipher.auth_data = [header.to_json, encrypted_master_key, iv].collect do |segment|
133
+ UrlSafeBase64.encode64 segment.to_s
134
+ end.join('.')
135
+ end
136
+ self
137
+ end
138
+
139
+ def generate_gcm_keys!
140
+ self.master_key ||= if dir?
141
+ public_key_or_secret
142
+ else
143
+ @cipher.random_key
144
+ end
145
+ self.encryption_key = master_key
146
+ self.integrity_key = :wont_be_used
147
+ self
148
+ end
149
+
150
+ def generate_cbc_keys!
151
+ encryption_key_size = sha_size / 2
152
+ integrity_key_size = master_key_size = sha_size
153
+ self.master_key ||= if dir?
154
+ public_key_or_secret
155
+ else
156
+ SecureRandom.random_bytes master_key_size / 8
157
+ end
158
+ encryption_segments = [
159
+ 1,
160
+ master_key,
161
+ encryption_key_size,
162
+ encryption_method,
163
+ epu || 0,
164
+ epv || 0,
165
+ 'Encryption'
166
+ ]
167
+ integrity_segments = [
168
+ 1,
169
+ master_key,
170
+ integrity_key_size,
171
+ encryption_method,
172
+ epu || 0,
173
+ epv || 0,
174
+ 'Integrity'
175
+ ]
176
+ encryption_hash_input, integrity_hash_input = [encryption_segments, integrity_segments].collect do |segments|
177
+ segments.collect do |segment|
178
+ case segment
179
+ when Integer
180
+ BinData::Int32be.new(segment).to_binary_s
181
+ else
182
+ segment.to_s
183
+ end
184
+ end.join
185
+ end
186
+ self.encryption_key = sha_digest.digest(encryption_hash_input)[0, encryption_key_size / 8]
187
+ self.integrity_key = sha_digest.digest integrity_hash_input
188
+ self
189
+ end
190
+
191
+ def integrity_value
192
+ @integrity_value ||= if gcm?
193
+ cipher.auth_tag
194
+ else
195
+ secured_input = [
196
+ header.to_json,
197
+ encrypted_master_key,
198
+ iv,
199
+ cipher_text
200
+ ].collect do |segment|
201
+ UrlSafeBase64.encode64 segment.to_s
202
+ end.join('.')
203
+ OpenSSL::HMAC.digest sha_digest, integrity_key, secured_input
204
+ end
205
+ @integrity_value
206
+ end
4
207
  end
5
- end
208
+ end
@@ -40,13 +40,13 @@ module JSON
40
40
  hash = case public_key
41
41
  when OpenSSL::PKey::RSA
42
42
  {
43
- :alg => :RSA,
43
+ :kty => :RSA,
44
44
  :e => UrlSafeBase64.encode64(public_key.e.to_s(2)),
45
45
  :n => UrlSafeBase64.encode64(public_key.n.to_s(2)),
46
46
  }
47
47
  when OpenSSL::PKey::EC
48
48
  {
49
- :alg => :EC,
49
+ :kty => :EC,
50
50
  :crv => ecdsa_curve_name(public_key),
51
51
  :x => UrlSafeBase64.encode64(ecdsa_coodinates(public_key)[:x].to_s),
52
52
  :y => UrlSafeBase64.encode64(ecdsa_coodinates(public_key)[:y].to_s),
@@ -59,7 +59,7 @@ module JSON
59
59
 
60
60
  class << self
61
61
  def decode(jwk)
62
- case jwk[:alg].to_s
62
+ case jwk[:kty].to_s
63
63
  when 'RSA'
64
64
  e = OpenSSL::BN.new UrlSafeBase64.decode64(jwk[:e]), 2
65
65
  n = OpenSSL::BN.new UrlSafeBase64.decode64(jwk[:n]), 2
@@ -2,6 +2,9 @@ module JSON
2
2
  class JWS < JWT
3
3
  class InvalidFormat < JWT::InvalidFormat; end
4
4
  class VerificationFailed < JWT::VerificationFailed; end
5
+ class UnexpectedAlgorithm < JWT::UnexpectedAlgorithm; end
6
+
7
+ register_header_keys :jku, :kid, :x5u, :x5t
5
8
 
6
9
  def initialize(jwt)
7
10
  replace jwt
@@ -20,10 +23,6 @@ module JSON
20
23
 
21
24
  private
22
25
 
23
- def algorithm
24
- header[:alg]
25
- end
26
-
27
26
  def digest
28
27
  OpenSSL::Digest::Digest.new "SHA#{algorithm.to_s[2, 3]}"
29
28
  end
@@ -62,7 +61,7 @@ module JSON
62
61
  verify_ecdsa_group! private_key
63
62
  private_key.dsa_sign_asn1 digest.digest(signature_base_string)
64
63
  else
65
- raise InvalidFormat.new('Unknown Signature Algorithm')
64
+ raise UnexpectedAlgorithm.new('Unknown Signature Algorithm')
66
65
  end
67
66
  end
68
67
 
@@ -79,20 +78,20 @@ module JSON
79
78
  verify_ecdsa_group! public_key
80
79
  public_key.dsa_verify_asn1 digest.digest(signature_base_string), signature
81
80
  else
82
- raise InvalidFormat.new('Unknown Signature Algorithm')
81
+ raise UnexpectedAlgorithm.new('Unknown Signature Algorithm')
83
82
  end
84
83
  end
85
84
 
86
85
  def verify_ecdsa_group!(key)
87
86
  group_name = case digest.digest_length * 8
88
87
  when 256
89
- 'secp256k1'
88
+ :secp256k1
90
89
  when 384
91
- 'secp384r1'
90
+ :secp384r1
92
91
  when 512
93
- 'secp521r1'
92
+ :secp521r1
94
93
  end
95
- key.group = OpenSSL::PKey::EC::Group.new group_name
94
+ key.group = OpenSSL::PKey::EC::Group.new group_name.to_s
96
95
  key.check_key
97
96
  end
98
97
 
@@ -12,11 +12,28 @@ module JSON
12
12
  class VerificationFailed < Exception; end
13
13
  class UnexpectedAlgorithm < VerificationFailed; end
14
14
 
15
+ def header
16
+ @header ||= {}
17
+ end
18
+
19
+ class << self
20
+ def register_header_keys(*keys)
21
+ keys.each do |header_key|
22
+ define_method header_key do
23
+ self.header[header_key]
24
+ end
25
+ define_method "#{header_key}=" do |value|
26
+ self.header[header_key] = value
27
+ end
28
+ end
29
+ end
30
+ end
31
+ register_header_keys :typ, :cty, :alg
32
+ alias_method :algorithm, :alg
33
+
15
34
  def initialize(claims)
16
- @header = {
17
- :typ => :JWT,
18
- :alg => :none
19
- }
35
+ self.typ = :JWT
36
+ self.alg = :none
20
37
  [:exp, :nbf, :iat].each do |key|
21
38
  claims[key] = claims[key].to_i if claims[key]
22
39
  end
@@ -24,12 +41,13 @@ module JSON
24
41
  end
25
42
 
26
43
  def sign(private_key_or_secret, algorithm = :HS256)
27
- header[:alg] = algorithm
28
- JWS.new(self).sign!(private_key_or_secret)
44
+ jws = JWS.new(self)
45
+ jws.alg = algorithm
46
+ jws.sign! private_key_or_secret
29
47
  end
30
48
 
31
49
  def verify(signature_base_string, public_key_or_secret = nil)
32
- if header[:alg].to_s == 'none'
50
+ if alg.to_s == 'none'
33
51
  raise UnexpectedAlgorithm if public_key_or_secret
34
52
  signature == '' or raise VerificationFailed
35
53
  else
@@ -37,6 +55,13 @@ module JSON
37
55
  end
38
56
  end
39
57
 
58
+ def encrypt(public_key_or_secret, algorithm = :RSA1_5, encryption_method = :'A128CBC+HS256')
59
+ jwe = JWE.new(self)
60
+ jwe.alg = algorithm
61
+ jwe.enc = encryption_method
62
+ jwe.encrypt! public_key_or_secret
63
+ end
64
+
40
65
  def to_s
41
66
  [
42
67
  header.to_json,
@@ -67,10 +92,12 @@ module JSON
67
92
  # So we need to use raw base64 strings for signature verification.
68
93
  jwt.verify signature_base_string, key_or_secret unless key_or_secret == :skip_verification
69
94
  jwt
70
- when 3 # JWE
71
- # TODO: Concept code first.
72
- # jwt = JWE.decrypt ...
73
- # jwt.verify ...
95
+ when 4 # JWE
96
+ jwe = JWE.new jwt_string
97
+ jwe.header = MultiJson.load(
98
+ jwt_string.split('.').first
99
+ ).with_indifferent_access
100
+ jwe.decrypt! key_or_secret
74
101
  else
75
102
  raise InvalidFormat.new('Invalid JWT Format. JWT should include 2 or 3 dots.')
76
103
  end
@@ -0,0 +1,21 @@
1
+ module NimbusSpecHelper
2
+ module_function
3
+
4
+ def setup
5
+ nimbus_path = File.expand_path(
6
+ File.join(
7
+ File.dirname(__FILE__),
8
+ 'json-jwt-nimbus'
9
+ )
10
+ )
11
+ if File.exist? nimbus_path
12
+ require File.join(nimbus_path, 'nimbus_jwe')
13
+ end
14
+ end
15
+
16
+ def nimbus_available?
17
+ defined? NimbusJWE
18
+ end
19
+ end
20
+
21
+ NimbusSpecHelper.setup
@@ -4,11 +4,20 @@ module SignKeyFixtureHelper
4
4
  end
5
5
 
6
6
  def pem_file(file_name)
7
- File.new(
8
- File.join(
9
- File.dirname(__FILE__),
10
- "../fixtures/#{file_name}.pem"
11
- )
7
+ File.new pem_file_path(file_name)
8
+ end
9
+
10
+ def pem_file_path(file_name)
11
+ File.join(
12
+ File.dirname(__FILE__),
13
+ "../fixtures/#{file_name}.pem"
14
+ )
15
+ end
16
+
17
+ def der_file_path(file_name)
18
+ File.join(
19
+ File.dirname(__FILE__),
20
+ "../fixtures/#{file_name}.der"
12
21
  )
13
22
  end
14
23
 
@@ -0,0 +1,157 @@
1
+ require 'spec_helper'
2
+
3
+ def gcm_supported?
4
+ RUBY_VERSION >= '2.0.0' && OpenSSL::OPENSSL_VERSION >= 'OpenSSL 1.0.1c'
5
+ end
6
+
7
+ describe JSON::JWE do
8
+ let(:shared_key) { SecureRandom.hex 16 } # default shared key is too short
9
+ let(:private_key_path) { der_file_path 'rsa/private_key' }
10
+
11
+ describe 'encrypt!' do
12
+ shared_examples_for :gcm_encryption do
13
+ context 'when enc=A128GCM' do
14
+ before { jwe.enc = :A128GCM }
15
+
16
+ it 'should decryptable by Nimbus JOSE JWT' do
17
+ jwe.encrypt! key
18
+ NimbusJWE.decrypt(jwe, private_key_path).should == plain_text
19
+ end
20
+ end
21
+
22
+ context 'when enc=A256GCM' do
23
+ before { jwe.enc = :A256GCM }
24
+
25
+ it 'should decryptable by Nimbus JOSE JWT' do
26
+ jwe.encrypt! key
27
+ NimbusJWE.decrypt(jwe, private_key_path).should == plain_text
28
+ end
29
+ end
30
+ end
31
+
32
+ shared_examples_for :gcm_encryption_unsupported do
33
+ context 'when enc=A128GCM' do
34
+ before { jwe.enc = :A128GCM }
35
+
36
+ it do
37
+ expect do
38
+ jwe.encrypt! key
39
+ end.to raise_error JSON::JWE::UnexpectedAlgorithm
40
+ end
41
+ end
42
+
43
+ context 'when enc=A256GCM' do
44
+ before { jwe.enc = :A256GCM }
45
+
46
+ it do
47
+ expect do
48
+ jwe.encrypt! key
49
+ end.to raise_error JSON::JWE::UnexpectedAlgorithm
50
+ end
51
+ end
52
+ end
53
+
54
+ shared_examples_for :cbc_encryption do
55
+ context 'when enc=A128CBC+HS256' do
56
+ before { jwe.enc = :'A128CBC+HS256' }
57
+
58
+ it 'should decryptable by Nimbus JOSE JWT' do
59
+ jwe.encrypt! key
60
+ NimbusJWE.decrypt(jwe, private_key_path).should == plain_text
61
+ end
62
+ end
63
+
64
+ context 'when enc=A256CBC+HS512' do
65
+ before { jwe.enc = :'A256CBC+HS512' }
66
+
67
+ it 'should decryptable by Nimbus JOSE JWT' do
68
+ jwe.encrypt! key
69
+ NimbusJWE.decrypt(jwe, private_key_path).should == plain_text
70
+ end
71
+ end
72
+ end
73
+
74
+ context 'when plaintext given' do
75
+ let(:plain_text) { 'Hello World' }
76
+ let(:jwe) { JSON::JWE.new plain_text }
77
+
78
+ context 'when alg=RSA1_5' do
79
+ if NimbusSpecHelper.nimbus_available?
80
+ let(:key) { public_key }
81
+ before { jwe.alg = :'RSA1_5' }
82
+
83
+ if gcm_supported?
84
+ it_behaves_like :gcm_encryption
85
+ else
86
+ it_behaves_like :gcm_encryption_unsupported
87
+ end
88
+ it_behaves_like :cbc_encryption
89
+ else
90
+ it :TODO
91
+ end
92
+ end
93
+
94
+ context 'when alg=RSA-OAEP' do
95
+ if NimbusSpecHelper.nimbus_available?
96
+ let(:key) { public_key }
97
+ before { jwe.alg = :'RSA-OAEP' }
98
+
99
+ if gcm_supported?
100
+ it_behaves_like :gcm_encryption
101
+ else
102
+ it_behaves_like :gcm_encryption_unsupported
103
+ end
104
+ it_behaves_like :cbc_encryption
105
+ else
106
+ it :TODO
107
+ end
108
+ end
109
+
110
+ context 'when alg=dir' do
111
+ it :TODO
112
+ end
113
+ end
114
+
115
+ context 'when jwt given' do
116
+ let(:plain_text) { jwt.to_s }
117
+ let(:jwt) { JSON::JWT.new(foo: :bar) }
118
+ let(:jwe) { JSON::JWE.new jwt }
119
+
120
+ context 'when alg=RSA-OAEP' do
121
+ if NimbusSpecHelper.nimbus_available?
122
+ let(:key) { public_key }
123
+ before { jwe.alg = :'RSA1_5' }
124
+
125
+ if gcm_supported?
126
+ it_behaves_like :gcm_encryption
127
+ else
128
+ it_behaves_like :gcm_encryption_unsupported
129
+ end
130
+ it_behaves_like :cbc_encryption
131
+ else
132
+ it :TODO
133
+ end
134
+ end
135
+
136
+ context 'when alg=RSA-OAEP' do
137
+ if NimbusSpecHelper.nimbus_available?
138
+ let(:key) { public_key }
139
+ before { jwe.alg = :'RSA-OAEP' }
140
+
141
+ if gcm_supported?
142
+ it_behaves_like :gcm_encryption
143
+ else
144
+ it_behaves_like :gcm_encryption_unsupported
145
+ end
146
+ it_behaves_like :cbc_encryption
147
+ else
148
+ it :TODO
149
+ end
150
+ end
151
+
152
+ context 'when alg=dir' do
153
+ it :TODO
154
+ end
155
+ end
156
+ end
157
+ end
@@ -3,8 +3,8 @@ require 'spec_helper'
3
3
  describe JSON::JWK do
4
4
  context 'when RSA public key given' do
5
5
  let(:jwk) { JSON::JWK.new public_key }
6
- it { jwk.keys.should include :alg, :e, :n }
7
- its(:alg) { jwk[:alg].should == :RSA }
6
+ it { jwk.keys.should include :kty, :e, :n }
7
+ its(:kty) { jwk[:kty].should == :RSA }
8
8
  its(:e) { jwk[:e].should == UrlSafeBase64.encode64(public_key.e.to_s(2)) }
9
9
  its(:n) { jwk[:n].should == UrlSafeBase64.encode64(public_key.n.to_s(2)) }
10
10
 
@@ -36,8 +36,8 @@ describe JSON::JWK do
36
36
  [256, 384, 512].each do |digest_length|
37
37
  describe "EC#{digest_length}" do
38
38
  let(:jwk) { JSON::JWK.new public_key(:ecdsa, digest_length: digest_length) }
39
- it { jwk.keys.should include :alg, :crv, :x, :y }
40
- its(:alg) { jwk[:alg].should == :EC }
39
+ it { jwk.keys.should include :kty, :crv, :x, :y }
40
+ its(:kty) { jwk[:kty].should == :EC }
41
41
  its(:x) { jwk[:x].should == expected_coodinates[digest_length][:x] }
42
42
  its(:y) { jwk[:y].should == expected_coodinates[digest_length][:y] }
43
43
  end
@@ -66,7 +66,7 @@ describe JSON::JWK do
66
66
  context 'when RSA' do
67
67
  subject do
68
68
  JSON::JWK.decode(
69
- alg: :RSA,
69
+ kty: :RSA,
70
70
  n: n,
71
71
  e: e
72
72
  )
@@ -108,7 +108,7 @@ NrqoxoakrPo1NI1u+ET8oWGmnjB/nJFAPwIDAQAB
108
108
  it do
109
109
  expect do
110
110
  JSON::JWK.decode(
111
- alg: :EC,
111
+ kty: :EC,
112
112
  crv: 'crv',
113
113
  x: 'x',
114
114
  y: 'y'
@@ -121,7 +121,7 @@ NrqoxoakrPo1NI1u+ET8oWGmnjB/nJFAPwIDAQAB
121
121
  it do
122
122
  expect do
123
123
  JSON::JWK.decode(
124
- alg: :XXX
124
+ kty: :XXX
125
125
  )
126
126
  end.to raise_error JSON::JWK::UnknownAlgorithm
127
127
  end
@@ -4,7 +4,7 @@ describe JSON::JWS do
4
4
  let(:alg) { :none }
5
5
  let(:jwt) do
6
6
  _jwt_ = JSON::JWT.new claims
7
- _jwt_.header[:alg] = alg
7
+ _jwt_.alg = alg
8
8
  _jwt_
9
9
  end
10
10
  let(:jws) { JSON::JWS.new jwt }
@@ -70,7 +70,7 @@ describe JSON::JWS do
70
70
  it do
71
71
  expect do
72
72
  jws.sign! 'key'
73
- end.to raise_error JSON::JWS::InvalidFormat
73
+ end.to raise_error JSON::JWS::UnexpectedAlgorithm
74
74
  end
75
75
  end
76
76
  end
@@ -132,7 +132,7 @@ describe JSON::JWS do
132
132
  it do
133
133
  expect do
134
134
  jws.verify jws.send(:signature_base_string), 'key'
135
- end.to raise_error JSON::JWS::InvalidFormat
135
+ end.to raise_error JSON::JWS::UnexpectedAlgorithm
136
136
  end
137
137
  end
138
138
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe JSON::JWT do
4
4
  let(:jwt) { JSON::JWT.new claims }
5
5
  let(:jws) do
6
- jwt.header[:alg] = :HS256
6
+ jwt.alg = :HS256
7
7
  jws = JSON::JWS.new jwt
8
8
  jws.signature = 'signature'
9
9
  jws
@@ -93,6 +93,26 @@ describe JSON::JWT do
93
93
  end
94
94
  end
95
95
 
96
+ describe '#encrypt' do
97
+ let(:shared_key) { SecureRandom.hex 16 } # default shared key is too short
98
+
99
+ it 'should encryptable without signing' do
100
+ jwt.encrypt(public_key).should be_a JSON::JWE
101
+ end
102
+
103
+ it 'should encryptable after signed' do
104
+ jwt.sign(shared_key).encrypt(public_key).should be_a JSON::JWE
105
+ end
106
+
107
+ it 'should accept optional algorithm' do
108
+ jwt.encrypt(shared_key, :dir).should be_a JSON::JWE
109
+ end
110
+
111
+ it 'should accept optional algorithm and encryption method' do
112
+ jwt.encrypt(shared_key, :dir, :'A256CBC+HS512').should be_a JSON::JWE
113
+ end
114
+ end
115
+
96
116
  describe '.decode' do
97
117
  context 'when not signed nor encrypted' do
98
118
  context 'no signature given' do
@@ -2,4 +2,5 @@ require 'cover_me'
2
2
  require 'rspec'
3
3
  require 'json/jwt'
4
4
 
5
- require 'helpers/sign_key_fixture_helper'
5
+ require 'helpers/sign_key_fixture_helper'
6
+ require 'helpers/nimbus_spec_helper'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json-jwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - nov matake
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-03-03 00:00:00.000000000 Z
11
+ date: 2013-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bindata
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rake
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -117,9 +131,11 @@ extensions: []
117
131
  extra_rdoc_files: []
118
132
  files:
119
133
  - .gitignore
134
+ - .gitmodules
120
135
  - .rspec
121
136
  - .travis.yml
122
137
  - Gemfile
138
+ - Gemfile.lock
123
139
  - LICENSE
124
140
  - README.rdoc
125
141
  - Rakefile
@@ -136,9 +152,12 @@ files:
136
152
  - spec/fixtures/ecdsa/384/public_key.pem
137
153
  - spec/fixtures/ecdsa/512/private_key.pem
138
154
  - spec/fixtures/ecdsa/512/public_key.pem
155
+ - spec/fixtures/rsa/private_key.der
139
156
  - spec/fixtures/rsa/private_key.pem
140
157
  - spec/fixtures/rsa/public_key.pem
158
+ - spec/helpers/nimbus_spec_helper.rb
141
159
  - spec/helpers/sign_key_fixture_helper.rb
160
+ - spec/json/jwe_spec.rb
142
161
  - spec/json/jwk/set_spec.rb
143
162
  - spec/json/jwk_spec.rb
144
163
  - spec/json/jws_spec.rb
@@ -175,11 +194,15 @@ test_files:
175
194
  - spec/fixtures/ecdsa/384/public_key.pem
176
195
  - spec/fixtures/ecdsa/512/private_key.pem
177
196
  - spec/fixtures/ecdsa/512/public_key.pem
197
+ - spec/fixtures/rsa/private_key.der
178
198
  - spec/fixtures/rsa/private_key.pem
179
199
  - spec/fixtures/rsa/public_key.pem
200
+ - spec/helpers/nimbus_spec_helper.rb
180
201
  - spec/helpers/sign_key_fixture_helper.rb
202
+ - spec/json/jwe_spec.rb
181
203
  - spec/json/jwk/set_spec.rb
182
204
  - spec/json/jwk_spec.rb
183
205
  - spec/json/jws_spec.rb
184
206
  - spec/json/jwt_spec.rb
185
207
  - spec/spec_helper.rb
208
+ has_rdoc: