json-jwt 0.4.3 → 0.5.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 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: