json-jwt 0.6.0 → 0.6.1

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9ed6b68461d916fd8be52e755b8bb2c77253149d
4
- data.tar.gz: 8f0b99b938171b21ab88d259471ec72622c979bb
3
+ metadata.gz: cfafaeda298c56aa5cd5f1056f33b31ed7b31bb8
4
+ data.tar.gz: fe6fd7d8d776f0b197add6a79f2b11a03afc9af7
5
5
  SHA512:
6
- metadata.gz: 07c51fe7a0b6b66ce4e4504f36baf1698c76537fa8f38513d2cc3fc67dd33208c88b64b8fbe8d0c6feafbf457d10e1ccdf2f3f2adc148035577ed3d5c37cedfb
7
- data.tar.gz: 44ae1afcca4d398d46fedacfa69e3403d484f77011af870b7e77f38496a4b1177d3b8fad54a014b49a980dc0f871135b3eed27354cc3035e3cba80b1d36d7d22
6
+ metadata.gz: f0ead0b472adcf5fab5203765d2b83ea4afeb131510d4765b0f884867de2affeac688d72c8bbc64626498680e0b6c55a1f351d9fcd07fde418342be7ef9ab92c
7
+ data.tar.gz: adca33ab7ec94e4a92a70585cf3c3e441f2f22c56701071adc79f1d5ecd6a0bc28fbb9cbb13ce74b9869c8dfe274c3da1d65b49621e5fbe1ce944e1c6204caab
data/README.rdoc CHANGED
@@ -34,7 +34,7 @@ JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON
34
34
 
35
35
  # With signature & encryption
36
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
37
+ jws.to_s # => header.encrypted_key.iv.cipher_text.authentication_tag
38
38
 
39
39
  For details about <code>key</code> and <code>algorithm</code>, see
40
40
  {JWS Spec}[https://github.com/nov/json-jwt/blob/master/spec/json/jws_spec.rb] and
data/Rakefile CHANGED
@@ -4,15 +4,16 @@ Bundler::GemHelper.install_tasks
4
4
  require 'rspec/core/rake_task'
5
5
  RSpec::Core::RakeTask.new(:spec)
6
6
 
7
- namespace :cover_me do
8
- desc "Generates and opens code coverage report."
7
+ namespace :coverage do
8
+ desc "Open coverage report"
9
9
  task :report do
10
- require 'cover_me'
11
- CoverMe.complete!
10
+ require 'simplecov'
11
+ `open "#{File.join SimpleCov.coverage_path, 'index.html'}"`
12
12
  end
13
13
  end
14
+
14
15
  task :spec do
15
- Rake::Task['cover_me:report'].invoke unless ENV['TRAVIS_RUBY_VERSION']
16
+ Rake::Task[:'coverage:report'].invoke unless ENV['TRAVIS_RUBY_VERSION']
16
17
  end
17
18
 
18
- task default: :spec
19
+ task :default => :spec
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.0
1
+ 0.6.1
data/json-jwt.gemspec CHANGED
@@ -1,20 +1,22 @@
1
- Gem::Specification.new do |s|
2
- s.name = "json-jwt"
3
- s.version = File.read("VERSION")
4
- s.authors = ["nov matake"]
5
- s.email = ["nov@matake.jp"]
6
- s.homepage = "https://github.com/nov/json-jwt"
7
- s.summary = %q{JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON Web Key) in Ruby}
8
- s.description = %q{JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON Web Key) in Ruby}
9
- s.files = `git ls-files`.split("\n")
10
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
11
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
- s.require_paths = ["lib"]
13
- s.add_runtime_dependency "multi_json", ">= 1.3"
14
- s.add_runtime_dependency "url_safe_base64"
15
- s.add_runtime_dependency "activesupport"
16
- s.add_runtime_dependency "bindata"
17
- s.add_development_dependency "rake", ">= 0.8"
18
- s.add_development_dependency "cover_me", ">= 1.2.0"
19
- s.add_development_dependency "rspec", ">= 2"
1
+ Gem::Specification.new do |gem|
2
+ gem.name = "json-jwt"
3
+ gem.version = File.read("VERSION")
4
+ gem.authors = ["nov matake"]
5
+ gem.email = ["nov@matake.jp"]
6
+ gem.homepage = "https://github.com/nov/json-jwt"
7
+ gem.summary = %q{JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON Web Key) in Ruby}
8
+ gem.description = %q{JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON Web Key) in Ruby}
9
+ gem.license = 'MIT'
10
+ gem.files = `git ls-files`.split("\n")
11
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
12
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
13
+ gem.require_paths = ["lib"]
14
+ gem.add_runtime_dependency "multi_json", ">= 1.3"
15
+ gem.add_runtime_dependency "url_safe_base64"
16
+ gem.add_runtime_dependency "activesupport"
17
+ gem.add_runtime_dependency "bindata"
18
+ gem.add_runtime_dependency "securecompare"
19
+ gem.add_development_dependency "rake", ">= 0.8"
20
+ gem.add_development_dependency "simplecov"
21
+ gem.add_development_dependency "rspec", ">= 2"
20
22
  end
