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,456 @@
1
+ # encoding: US-ASCII
2
+
3
+ require 'rspec'
4
+ require 'krypt'
5
+ require 'openssl'
6
+ require_relative './resources'
7
+
8
+ describe Krypt::ASN1::OctetString do
9
+ include Krypt::ASN1::Resources
10
+
11
+ let(:mod) { Krypt::ASN1 }
12
+ let(:klass) { mod::OctetString }
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::OctetString
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 "hello,world!"' do
38
+ let(:value) { 'hello,world!' }
39
+
40
+ its(:tag) { should == Krypt::ASN1::OCTET_STRING }
41
+ its(:tag_class) { should == :UNIVERSAL }
42
+ its(:value) { should == 'hello,world!' }
43
+ its(:infinite_length) { should == false }
44
+ end
45
+
46
+ context 'accepts (empty)' do
47
+ let(:value) { '' }
48
+ its(:value) { should == '' }
49
+ end
50
+ end
51
+
52
+ context 'gets explicit tag number as the 2nd argument' do
53
+ subject { klass.new('hello,world!', tag, :PRIVATE) }
54
+
55
+ context 'accepts default tag' do
56
+ let(:tag) { Krypt::ASN1::OCTET_STRING }
57
+ its(:tag) { should == tag }
58
+ end
59
+
60
+ context 'accepts custom tag' do
61
+ let(:tag) { 14 }
62
+ its(:tag) { should == tag }
63
+ end
64
+ end
65
+
66
+ context 'gets tag class symbol as the 3rd argument' do
67
+ subject { klass.new('hello,world!', Krypt::ASN1::OCTET_STRING, tag_class) }
68
+
69
+ context 'accepts :UNIVERSAL' do
70
+ let(:tag_class) { :UNIVERSAL }
71
+ its(:tag_class) { should == tag_class }
72
+ end
73
+
74
+ context 'accepts :APPLICATION' do
75
+ let(:tag_class) { :APPLICATION }
76
+ its(:tag_class) { should == tag_class }
77
+ end
78
+
79
+ context 'accepts :CONTEXT_SPECIFIC' do
80
+ let(:tag_class) { :CONTEXT_SPECIFIC }
81
+ its(:tag_class) { should == tag_class }
82
+ end
83
+
84
+ context 'accepts :PRIVATE' do
85
+ let(:tag_class) { :PRIVATE }
86
+ its(:tag_class) { should == tag_class }
87
+ end
88
+
89
+ context 'accepts :IMPLICIT' do
90
+ let(:tag_class) { :IMPLICIT }
91
+ its(:tag_class) { should == tag_class }
92
+ end
93
+
94
+ context 'accepts :EXPLICIT' do
95
+ let(:tag_class) { :EXPLICIT }
96
+ its(:tag_class) { should == tag_class }
97
+ end
98
+ end
99
+
100
+ context 'when the 2nd argument is given but 3rd argument is omitted' do
101
+ subject { klass.new('hello,world!', Krypt::ASN1::OCTET_STRING) }
102
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
103
+ end
104
+ end
105
+
106
+ describe 'accessors' do
107
+ describe '#value' do
108
+ subject { o = klass.new(nil); o.value = value; o }
109
+
110
+ context 'accepts "hello,world!"' do
111
+ let(:value) { 'hello,world!' }
112
+
113
+ its(:tag) { should == Krypt::ASN1::OCTET_STRING }
114
+ its(:tag_class) { should == :UNIVERSAL }
115
+ its(:value) { should == 'hello,world!' }
116
+ its(:infinite_length) { should == false }
117
+ end
118
+
119
+ context 'accepts (empty)' do
120
+ let(:value) { '' }
121
+ its(:value) { should == '' }
122
+ end
123
+ end
124
+
125
+ describe '#tag' do
126
+ subject { o = klass.new(nil); o.tag = tag; o }
127
+
128
+ context 'accepts default tag' do
129
+ let(:tag) { Krypt::ASN1::OCTET_STRING }
130
+ its(:tag) { should == tag }
131
+ end
132
+
133
+ context 'accepts custom tag' do
134
+ let(:tag) { 14 }
135
+ its(:tag) { should == tag }
136
+ end
137
+ end
138
+
139
+ describe '#tag_class' do
140
+ subject { o = klass.new(nil); o.tag_class = tag_class; o }
141
+
142
+ context 'accepts :UNIVERSAL' do
143
+ let(:tag_class) { :UNIVERSAL }
144
+ its(:tag_class) { should == tag_class }
145
+ end
146
+
147
+ context 'accepts :APPLICATION' do
148
+ let(:tag_class) { :APPLICATION }
149
+ its(:tag_class) { should == tag_class }
150
+ end
151
+
152
+ context 'accepts :CONTEXT_SPECIFIC' do
153
+ let(:tag_class) { :CONTEXT_SPECIFIC }
154
+ its(:tag_class) { should == tag_class }
155
+ end
156
+
157
+ context 'accepts :PRIVATE' do
158
+ let(:tag_class) { :PRIVATE }
159
+ its(:tag_class) { should == tag_class }
160
+ end
161
+
162
+ context 'accepts :IMPLICIT' do
163
+ let(:tag_class) { :IMPLICIT }
164
+ its(:tag_class) { should == tag_class }
165
+ end
166
+
167
+ context 'accepts :EXPLICIT' do
168
+ let(:tag_class) { :EXPLICIT }
169
+ its(:tag_class) { should == tag_class }
170
+ end
171
+ end
172
+ end
173
+
174
+ describe '#to_der' do
175
+ context 'encodes a given value' do
176
+ subject { klass.new(value).to_der }
177
+
178
+ context 'hello,world!' do
179
+ let(:value) { 'hello,world!' }
180
+ it { should == "\x04\x0Chello,world!" }
181
+ end
182
+
183
+ context '(empty)' do
184
+ let(:value) { '' }
185
+ it { should == "\x04\x00" }
186
+ end
187
+
188
+ context '999 octets' do
189
+ let(:value) { 'x' * 999 }
190
+ it { should == "\x04\x82\x03\xE7" + 'x' * 999 }
191
+ end
192
+
193
+ context '1000 octets' do
194
+ let(:value) { 'x' * 1000 }
195
+ it { should == "\x04\x82\x03\xE8" + 'x' * 1000 }
196
+ end
197
+
198
+ context '1001 octets' do
199
+ let(:value) { 'x' * 1001 }
200
+ it { should == "\x04\x82\x03\xE9" + 'x' * 1001 }
201
+ end
202
+
203
+ context 'nil' do
204
+ let(:value) { nil }
205
+ it { should == "\x04\x00" }
206
+ end
207
+ end
208
+
209
+ context 'encodes tag number' do
210
+ subject { klass.new('hello,world!', tag, :PRIVATE).to_der }
211
+
212
+ context 'default tag' do
213
+ let(:tag) { Krypt::ASN1::OCTET_STRING }
214
+ it { should == "\xC4\x0Chello,world!" }
215
+ end
216
+
217
+ context 'custom tag' do
218
+ let(:tag) { 14 }
219
+ it { should == "\xCE\x0Chello,world!" }
220
+ end
221
+
222
+ context 'nil' do
223
+ let(:tag) { nil }
224
+ it { -> { subject }.should raise_error asn1error }
225
+ end
226
+ end
227
+
228
+ context 'encodes tag class' do
229
+ subject { klass.new('hello,world!', Krypt::ASN1::OCTET_STRING, tag_class).to_der }
230
+
231
+ context 'UNIVERSAL' do
232
+ let(:tag_class) { :UNIVERSAL }
233
+ it { should == "\x04\x0Chello,world!" }
234
+ end
235
+
236
+ context 'APPLICATION' do
237
+ let(:tag_class) { :APPLICATION }
238
+ it { should == "\x44\x0Chello,world!" }
239
+ end
240
+
241
+ context 'CONTEXT_SPECIFIC' do
242
+ let(:tag_class) { :CONTEXT_SPECIFIC }
243
+ it { should == "\x84\x0Chello,world!" }
244
+ end
245
+
246
+ context 'PRIVATE' do
247
+ let(:tag_class) { :PRIVATE }
248
+ it { should == "\xC4\x0Chello,world!" }
249
+ end
250
+
251
+ context 'IMPLICIT' do
252
+ let(:tag_class) { :IMPLICIT }
253
+ it { should == "\x84\x0Chello,world!" }
254
+ end
255
+
256
+ context 'EXPLICIT' do
257
+ let(:tag_class) { :EXPLICIT }
258
+ it { should == "\xA4\x0E\x04\x0Chello,world!" }
259
+ end
260
+
261
+ context nil do
262
+ let(:tag_class) { nil }
263
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check nil
264
+ end
265
+
266
+ context :no_such_class do
267
+ let(:tag_class) { :no_such_class }
268
+ it { -> { subject }.should raise_error asn1error }
269
+ end
270
+ end
271
+
272
+ context 'encodes values set via accessors' do
273
+ subject {
274
+ o = klass.new(nil)
275
+ o.value = value if defined? value
276
+ o.tag = tag if defined? tag
277
+ o.tag_class = tag_class if defined? tag_class
278
+ o.to_der
279
+ }
280
+
281
+ context 'value: 01010101' do
282
+ let(:value) { 'hello,world!' }
283
+ it { should == "\x04\x0Chello,world!" }
284
+ end
285
+
286
+ context 'custom tag' do
287
+ let(:value) { 'hello,world!' }
288
+ let(:tag) { 14 }
289
+ let(:tag_class) { :PRIVATE }
290
+ it { should == "\xCE\x0Chello,world!" }
291
+ end
292
+
293
+ context 'tag_class' do
294
+ let(:value) { 'hello,world!' }
295
+ let(:tag_class) { :APPLICATION }
296
+ it { should == "\x44\x0Chello,world!" }
297
+ end
298
+ end
299
+
300
+ context "encodes infinite length constructed values" do
301
+ subject do
302
+ asn1 = klass.new(value)
303
+ asn1.infinite_length = true
304
+ asn1.to_der
305
+ end
306
+
307
+ context "UNIVERSAL primitive with explicit EOC" do
308
+ let(:value) { [
309
+ mod::OctetString.new("\x01"),
310
+ mod::OctetString.new("\x02"),
311
+ mod::EndOfContents.new
312
+ ] }
313
+ it { subject.should == "\x24\x80\x04\x01\x01\x04\x01\x02\x00\x00" }
314
+ end
315
+
316
+ context "UNIVERSAL primitive without explicit EOC" do
317
+ let(:value) { [
318
+ mod::OctetString.new("\x01"),
319
+ mod::OctetString.new("\x02"),
320
+ ] }
321
+ it { subject.should == "\x24\x80\x04\x01\x01\x04\x01\x02\x00\x00" }
322
+ end
323
+ end
324
+ end
325
+
326
+ describe '#encode_to' do
327
+ context 'encodes to an IO' do
328
+ subject { klass.new(value).encode_to(io); io }
329
+
330
+ context "StringIO" do
331
+ let(:value) { 'hello,world!' }
332
+ let(:io) { string_io_object }
333
+ its(:written_bytes) { should == "\x04\x0Chello,world!" }
334
+ end
335
+
336
+ context "Object responds to :write" do
337
+ let(:value) { 'hello,world!' }
338
+ let(:io) { writable_object }
339
+ its(:written_bytes) { should == "\x04\x0Chello,world!" }
340
+ end
341
+
342
+ context "raise IO error transparently" do
343
+ let(:value) { 'hello,world!' }
344
+ let(:io) { io_error_object }
345
+ it { -> { subject }.should raise_error asn1error }
346
+ end
347
+ end
348
+
349
+ it 'returns self' do
350
+ obj = klass.new('hello,world!')
351
+ obj.encode_to(string_io_object).should == obj
352
+ end
353
+ end
354
+
355
+ describe 'extracted from ASN1.decode' do
356
+ subject { decoder.decode(der) }
357
+
358
+ context 'extracted value' do
359
+ context 'hello,world!' do
360
+ let(:der) { "\x04\x0Chello,world!" }
361
+ its(:class) { should == klass }
362
+ its(:tag) { should == Krypt::ASN1::OCTET_STRING }
363
+ its(:value) { should == 'hello,world!' }
364
+ end
365
+
366
+ context '(empty)' do
367
+ let(:der) { "\x04\x00" }
368
+ its(:class) { should == klass }
369
+ its(:tag) { should == Krypt::ASN1::OCTET_STRING }
370
+ its(:value) { should == '' }
371
+ end
372
+
373
+ context '999 octets' do
374
+ let(:der) { "\x04\x82\x03\xE7" + 'x' * 999 }
375
+ its(:class) { should == klass }
376
+ its(:tag) { should == Krypt::ASN1::OCTET_STRING }
377
+ its(:value) { should == 'x' * 999 }
378
+ end
379
+
380
+ context '1000 octets' do
381
+ let(:der) { "\x04\x82\x03\xE8" + 'x' * 1000 }
382
+ its(:class) { should == klass }
383
+ its(:tag) { should == Krypt::ASN1::OCTET_STRING }
384
+ its(:value) { should == 'x' * 1000 }
385
+ end
386
+
387
+ context '1001 octets' do
388
+ let(:der) { "\x04\x82\x03\xE9" + 'x' * 1001 }
389
+ its(:class) { should == klass }
390
+ its(:tag) { should == Krypt::ASN1::OCTET_STRING }
391
+ its(:value) { should == 'x' * 1001 }
392
+ end
393
+ end
394
+
395
+ context 'extracted tag class' do
396
+ context 'UNIVERSAL' do
397
+ let(:der) { "\x04\x0Chello,world!" }
398
+ its(:tag_class) { should == :UNIVERSAL }
399
+ end
400
+
401
+ context 'APPLICATION' do
402
+ let(:der) { "\x44\x0Chello,world!" }
403
+ its(:tag_class) { should == :APPLICATION }
404
+ end
405
+
406
+ context 'CONTEXT_SPECIFIC' do
407
+ let(:der) { "\x84\x0Chello,world!" }
408
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
409
+ end
410
+
411
+ context 'PRIVATE' do
412
+ let(:der) { "\xC4\x0Chello,world!" }
413
+ its(:tag_class) { should == :PRIVATE }
414
+ end
415
+
416
+ context "setting IMPLICIT will result in CONTEXT_SPECIFIC" do
417
+ let(:der) { "\x04\x0Chello,world!" }
418
+ it do
419
+ subject.tag_class = :IMPLICIT
420
+ subject.to_der.should == "\x84\x0Chello,world!"
421
+ end
422
+ end
423
+
424
+ context "setting EXPLICIT will reencode as CONTEXT_SPECIFIC" do
425
+ let(:der) { "\x04\x0Chello,world!" }
426
+ it do
427
+ subject.tag_class = :EXPLICIT
428
+ subject.tag = 0
429
+ subject.to_der.should == "\xA0\x0E\x04\x0Chello,world!"
430
+ end
431
+ end
432
+
433
+ end
434
+
435
+ context 'infinite-length encoded octet string' do
436
+ let(:der) { "\x24\x80\x04\x01\x00\x04\x01\x01\x00\x00" }
437
+ its(:tag) { should == Krypt::ASN1::OCTET_STRING }
438
+ its(:tag_class) { should == :UNIVERSAL }
439
+ its(:infinite_length) { should == true }
440
+ it '' do
441
+ subject.should be_an_instance_of mod::OctetString
442
+ subject.value.should respond_to :each
443
+ subject.value.size.should == 2
444
+ oct1 = subject.value[0]
445
+ oct2 = subject.value[1]
446
+ [oct1, oct2].each do |oct|
447
+ oct.tag.should == Krypt::ASN1::OCTET_STRING
448
+ oct.tag_class.should == :UNIVERSAL
449
+ end
450
+ oct1.value.should == "\x00"
451
+ oct2.value.should == "\x01"
452
+ subject.to_der.should == der
453
+ end
454
+ end
455
+ end
456
+ end