krypt 0.0.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.
Files changed (70) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +82 -0
  3. data/lib/krypt.rb +49 -0
  4. data/lib/krypt/asn1.rb +3 -0
  5. data/lib/krypt/asn1/common.rb +96 -0
  6. data/lib/krypt/asn1/template.rb +257 -0
  7. data/lib/krypt/codec.rb +57 -0
  8. data/lib/krypt/codec/base64.rb +140 -0
  9. data/lib/krypt/codec/base_codec.rb +36 -0
  10. data/lib/krypt/codec/hex.rb +122 -0
  11. data/lib/krypt/digest.rb +112 -0
  12. data/lib/krypt/hmac.rb +69 -0
  13. data/lib/krypt/pkcs5.rb +1 -0
  14. data/lib/krypt/pkcs5/pbkdf2.rb +41 -0
  15. data/lib/krypt/provider.rb +35 -0
  16. data/lib/krypt/x509.rb +3 -0
  17. data/lib/krypt/x509/certificate.rb +36 -0
  18. data/lib/krypt/x509/common.rb +41 -0
  19. data/lib/krypt/x509/crl.rb +33 -0
  20. data/lib/krypt_missing.rb +32 -0
  21. data/spec/krypt-core/MEMO.txt +85 -0
  22. data/spec/krypt-core/asn1/asn1_bit_string_spec.rb +475 -0
  23. data/spec/krypt-core/asn1/asn1_boolean_spec.rb +392 -0
  24. data/spec/krypt-core/asn1/asn1_constants_spec.rb +71 -0
  25. data/spec/krypt-core/asn1/asn1_data_spec.rb +1153 -0
  26. data/spec/krypt-core/asn1/asn1_end_of_contents_spec.rb +133 -0
  27. data/spec/krypt-core/asn1/asn1_enumerated_spec.rb +458 -0
  28. data/spec/krypt-core/asn1/asn1_generalized_time_spec.rb +492 -0
  29. data/spec/krypt-core/asn1/asn1_integer_spec.rb +557 -0
  30. data/spec/krypt-core/asn1/asn1_null_spec.rb +360 -0
  31. data/spec/krypt-core/asn1/asn1_object_id_spec.rb +495 -0
  32. data/spec/krypt-core/asn1/asn1_octet_string_spec.rb +456 -0
  33. data/spec/krypt-core/asn1/asn1_parser_spec.rb +503 -0
  34. data/spec/krypt-core/asn1/asn1_pem_spec.rb +282 -0
  35. data/spec/krypt-core/asn1/asn1_sequence_spec.rb +637 -0
  36. data/spec/krypt-core/asn1/asn1_set_spec.rb +795 -0
  37. data/spec/krypt-core/asn1/asn1_utc_time_spec.rb +495 -0
  38. data/spec/krypt-core/asn1/asn1_utf8_string_spec.rb +404 -0
  39. data/spec/krypt-core/asn1/resources.rb +53 -0
  40. data/spec/krypt-core/base64/base64_spec.rb +97 -0
  41. data/spec/krypt-core/digest/digest_spec.rb +707 -0
  42. data/spec/krypt-core/hex/hex_spec.rb +102 -0
  43. data/spec/krypt-core/pem/pem_decode_spec.rb +235 -0
  44. data/spec/krypt-core/resources.rb +1 -0
  45. data/spec/krypt-core/template/template_choice_parse_spec.rb +289 -0
  46. data/spec/krypt-core/template/template_dsl_spec.rb +351 -0
  47. data/spec/krypt-core/template/template_seq_of_parse_spec.rb +64 -0
  48. data/spec/krypt-core/template/template_seq_parse_spec.rb +1241 -0
  49. data/spec/krypt/codec/base64_decoder_spec.rb +94 -0
  50. data/spec/krypt/codec/base64_encoder_spec.rb +94 -0
  51. data/spec/krypt/codec/base64_mixed_spec.rb +16 -0
  52. data/spec/krypt/codec/hex_decoder_spec.rb +94 -0
  53. data/spec/krypt/codec/hex_encoder_spec.rb +94 -0
  54. data/spec/krypt/codec/hex_mixed_spec.rb +17 -0
  55. data/spec/krypt/codec/identity_shared.rb +119 -0
  56. data/spec/krypt/hmac/hmac_spec.rb +311 -0
  57. data/spec/krypt/pkcs5/pbkdf2_spec.rb +79 -0
  58. data/spec/krypt/provider/provider_spec.rb +83 -0
  59. data/spec/res/ca-bundle.crt +11758 -0
  60. data/spec/res/certificate.cer +0 -0
  61. data/spec/res/certificate.pem +20 -0
  62. data/spec/res/multiple_certs.pem +60 -0
  63. data/spec/resources.rb +66 -0
  64. data/test/helper.rb +8 -0
  65. data/test/res/certificate.cer +0 -0
  66. data/test/resources.rb +48 -0
  67. data/test/scratch.rb +28 -0
  68. data/test/test_krypt_asn1.rb +119 -0
  69. data/test/test_krypt_parser.rb +331 -0
  70. metadata +134 -0
