krypt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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