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,495 @@
1
+ # encoding: US-ASCII
2
+
3
+ require 'rspec'
4
+ require 'krypt'
5
+ require 'openssl'
6
+ require_relative './resources'
7
+
8
+ describe Krypt::ASN1::UTCTime do
9
+ include Krypt::ASN1::Resources
10
+
11
+ let(:mod) { Krypt::ASN1 }
12
+ let(:klass) { mod::UTCTime }
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::UTCTime
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::UTC_TIME }
40
+ its(:tag_class) { should == :UNIVERSAL }
41
+ its(:value) { should == value }
42
+ its(:infinite_length) { should == false }
43
+ end
44
+
45
+ context 'accepts Numeric' do
46
+ let(:value) { 0 + Time.now.to_i }
47
+ its(:tag) { should == Krypt::ASN1::UTC_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::UTC_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::UTC_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::UTC_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::UTC_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::UTC_TIME }
128
+ its(:tag_class) { should == :UNIVERSAL }
129
+ its(:value) { should == value }
130
+ its(:infinite_length) { should == false }
131
+ end
132
+
133
+ context 'accepts Numeric' do
134
+ let(:value) { 0 + Time.now.to_i }
135
+ its(:tag) { should == Krypt::ASN1::UTC_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::UTC_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::UTC_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 == "\x17\x0D120124000000Z" }
211
+ end
212
+
213
+ context 'Numeric' do
214
+ let(:value) { Time.utc(2012, 1, 24, 0, 0, 0).to_i }
215
+ it { should == "\x17\x0D120124000000Z" }
216
+ end
217
+
218
+ context 'String' do
219
+ let(:value) { Time.utc(2012, 1, 24, 0, 0, 0).to_i }
220
+ it { should == "\x17\x0D120124000000Z" }
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 == "\x17\x0D000101000000Z" }
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 == "\x17\x0D991231235959Z" }
231
+ end
232
+
233
+ context 'timezone' do
234
+ pending 'ossl does not support this'
235
+ end
236
+
237
+ context '(empty)' do
238
+ let(:value) { '' }
239
+ it { -> { subject }.should raise_error asn1error }
240
+ end
241
+
242
+ context 'Bignum' do
243
+ let(:value) { 2**64 - 1 }
244
+ it { -> { subject }.should raise_error asn1error }
245
+ end
246
+
247
+ context 'negative Integer' do
248
+ let(:value) { -1 }
249
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
250
+ end
251
+
252
+ context 'String that Integer(str) barks' do
253
+ let(:value) { "ABC" }
254
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
255
+ end
256
+
257
+ context 'some object' do
258
+ let(:value) { Object.new }
259
+ it { -> { subject }.should raise_error asn1error }
260
+ end
261
+ end
262
+
263
+ context 'encodes tag number' do
264
+ subject { klass.new(1327330800, tag, :PRIVATE).to_der }
265
+
266
+ context 'default tag' do
267
+ let(:tag) { Krypt::ASN1::UTC_TIME }
268
+ it { should == "\xD7\x0D120123150000Z" }
269
+ end
270
+
271
+ context 'custom tag' do
272
+ let(:tag) { 14 }
273
+ it { should == "\xCE\x0D120123150000Z" }
274
+ end
275
+
276
+ context 'nil' do
277
+ let(:tag) { nil }
278
+ it { -> { subject }.should raise_error asn1error }
279
+ end
280
+ end
281
+
282
+ context 'encodes tag class' do
283
+ subject { klass.new(1327330800, Krypt::ASN1::UTC_TIME, tag_class).to_der }
284
+
285
+ context 'UNIVERSAL' do
286
+ let(:tag_class) { :UNIVERSAL }
287
+ it { should == "\x17\x0D120123150000Z" }
288
+ end
289
+
290
+ context 'APPLICATION' do
291
+ let(:tag_class) { :APPLICATION }
292
+ it { should == "\x57\x0D120123150000Z" }
293
+ end
294
+
295
+ context 'CONTEXT_SPECIFIC' do
296
+ let(:tag_class) { :CONTEXT_SPECIFIC }
297
+ it { should == "\x97\x0D120123150000Z" }
298
+ end
299
+
300
+ context 'PRIVATE' do
301
+ let(:tag_class) { :PRIVATE }
302
+ it { should == "\xD7\x0D120123150000Z" }
303
+ end
304
+
305
+ context 'IMPLICIT' do
306
+ let(:tag_class) { :IMPLICIT }
307
+ it { should == "\x97\x0D120123150000Z" }
308
+ end
309
+
310
+ context 'EXPLICIT' do
311
+ let(:tag_class) { :EXPLICIT }
312
+ it { should == "\xB7\x0F\x17\x0D120123150000Z" }
313
+ end
314
+
315
+ context nil do
316
+ let(:tag_class) { nil }
317
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check nil
318
+ end
319
+
320
+ context :no_such_class do
321
+ let(:tag_class) { :no_such_class }
322
+ it { -> { subject }.should raise_error asn1error }
323
+ end
324
+ end
325
+
326
+ context 'encodes values set via accessors' do
327
+ subject {
328
+ o = klass.new(nil)
329
+ o.value = value if defined? value
330
+ o.tag = tag if defined? tag
331
+ o.tag_class = tag_class if defined? tag_class
332
+ o.to_der
333
+ }
334
+
335
+ context 'value: Time' do
336
+ let(:value) { Time.utc(2012, 1, 24, 0, 0, 0) }
337
+ it { should == "\x17\x0D120124000000Z" }
338
+ end
339
+
340
+ context 'custom tag' do
341
+ let(:value) { Time.utc(2012, 1, 24, 0, 0, 0) }
342
+ let(:tag) { 14 }
343
+ let(:tag_class) { :PRIVATE }
344
+ it { should == "\xCE\x0D120124000000Z" }
345
+ end
346
+
347
+ context 'tag_class' do
348
+ let(:value) { Time.utc(2012, 1, 24, 0, 0, 0) }
349
+ let(:tag_class) { :APPLICATION }
350
+ it { should == "\x57\x0D120124000000Z" }
351
+ end
352
+ end
353
+ end
354
+
355
+ describe '#encode_to' do
356
+ context 'encodes to an IO' do
357
+ subject { klass.new(value).encode_to(io); io }
358
+
359
+ context "StringIO" do
360
+ let(:value) { 1327330800 }
361
+ let(:io) { string_io_object }
362
+ its(:written_bytes) { should == "\x17\x0D120123150000Z" }
363
+ end
364
+
365
+ context "Object responds to :write" do
366
+ let(:value) { 1327330800 }
367
+ let(:io) { writable_object }
368
+ its(:written_bytes) { should == "\x17\x0D120123150000Z" }
369
+ end
370
+
371
+ context "raise IO error transparently" do
372
+ let(:value) { 1327330800 }
373
+ let(:io) { io_error_object }
374
+ it { -> { subject }.should raise_error asn1error }
375
+ end
376
+ end
377
+
378
+ it 'returns self' do
379
+ obj = klass.new(1327330800)
380
+ obj.encode_to(string_io_object).should == obj
381
+ end
382
+ end
383
+
384
+ describe 'extracted from ASN1.decode' do
385
+ subject { decoder.decode(der) }
386
+
387
+ context 'extracted value' do
388
+ context 'Time' do
389
+ let(:der) { "\x17\x0D120123150000Z" }
390
+ its(:class) { should == klass }
391
+ its(:tag) { should == Krypt::ASN1::UTC_TIME }
392
+ its(:value) { should == Time.utc(2012, 1, 23, 15, 0, 0) }
393
+ end
394
+
395
+ context 'Min time representation' do
396
+ let(:der) { "\x17\x0D000101000000Z" }
397
+ its(:class) { should == klass }
398
+ its(:tag) { should == Krypt::ASN1::UTC_TIME }
399
+ its(:value) { should == Time.utc(2000, 1, 1, 0, 0, 0) }
400
+ end
401
+
402
+ context 'Max time representation' do
403
+ let(:der) { "\x17\x0D991231235959Z" }
404
+ its(:class) { should == klass }
405
+ its(:tag) { should == Krypt::ASN1::UTC_TIME }
406
+ its(:value) { should == Time.utc(1999, 12, 31, 23, 59, 59) }
407
+ end
408
+
409
+ context '> 69' do
410
+ let(:der) { "\x17\x0D700101000000Z" }
411
+ its(:class) { should == klass }
412
+ its(:tag) { should == Krypt::ASN1::UTC_TIME }
413
+ its(:value) { should == Time.utc(1970, 1, 1, 0, 0, 0) }
414
+ end
415
+
416
+ context 'rejects nonsensical values' do
417
+ let(:der) { "\x17\x0DABCDEFGHIJKLZ" }
418
+ it { -> { subject.value }.should raise_error asn1error }
419
+ end
420
+
421
+ context 'timezone' do
422
+ context '+' do
423
+ let(:der) { "\x17\x11000101085959+0900" }
424
+ its(:class) { should == klass }
425
+ its(:tag) { should == Krypt::ASN1::UTC_TIME }
426
+ pending 'No timezone support yet'
427
+ its(:value) { Time.utc(1999, 12, 31, 23, 59, 59) }
428
+ end
429
+
430
+ context '-' do
431
+ let(:der) { "\x17\x11991231145959-0900" }
432
+ its(:class) { should == klass }
433
+ its(:tag) { should == Krypt::ASN1::UTC_TIME }
434
+ pending 'No timezone support yet'
435
+ its(:value) { Time.utc(1999, 12, 31, 23, 59, 59) }
436
+ end
437
+
438
+ context '+0' do
439
+ let(:der) { "\x17\x11991231235959+0000" }
440
+ its(:class) { should == klass }
441
+ its(:tag) { should == Krypt::ASN1::UTC_TIME }
442
+ pending 'No timezone support yet'
443
+ its(:value) { Time.utc(1999, 12, 31, 23, 59, 59) }
444
+ end
445
+
446
+ context '-0' do
447
+ let(:der) { "\x17\x11991231235959-0000" }
448
+ its(:class) { should == klass }
449
+ its(:tag) { should == Krypt::ASN1::UTC_TIME }
450
+ pending 'No timezone support yet'
451
+ its(:value) { Time.utc(1999, 12, 31, 23, 59, 59) }
452
+ end
453
+ end
454
+ end
455
+
456
+ context 'extracted tag class' do
457
+ context 'UNIVERSAL' do
458
+ let(:der) { "\x17\x0D991231235959Z" }
459
+ its(:tag_class) { should == :UNIVERSAL }
460
+ end
461
+
462
+ context 'APPLICATION' do
463
+ let(:der) { "\x47\x0D991231235959Z" }
464
+ its(:tag_class) { should == :APPLICATION }
465
+ end
466
+
467
+ context 'CONTEXT_SPECIFIC' do
468
+ let(:der) { "\x87\x0D991231235959Z" }
469
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
470
+ end
471
+
472
+ context 'PRIVATE' do
473
+ let(:der) { "\xC7\x0D991231235959Z" }
474
+ its(:tag_class) { should == :PRIVATE }
475
+ end
476
+
477
+ context "setting IMPLICIT will result in CONTEXT_SPECIFIC" do
478
+ let(:der) { "\x17\x0D120123150000Z" }
479
+ it do
480
+ subject.tag_class = :IMPLICIT
481
+ subject.to_der.should == "\x97\x0D120123150000Z"
482
+ end
483
+ end
484
+
485
+ context "setting EXPLICIT will reencode as CONTEXT_SPECIFIC" do
486
+ let(:der) { "\x17\x0D120123150000Z" }
487
+ it do
488
+ subject.tag_class = :EXPLICIT
489
+ subject.tag = 0
490
+ subject.to_der.should == "\xA0\x0F\x17\x0D120123150000Z"
491
+ end
492
+ end
493
+ end
494
+ end
495
+ end