@@ -0,0 +1,492 @@
1
+ # encoding: US-ASCII
2
+
3
+ require 'rspec'
4
+ require 'krypt'
5
+ require 'openssl'
6
+ require_relative './resources'
7
+
8
+ describe Krypt::ASN1::GeneralizedTime do
9
+ include Krypt::ASN1::Resources
10
+
11
+ let(:mod) { Krypt::ASN1 }
12
+ let(:klass) { mod::GeneralizedTime }
13
+ let(:decoder) { mod }
14
+ let(:asn1error) { mod::ASN1Error }
15
+
16
+ # For test against OpenSSL
17
+ #
18
+ #let(:mod) { OpenSSL::ASN1 }
19
+ #
20
+ # OpenSSL stub for signature mismatch
21
+ class OpenSSL::ASN1::GeneralizedTime
22
+ class << self
23
+ alias old_new new
24
+ def new(*args)
25
+ if args.size > 1
26
+ args = [args[0], args[1], :IMPLICIT, args[2]]
27
+ end
28
+ old_new(*args)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe '#new' do
34
+ context 'gets value for construct' do
35
+ subject { klass.new(value) }
36
+
37
+ context 'accepts Time' do
38
+ let(:value) { Time.now }
39
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
40
+ its(:tag_class) { should == :UNIVERSAL }
41
+ its(:value) { should == value }
42
+ its(:infinite_length) { should == false }
43
+ end
44
+
45
+ context 'accepts Integer' do
46
+ let(:value) { 0 + Time.now.to_i }
47
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
48
+ its(:tag_class) { should == :UNIVERSAL }
49
+ its(:value) { should == value }
50
+ its(:infinite_length) { should == false }
51
+ end
52
+
53
+ context 'accepts String' do
54
+ let(:value) { '' + Time.now.to_i.to_s }
55
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
56
+ its(:tag_class) { should == :UNIVERSAL }
57
+ its(:value) { should == value }
58
+ its(:infinite_length) { should == false }
59
+ end
60
+
61
+ context 'accepts 0' do
62
+ let(:value) { 0 }
63
+ its(:value) { should == value }
64
+ end
65
+ end
66
+
67
+ context 'gets explicit tag number as the 2nd argument' do
68
+ subject { klass.new(Time.now, tag, :PRIVATE) }
69
+
70
+ context 'accepts default tag' do
71
+ let(:tag) { Krypt::ASN1::GENERALIZED_TIME }
72
+ its(:tag) { should == tag }
73
+ end
74
+
75
+ context 'accepts custom tag' do
76
+ let(:tag) { 14 }
77
+ its(:tag) { should == tag }
78
+ end
79
+ end
80
+
81
+ context 'gets tag class symbol as the 3rd argument' do
82
+ subject { klass.new(Time.now, Krypt::ASN1::GENERALIZED_TIME, tag_class) }
83
+
84
+ context 'accepts :UNIVERSAL' do
85
+ let(:tag_class) { :UNIVERSAL }
86
+ its(:tag_class) { should == tag_class }
87
+ end
88
+
89
+ context 'accepts :APPLICATION' do
90
+ let(:tag_class) { :APPLICATION }
91
+ its(:tag_class) { should == tag_class }
92
+ end
93
+
94
+ context 'accepts :CONTEXT_SPECIFIC' do
95
+ let(:tag_class) { :CONTEXT_SPECIFIC }
96
+ its(:tag_class) { should == tag_class }
97
+ end
98
+
99
+ context 'accepts :PRIVATE' do
100
+ let(:tag_class) { :PRIVATE }
101
+ its(:tag_class) { should == tag_class }
102
+ end
103
+
104
+ context 'accepts :IMPLICIT' do
105
+ let(:tag_class) { :IMPLICIT }
106
+ its(:tag_class) { should == tag_class }
107
+ end
108
+
109
+ context 'accepts :EXPLICIT' do
110
+ let(:tag_class) { :EXPLICIT }
111
+ its(:tag_class) { should == tag_class }
112
+ end
113
+ end
114
+
115
+ context 'when the 2nd argument is given but 3rd argument is omitted' do
116
+ subject { klass.new(Time.now, Krypt::ASN1::GENERALIZED_TIME) }
117
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
118
+ end
119
+ end
120
+
121
+ describe 'accessors' do
122
+ describe '#value' do
123
+ subject { o = klass.new(nil); o.value = value; o }
124
+
125
+ context 'accepts Time' do
126
+ let(:value) { Time.now }
127
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
128
+ its(:tag_class) { should == :UNIVERSAL }
129
+ its(:value) { should == value }
130
+ its(:infinite_length) { should == false }
131
+ end
132
+
133
+ context 'accepts Integer' do
134
+ let(:value) { 0 + Time.now.to_i }
135
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
136
+ its(:tag_class) { should == :UNIVERSAL }
137
+ its(:value) { should == value }
138
+ its(:infinite_length) { should == false }
139
+ end
140
+
141
+ context 'accepts String' do
142
+ let(:value) { '' + Time.now.to_i.to_s }
143
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
144
+ its(:tag_class) { should == :UNIVERSAL }
145
+ its(:value) { should == value }
146
+ its(:infinite_length) { should == false }
147
+ end
148
+
149
+ context 'accepts 0' do
150
+ let(:value) { 0 }
151
+ its(:value) { should == value }
152
+ end
153
+ end
154
+
155
+ describe '#tag' do
156
+ subject { o = klass.new(nil); o.tag = tag; o }
157
+
158
+ context 'accepts default tag' do
159
+ let(:tag) { Krypt::ASN1::GENERALIZED_TIME }
160
+ its(:tag) { should == tag }
161
+ end
162
+
163
+ context 'accepts custom tag' do
164
+ let(:tag) { 14 }
165
+ its(:tag) { should == tag }
166
+ end
167
+ end
168
+
169
+ describe '#tag_class' do
170
+ subject { o = klass.new(nil); o.tag_class = tag_class; o }
171
+
172
+ context 'accepts :UNIVERSAL' do
173
+ let(:tag_class) { :UNIVERSAL }
174
+ its(:tag_class) { should == tag_class }
175
+ end
176
+
177
+ context 'accepts :APPLICATION' do
178
+ let(:tag_class) { :APPLICATION }
179
+ its(:tag_class) { should == tag_class }
180
+ end
181
+
182
+ context 'accepts :CONTEXT_SPECIFIC' do
183
+ let(:tag_class) { :CONTEXT_SPECIFIC }
184
+ its(:tag_class) { should == tag_class }
185
+ end
186
+
187
+ context 'accepts :PRIVATE' do
188
+ let(:tag_class) { :PRIVATE }
189
+ its(:tag_class) { should == tag_class }
190
+ end
191
+
192
+ context 'accepts :IMPLICIT' do
193
+ let(:tag_class) { :IMPLICIT }
194
+ its(:tag_class) { should == tag_class }
195
+ end
196
+
197
+ context 'accepts :EXPLICIT' do
198
+ let(:tag_class) { :EXPLICIT }
199
+ its(:tag_class) { should == tag_class }
200
+ end
201
+ end
202
+ end
203
+
204
+ describe '#to_der' do
205
+ context 'encodes a given value' do
206
+ subject { klass.new(value).to_der }
207
+
208
+ context 'Time' do
209
+ let(:value) { Time.utc(2012, 1, 24, 0, 0, 0) }
210
+ it { should == "\x18\x0F20120124000000Z" }
211
+ end
212
+
213
+ context 'Numeric' do
214
+ let(:value) { Time.utc(2012, 1, 24, 0, 0, 0).to_i }
215
+ it { should == "\x18\x0F20120124000000Z" }
216
+ end
217
+
218
+ context 'String' do
219
+ let(:value) { Time.utc(2012, 1, 24, 0, 0, 0).to_i }
220
+ it { should == "\x18\x0F20120124000000Z" }
221
+ end
222
+
223
+ context 'Min time representation' do
224
+ let(:value) { Time.utc(2000, 1, 1, 0, 0, 0).to_i }
225
+ it { should == "\x18\x0F20000101000000Z" }
226
+ end
227
+
228
+ context 'Max time representation' do
229
+ let(:value) { Time.utc(1999, 12, 31, 23, 59, 59).to_i }
230
+ it { should == "\x18\x0F19991231235959Z" }
231
+ end
232
+
233
+ context 'second fraction' do
234
+ pending 'ossl does not support this'
235
+ end
236
+
237
+ context 'timezone' do
238
+ pending 'ossl does not support this'
239
+ end
240
+
241
+ context '(empty)' do
242
+ let(:value) { '' }
243
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
244
+ end
245
+
246
+ context 'Bignum' do
247
+ let(:value) { 2**64 - 1 }
248
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
249
+ end
250
+
251
+ context 'negative Integer' do
252
+ let(:value) { -1 }
253
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
254
+ end
255
+
256
+ context 'String that Integer(str) barks' do
257
+ let(:value) { "ABC" }
258
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
259
+ end
260
+ end
261
+
262
+ context 'encodes tag number' do
263
+ subject { klass.new(1327330800, tag, :PRIVATE).to_der }
264
+
265
+ context 'default tag' do
266
+ let(:tag) { Krypt::ASN1::GENERALIZED_TIME }
267
+ it { should == "\xD8\x0F20120123150000Z" }
268
+ end
269
+
270
+ context 'custom tag' do
271
+ let(:tag) { 14 }
272
+ it { should == "\xCE\x0F20120123150000Z" }
273
+ end
274
+
275
+ context 'nil' do
276
+ let(:tag) { nil }
277
+ it { -> { subject }.should raise_error asn1error }
278
+ end
279
+ end
280
+
281
+ context 'encodes tag class' do
282
+ subject { klass.new(1327330800, Krypt::ASN1::GENERALIZED_TIME, tag_class).to_der }
283
+
284
+ context 'UNIVERSAL' do
285
+ let(:tag_class) { :UNIVERSAL }
286
+ it { should == "\x18\x0F20120123150000Z" }
287
+ end
288
+
289
+ context 'APPLICATION' do
290
+ let(:tag_class) { :APPLICATION }
291
+ it { should == "\x58\x0F20120123150000Z" }
292
+ end
293
+
294
+ context 'CONTEXT_SPECIFIC' do
295
+ let(:tag_class) { :CONTEXT_SPECIFIC }
296
+ it { should == "\x98\x0F20120123150000Z" }
297
+ end
298
+
299
+ context 'PRIVATE' do
300
+ let(:tag_class) { :PRIVATE }
301
+ it { should == "\xD8\x0F20120123150000Z" }
302
+ end
303
+
304
+ context 'IMPLICIT' do
305
+ let(:tag_class) { :IMPLICIT }
306
+ it { should == "\x98\x0F20120123150000Z" }
307
+ end
308
+
309
+ context 'EXPLICIT' do
310
+ let(:tag_class) { :EXPLICIT }
311
+ it { should == "\xB8\x11\x18\x0F20120123150000Z" }
312
+ end
313
+
314
+ context nil do
315
+ let(:tag_class) { nil }
316
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check nil
317
+ end
318
+
319
+ context :no_such_class do
320
+ let(:tag_class) { :no_such_class }
321
+ it { -> { subject }.should raise_error asn1error }
322
+ end
323
+ end
324
+
325
+ context 'encodes values set via accessors' do
326
+ subject {
327
+ o = klass.new(nil)
328
+ o.value = value if defined? value
329
+ o.tag = tag if defined? tag
330
+ o.tag_class = tag_class if defined? tag_class
331
+ o.to_der
332
+ }
333
+
334
+ context 'value: Time' do
335
+ let(:value) { Time.utc(2012, 1, 24, 0, 0, 0) }
336
+ it { should == "\x18\x0F20120124000000Z" }
337
+ end
338
+
339
+ context 'custom tag' do
340
+ let(:value) { Time.utc(2012, 1, 24, 0, 0, 0) }
341
+ let(:tag) { 14 }
342
+ let(:tag_class) { :PRIVATE }
343
+ it { should == "\xCE\x0F20120124000000Z" }
344
+ end
345
+
346
+ context 'tag_class' do
347
+ let(:value) { Time.utc(2012, 1, 24, 0, 0, 0) }
348
+ let(:tag_class) { :APPLICATION }
349
+ it { should == "\x58\x0F20120124000000Z" }
350
+ end
351
+ end
352
+ end
353
+
354
+ describe '#encode_to' do
355
+ context 'encodes to an IO' do
356
+ subject { klass.new(value).encode_to(io); io }
357
+
358
+ context "StringIO" do
359
+ let(:value) { 1327330800 }
360
+ let(:io) { string_io_object }
361
+ its(:written_bytes) { should == "\x18\x0F20120123150000Z" }
362
+ end
363
+
364
+ context "Object responds to :write" do
365
+ let(:value) { 1327330800 }
366
+ let(:io) { writable_object }
367
+ its(:written_bytes) { should == "\x18\x0F20120123150000Z" }
368
+ end
369
+
370
+ context "raise IO error transparently" do
371
+ let(:value) { 1327330800 }
372
+ let(:io) { io_error_object }
373
+ it { -> { subject }.should raise_error asn1error }
374
+ end
375
+ end
376
+
377
+ it 'returns self' do
378
+ obj = klass.new(1327330800)
379
+ obj.encode_to(string_io_object).should == obj
380
+ end
381
+ end
382
+
383
+ describe 'extracted from ASN1.decode' do
384
+ subject { decoder.decode(der) }
385
+
386
+ context 'extracted value' do
387
+ context 'Time' do
388
+ let(:der) { "\x18\x0F20120124000000Z" }
389
+ its(:class) { should == klass }
390
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
391
+ its(:value) { should == Time.utc(2012, 1, 24, 0, 0, 0) }
392
+ end
393
+
394
+ context 'with fraction' do
395
+ pending 'ossl does not support this'
396
+ =begin
397
+ let(:der) { "\x18\x1620120124000000.012345Z" }
398
+ its(:class) { should == klass }
399
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
400
+ its(:value) { subject.usec.should == 12345 } # TODO: ossl does not support decoding usec
401
+ =end
402
+ end
403
+
404
+ context 'Min time representation' do
405
+ let(:der) { "\x18\x0F20000101000000Z" }
406
+ its(:class) { should == klass }
407
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
408
+ its(:value) { should == Time.utc(2000, 1, 1, 0, 0, 0) }
409
+ end
410
+
411
+ context 'Max time representation' do
412
+ let(:der) { "\x18\x0F19991231235959Z" }
413
+ its(:class) { should == klass }
414
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
415
+ its(:value) { should == Time.utc(1999, 12, 31, 23, 59, 59) }
416
+ end
417
+
418
+ context 'timezone' do
419
+ context '+' do
420
+ let(:der) { "\x18\x1320000101085959+0900" }
421
+ its(:class) { should == klass }
422
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
423
+ pending 'No timezone support yet'
424
+ its(:value) { Time.utc(1999, 12, 31, 23, 59, 59) }
425
+ end
426
+
427
+ context '-' do
428
+ let(:der) { "\x18\x1319991231145959-0900" }
429
+ its(:class) { should == klass }
430
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
431
+ pending 'No timezone support yet'
432
+ its(:value) { Time.utc(1999, 12, 31, 23, 59, 59) }
433
+ end
434
+
435
+ context '+0' do
436
+ let(:der) { "\x18\x1319991231235959+0000" }
437
+ its(:class) { should == klass }
438
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
439
+ pending 'No timezone support yet'
440
+ its(:value) { Time.utc(1999, 12, 31, 23, 59, 59) }
441
+ end
442
+
443
+ context '-0' do
444
+ let(:der) { "\x18\x1319991231235959-0000" }
445
+ its(:class) { should == klass }
446
+ its(:tag) { should == Krypt::ASN1::GENERALIZED_TIME }
447
+ pending 'No timezone support yet'
448
+ its(:value) { Time.utc(1999, 12, 31, 23, 59, 59) }
449
+ end
450
+ end
451
+ end
452
+
453
+ context 'extracted tag class' do
454
+ context 'UNIVERSAL' do
455
+ let(:der) { "\x18\x0F20120123150000Z" }
456
+ its(:tag_class) { should == :UNIVERSAL }
457
+ end
458
+
459
+ context 'APPLICATION' do
460
+ let(:der) { "\x48\x0F20120123150000Z" }
461
+ its(:tag_class) { should == :APPLICATION }
462
+ end
463
+
464
+ context 'CONTEXT_SPECIFIC' do
465
+ let(:der) { "\x98\x0F20120123150000Z" }
466
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
467
+ end
468
+
469
+ context 'PRIVATE' do
470
+ let(:der) { "\xC8\x0F20120123150000Z" }
471
+ its(:tag_class) { should == :PRIVATE }
472
+ end
473
+
474
+ context "setting IMPLICIT will result in CONTEXT_SPECIFIC" do
475
+ let(:der) { "\x18\x0F20120123150000Z" }
476
+ it do
477
+ subject.tag_class = :IMPLICIT
478
+ subject.to_der.should == "\x98\x0F20120123150000Z"
479
+ end
480
+ end
481
+
482
+ context "setting EXPLICIT will reencode as CONTEXT_SPECIFIC" do
483
+ let(:der) { "\x18\x0F20120123150000Z" }
484
+ it do
485
+ subject.tag_class = :EXPLICIT
486
+ subject.tag = 0
487
+ subject.to_der.should == "\xA0\x11\x18\x0F20120123150000Z"
488
+ end
489
+ end
490
+ end
491
+ end
492
+ end