data/lib/json/jose.rb CHANGED
@@ -1,5 +1,9 @@
1
+ require 'securecompare'
2
+
1
3
  module JSON
2
4
  class JOSE < JWT
5
+ include SecureCompare
6
+
3
7
  def content_type
4
8
  'application/jose'
5
9
  end
data/lib/json/jwe.rb CHANGED
@@ -7,6 +7,8 @@ module JSON
7
7
  class DecryptionFailed < JWT::VerificationFailed; end
8
8
  class UnexpectedAlgorithm < JWT::UnexpectedAlgorithm; end
9
9
 
10
+ NUM_OF_SEGMENTS = 5
11
+
10
12
  attr_accessor(
11
13
  :public_key_or_secret, :private_key_or_secret, :mode,
12
14
  :input, :plain_text, :cipher_text, :authentication_tag, :iv,
@@ -41,7 +43,7 @@ module JSON
41
43
  cipher.decrypt
42
44
  restore_cipher_keys!
43
45
  self.plain_text = cipher.update(cipher_text) + cipher.final
44
- verify_cbc_integirity_value! if cbc?
46
+ verify_cbc_authentication_tag! if cbc?
45
47
  self
46
48
  end
47
49
 
@@ -119,6 +121,17 @@ module JSON
119
121
  OpenSSL::Digest::Digest.new "SHA#{sha_size}"
120
122
  end
121
123
 
124
+ def derive_encryption_and_mac_keys_cbc!
125
+ self.mac_key, self.encryption_key = content_encryption_key.unpack("a#{content_encryption_key.length / 2}" * 2)
126
+ self
127
+ end
128
+
129
+ def derive_encryption_and_mac_keys_gcm!
130
+ self.encryption_key = content_encryption_key
131
+ self.mac_key = :wont_be_used
132
+ self
133
+ end
134
+
122
135
  # encyption
123
136
 
124
137
  def jwe_encrypted_key
@@ -165,7 +178,7 @@ module JSON
165
178
  else
166
179
  cipher.random_key
167
180
  end
168
- self.encryption_key = content_encryption_key
181
+ derive_encryption_and_mac_keys_gcm!
169
182
  self
170
183
  end
171
184
 
@@ -175,7 +188,7 @@ module JSON
175
188
  else
176
189
  SecureRandom.random_bytes sha_size / 8
177
190
  end
178
- self.mac_key, self.encryption_key = content_encryption_key.unpack("a#{content_encryption_key.length / 2}" * 2)
191
+ derive_encryption_and_mac_keys_cbc!
179
192
  self
180
193
  end
181
194
 
@@ -200,6 +213,9 @@ module JSON
200
213
  # decryption
201
214
 
202
215
  def decode_segments!
216
+ unless input.count('.') + 1 == NUM_OF_SEGMENTS
217
+ raise InvalidFormat.new("Invalid JWE Format. JWE should include #{NUM_OF_SEGMENTS} segments.")
218
+ end
203
219
  _header_json_, self.jwe_encrypted_key, self.iv, self.cipher_text, self.authentication_tag = input.split('.').collect do |segment|
204
220
  UrlSafeBase64.decode64 segment
205
221
  end
@@ -233,9 +249,9 @@ module JSON
233
249
  self.content_encryption_key = decrypt_content_encryption_key
234
250
  case
235
251
  when gcm?
236
- self.encryption_key = content_encryption_key
252
+ derive_encryption_and_mac_keys_gcm!
237
253
  when cbc?
238
- self.mac_key, self.encryption_key = content_encryption_key.unpack("a#{content_encryption_key.length / 2}" * 2)
254
+ derive_encryption_and_mac_keys_cbc!
239
255
  end
240
256
  cipher.key = encryption_key
241
257
  cipher.iv = iv # NOTE: 'iv' has to be set after 'key' for GCM
@@ -245,7 +261,7 @@ module JSON
245
261
  end
246
262
  end
247
263
 
248
- def verify_cbc_integirity_value!
264
+ def verify_cbc_authentication_tag!
249
265
  auth_data = input.split('.').first
250
266
  secured_input = [
251
267
  auth_data,
@@ -256,8 +272,8 @@ module JSON
256
272
  expected_authentication_tag = OpenSSL::HMAC.digest(
257
273
  sha_digest, mac_key, secured_input
258
274
  )[0, sha_size / 2 / 8]
259
- unless authentication_tag == expected_authentication_tag
260
- raise DecryptionFailed.new('Invalid integrity value')
275
+ unless secure_compare(authentication_tag, expected_authentication_tag)
276
+ raise DecryptionFailed.new('Invalid authentication tag')
261
277
  end
262
278
  end
263
279
  end
data/lib/json/jws.rb CHANGED
@@ -4,6 +4,8 @@ module JSON
4
4
  class VerificationFailed < JWT::VerificationFailed; end
5
5
  class UnexpectedAlgorithm < JWT::UnexpectedAlgorithm; end
6
6
 
7
+ NUM_OF_SEGMENTS = 3
8
+
7
9
  def initialize(jwt)
8
10
  replace jwt
9
11
  raise InvalidFormat.new('Signature Algorithm Required') unless algorithm
@@ -66,8 +68,7 @@ module JSON
66
68
  def valid?(signature_base_string, public_key_or_secret)
67
69
  case
68
70
  when hmac?
69
- secret = public_key_or_secret
70
- sign(signature_base_string, secret) == signature
71
+ secure_compare sign(signature_base_string, public_key_or_secret), signature
71
72
  when rsa?
72
73
  public_key = public_key_or_secret
73
74
  public_key.verify digest, signature, signature_base_string
data/lib/json/jwt.rb CHANGED
@@ -78,15 +78,15 @@ module JSON
78
78
 
79
79
  class << self
80
80
  def decode(jwt_string, key_or_secret = nil)
81
- case jwt_string.count('.')
82
- when 2 # JWT / JWS
83
- header, claims, signature = jwt_string.split('.', 3).collect do |segment|
81
+ case jwt_string.count('.') + 1
82
+ when JWS::NUM_OF_SEGMENTS # JWT / JWS
83
+ header, claims, signature = jwt_string.split('.', JWS::NUM_OF_SEGMENTS).collect do |segment|
84
84
  UrlSafeBase64.decode64 segment.to_s
85
85
  end
86
86
  header, claims = [header, claims].collect do |json|
87
87
  MultiJson.load(json).with_indifferent_access
88
88
  end
89
- signature_base_string = jwt_string.split('.')[0, 2].join('.')
89
+ signature_base_string = jwt_string.split('.')[0, JWS::NUM_OF_SEGMENTS - 1].join('.')
90
90
  jwt = new claims
91
91
  jwt.header = header
92
92
  jwt.signature = signature
@@ -96,7 +96,7 @@ module JSON
96
96
  # So we need to use raw base64 strings for signature verification.
97
97
  jwt.verify signature_base_string, key_or_secret unless key_or_secret == :skip_verification
98
98
  jwt
99
- when 4 # JWE
99
+ when JWE::NUM_OF_SEGMENTS
100
100
  jwe = JWE.new jwt_string
101
101
  jwe.header = MultiJson.load(
102
102
  UrlSafeBase64.decode64 jwt_string.split('.').first
@@ -104,7 +104,7 @@ module JSON
104
104
  jwe.decrypt! key_or_secret unless key_or_secret == :skip_decryption
105
105
  jwe
106
106
  else
107
- raise InvalidFormat.new('Invalid JWT Format. JWT should include 2 or 3 dots.')
107
+ raise InvalidFormat.new("Invalid JWT Format. JWT should include #{JWS::NUM_OF_SEGMENTS} or #{JWE::NUM_OF_SEGMENTS} segments.")
108
108
  end
109
109
  rescue MultiJson::DecodeError
110
110
  raise InvalidFormat.new("Invalid JSON Format")
@@ -227,7 +227,7 @@ describe JSON::JWE do
227
227
  end
228
228
  end
229
229
 
230
- shared_examples_for :verify_cbc_integrity_value do
230
+ shared_examples_for :verify_cbc_authentication_tag do
231
231
  let(:input) do
232
232
  _jwe_ = JSON::JWE.new plain_text
233
233
  _jwe_.alg, _jwe_.enc = alg, enc
@@ -316,13 +316,13 @@ describe JSON::JWE do
316
316
  context 'when enc=A128CBC-HS256' do
317
317
  let(:enc) { :'A128CBC-HS256' }
318
318
  it_behaves_like :decryptable
319
- it_behaves_like :verify_cbc_integrity_value
319
+ it_behaves_like :verify_cbc_authentication_tag
320
320
  end
321
321
 
322
322
  context 'when enc=A256CBC-HS512' do
323
323
  let(:enc) { :'A256CBC-HS512' }
324
324
  it_behaves_like :decryptable
325
- it_behaves_like :verify_cbc_integrity_value
325
+ it_behaves_like :verify_cbc_authentication_tag
326
326
  end
327
327
  end
328
328
 
@@ -333,7 +333,7 @@ describe JSON::JWE do
333
333
  end
334
334
 
335
335
  context 'when unknonw/unsupported algorithm given' do
336
- let(:input) { 'whatever' }
336
+ let(:input) { 'header.key.iv.cipher_text.auth_tag' }
337
337
  let(:key) { public_key }
338
338
  let(:alg) { :RSA1_5 }
339
339
  let(:enc) { :'A128CBC-HS256' }
@@ -355,5 +355,16 @@ describe JSON::JWE do
355
355
  end
356
356
  end
357
357
  end
358
+
359
+ context 'when invalid format of input given' do
360
+ let(:input) { 'header.payload.signature' }
361
+ let(:alg) { :RSA1_5 }
362
+ let(:enc) { :'A128CBC-HS256' }
363
+ it do
364
+ expect do
365
+ jwe.decrypt! public_key
366
+ end.to raise_error JSON::JWE::InvalidFormat
367
+ end
368
+ end
358
369
  end
359
370
  end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,9 @@
1
- require 'cover_me'
1
+ require 'simplecov'
2
+
3
+ SimpleCov.start do
4
+ add_filter 'spec'
5
+ end
6
+
2
7
  require 'rspec'
3
8
  require 'json/jwt'
4
9
 
metadata CHANGED
@@ -1,111 +1,125 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json-jwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
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-10-24 00:00:00.000000000 Z
11
+ date: 2014-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: url_safe_base64
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
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
42
  name: activesupport
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
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
56
  name: bindata
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: securecompare
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
+ - - ">="
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rake
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - '>='
87
+ - - ">="
74
88
  - !ruby/object:Gem::Version
75
89
  version: '0.8'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - '>='
94
+ - - ">="
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0.8'
83
97
  - !ruby/object:Gem::Dependency
84
- name: cover_me
98
+ name: simplecov
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
- - - '>='
101
+ - - ">="
88
102
  - !ruby/object:Gem::Version
89
- version: 1.2.0
103
+ version: '0'
90
104
  type: :development
91
105
  prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
- - - '>='
108
+ - - ">="
95
109
  - !ruby/object:Gem::Version
96
- version: 1.2.0
110
+ version: '0'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: rspec
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
- - - '>='
115
+ - - ">="
102
116
  - !ruby/object:Gem::Version
103
117
  version: '2'
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
- - - '>='
122
+ - - ">="
109
123
  - !ruby/object:Gem::Version
110
124
  version: '2'
111
125
  description: JSON Web Token and its family (JSON Web Signature, JSON Web Encryption
@@ -116,10 +130,10 @@ executables: []
116
130
  extensions: []
117
131
  extra_rdoc_files: []
118
132
  files:
119
- - .gitignore
120
- - .gitmodules
121
- - .rspec
122
- - .travis.yml
133
+ - ".gitignore"
134
+ - ".gitmodules"
135
+ - ".rspec"
136
+ - ".travis.yml"
123
137
  - Gemfile
124
138
  - LICENSE
125
139
  - README.rdoc
@@ -150,7 +164,8 @@ files:
150
164
  - spec/json/jwt_spec.rb
151
165
  - spec/spec_helper.rb
152
166
  homepage: https://github.com/nov/json-jwt
153
- licenses: []
167
+ licenses:
168
+ - MIT
154
169
  metadata: {}
155
170
  post_install_message:
156
171
  rdoc_options: []
@@ -158,17 +173,17 @@ require_paths:
158
173
  - lib
159
174
  required_ruby_version: !ruby/object:Gem::Requirement
160
175
  requirements:
161
- - - '>='
176
+ - - ">="
162
177
  - !ruby/object:Gem::Version
163
178
  version: '0'
164
179
  required_rubygems_version: !ruby/object:Gem::Requirement
165
180
  requirements:
166
- - - '>='
181
+ - - ">="
167
182
  - !ruby/object:Gem::Version
168
183
  version: '0'
169
184
  requirements: []
170
185
  rubyforge_project:
171
- rubygems_version: 2.0.3
186
+ rubygems_version: 2.2.1
172
187
  signing_key:
173
188
  specification_version: 4
174
189
  summary: JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and