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,1153 @@
1
+ # encoding: US-ASCII
2
+
3
+ require 'rspec'
4
+ require 'krypt'
5
+ require 'openssl'
6
+ require_relative './resources'
7
+ require_relative '../resources'
8
+
9
+ describe Krypt::ASN1::ASN1Data do
10
+ include Krypt::ASN1::Resources
11
+
12
+ let(:mod) { Krypt::ASN1 }
13
+ let(:klass) { mod::ASN1Data }
14
+ let(:decoder) { mod }
15
+ let(:asn1error) { mod::ASN1Error }
16
+
17
+ # For test against OpenSSL
18
+ #
19
+ #let(:mod) { OpenSSL::ASN1 }
20
+ #
21
+ # OpenSSL stub for signature mismatch
22
+ class OpenSSL::ASN1::ASN1Data
23
+ class << self
24
+ alias old_new new
25
+ def new(*args)
26
+ if args.size > 1
27
+ args = [args[0], args[1], :IMPLICIT, args[2]]
28
+ end
29
+ old_new(*args)
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "#new" do
35
+ context "requires exactly 3 arguments" do
36
+ subject { klass.new(value, tag, tag_class) }
37
+
38
+ context "accepts any object as value" do
39
+ let(:value) { Object.new }
40
+ let(:tag) { 14 }
41
+ let(:tag_class) { :UNIVERSAL }
42
+ its(:tag) { should == 14 }
43
+ its(:tag_class) { should == :UNIVERSAL }
44
+ its(:value) { should == value }
45
+ its(:infinite_length) { should == false }
46
+ end
47
+
48
+ context "accepts nil as value" do
49
+ let(:value) { nil }
50
+ let(:tag) { 14 }
51
+ let(:tag_class) { :UNIVERSAL }
52
+ its(:tag) { should == 14 }
53
+ its(:tag_class) { should == :UNIVERSAL }
54
+ its(:value) { should == nil }
55
+ its(:infinite_length) { should == false }
56
+ end
57
+ end
58
+
59
+ context "raises ArgumentError for more or less arguments" do
60
+ it { -> { klass.new }.should raise_error ArgumentError }
61
+ it { -> { klass.new(5) }.should raise_error ArgumentError }
62
+ it { -> { klass.new(5, 2) }.should raise_error ArgumentError }
63
+ it { -> { klass.new(5, 2, :UNIVERSAL, 17) }.should raise_error ArgumentError }
64
+ end
65
+
66
+ context "gets explicit tag number as the 2nd argument" do
67
+ subject { klass.new(nil, tag, :PRIVATE) }
68
+
69
+ context "accepts tags in the UNIVERSAL range" do
70
+ let(:tag) { Krypt::ASN1::BOOLEAN }
71
+ its(:tag) { should == tag }
72
+ end
73
+
74
+ context "accepts custom tags" do
75
+ let(:tag) { 42 }
76
+ its(:tag) { should == tag }
77
+ end
78
+
79
+ context "does not accept nil as tag" do
80
+ let(:tag) { nil }
81
+ it { -> { subject }.should raise_error asn1error }
82
+ end
83
+
84
+ context "does not accept a non-Number as tag" do
85
+ let(:tag) { Object.new }
86
+ it { -> { subject }.should raise_error asn1error }
87
+ end
88
+
89
+ end
90
+
91
+ context "gets tag class symbol as the 3rd argument" do
92
+ subject { klass.new(true, 14, tag_class) }
93
+
94
+ context "accepts :UNIVERSAL" do
95
+ let(:tag_class) { :UNIVERSAL }
96
+ its(:tag_class) { should == tag_class }
97
+ end
98
+
99
+ context "accepts :APPLICATION" do
100
+ let(:tag_class) { :APPLICATION }
101
+ its(:tag_class) { should == tag_class }
102
+ end
103
+
104
+ context "accepts :CONTEXT_SPECIFIC" do
105
+ let(:tag_class) { :CONTEXT_SPECIFIC }
106
+ its(:tag_class) { should == tag_class }
107
+ end
108
+
109
+ context "accepts :PRIVATE" do
110
+ let(:tag_class) { :PRIVATE }
111
+ its(:tag_class) { should == tag_class }
112
+ end
113
+
114
+ context "accepts :IMPLICIT" do
115
+ let(:tag_class) { :IMPLICIT }
116
+ its(:tag_class) { should == tag_class }
117
+ end
118
+
119
+ context "does not accept :EXPLICIT" do
120
+ let(:tag_class) { :EXPLICIT }
121
+ it { -> { subject }.should raise_error asn1error }
122
+ end
123
+
124
+ context "does not accept unknown tag classes" do
125
+ let(:tag_class) { :IMAGINARY }
126
+ it { -> { subject }.should raise_error asn1error }
127
+ end
128
+
129
+ context "does not accept non-Symbols as tag class" do
130
+ let(:tag_class) { 7 }
131
+ it { -> { subject }.should raise_error asn1error }
132
+ end
133
+ end
134
+
135
+ describe "rejects :EXPLICIT when set via accessor" do
136
+ it "primitive UNIVERSAL" do
137
+ asn1 = klass.new(42, Krypt::ASN1::INTEGER, :UNIVERSAL)
138
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
139
+ end
140
+
141
+ it "primitive CONTEXT_SPECIFIC" do
142
+ asn1 = klass.new("42", 0, :CONTEXT_SPECIFIC)
143
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
144
+ end
145
+
146
+ it "primitive APPLICATION" do
147
+ asn1 = klass.new("42", 0, :APPLICATION)
148
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
149
+ end
150
+
151
+ it "primitive PRIVATE" do
152
+ asn1 = klass.new("42", 0, :PRIVATE)
153
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
154
+ end
155
+
156
+ it "constructive UNIVERSAL" do
157
+ asn1 = klass.new([Krypt::ASN1::Null.new], Krypt::ASN1::SEQUENCE, :UNIVERSAL)
158
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
159
+ end
160
+
161
+ it "constructive CONTEXT_SPECIFIC" do
162
+ asn1 = klass.new([Krypt::ASN1::Null.new], Krypt::ASN1::SEQUENCE, :CONTEXT_SPECIFIC)
163
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
164
+ end
165
+
166
+ it "constructive APPLICATION" do
167
+ asn1 = klass.new([Krypt::ASN1::Null.new], Krypt::ASN1::SEQUENCE, :APPLICATION)
168
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
169
+ end
170
+
171
+ it "constructive PRIVATE" do
172
+ asn1 = klass.new([Krypt::ASN1::Null.new], Krypt::ASN1::SEQUENCE, :PRIVATE)
173
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
174
+ end
175
+ end
176
+
177
+ context "returns an instance of ASN1Data, despite of an
178
+ UNIVERSAL tag and tag class" do
179
+ subject { klass.new("test", Krypt::ASN1::OCTET_STRING, :UNIVERSAL) }
180
+ it { subject.should be_an_instance_of klass }
181
+ end
182
+ end
183
+
184
+ describe Krypt::ASN1::Constructive, "#new" do
185
+ let(:klazz) { mod::Constructive }
186
+
187
+ context "requires exactly 3 arguments" do
188
+ subject { klazz.new(value, tag, tag_class) }
189
+
190
+ context "accepts any object as value" do
191
+ let(:value) { Object.new }
192
+ let(:tag) { 14 }
193
+ let(:tag_class) { :UNIVERSAL }
194
+ its(:tag) { should == 14 }
195
+ its(:tag_class) { should == :UNIVERSAL }
196
+ its(:value) { should == value }
197
+ its(:infinite_length) { should == false }
198
+ end
199
+
200
+ context "accepts nil as value" do
201
+ let(:value) { nil }
202
+ let(:tag) { 14 }
203
+ let(:tag_class) { :UNIVERSAL }
204
+ its(:tag) { should == 14 }
205
+ its(:tag_class) { should == :UNIVERSAL }
206
+ its(:value) { should == nil }
207
+ its(:infinite_length) { should == false }
208
+ end
209
+ end
210
+
211
+ context "rejects :EXPLICIT" do
212
+ it { -> { klazz.new(42, 3, :EXPLICIT) }.should raise_error asn1error }
213
+
214
+ describe "when set via accessor" do
215
+ it "constructive UNIVERSAL" do
216
+ asn1 = klazz.new([Krypt::ASN1::Null.new], Krypt::ASN1::SEQUENCE, :UNIVERSAL)
217
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
218
+ end
219
+
220
+ it "constructive CONTEXT_SPECIFIC" do
221
+ asn1 = klazz.new([Krypt::ASN1::Null.new], Krypt::ASN1::SEQUENCE, :CONTEXT_SPECIFIC)
222
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
223
+ end
224
+
225
+ it "constructive APPLICATION" do
226
+ asn1 = klazz.new([Krypt::ASN1::Null.new], Krypt::ASN1::SEQUENCE, :APPLICATION)
227
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
228
+ end
229
+
230
+ it "constructive PRIVATE" do
231
+ asn1 = klazz.new([Krypt::ASN1::Null.new], Krypt::ASN1::SEQUENCE, :PRIVATE)
232
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
233
+ end
234
+ end
235
+ end
236
+
237
+ context "raises ArgumentError for more or less arguments" do
238
+ it { -> { klazz.new }.should raise_error ArgumentError }
239
+ it { -> { klazz.new(5) }.should raise_error ArgumentError }
240
+ it { -> { klazz.new(5, 2) }.should raise_error ArgumentError }
241
+ it { -> { klazz.new(5, 2, :UNIVERSAL, 17) }.should raise_error ArgumentError }
242
+ end
243
+ end
244
+
245
+ describe Krypt::ASN1::Primitive, "#new" do
246
+ let(:klazz) { mod::Primitive }
247
+
248
+ context "requires exactly 3 arguments" do
249
+ subject { klazz.new(value, tag, tag_class) }
250
+
251
+ context "accepts any object as value" do
252
+ let(:value) { Object.new }
253
+ let(:tag) { 14 }
254
+ let(:tag_class) { :UNIVERSAL }
255
+ its(:tag) { should == 14 }
256
+ its(:tag_class) { should == :UNIVERSAL }
257
+ its(:value) { should == value }
258
+ its(:infinite_length) { should == false }
259
+ end
260
+
261
+ context "accepts nil as value" do
262
+ let(:value) { nil }
263
+ let(:tag) { 14 }
264
+ let(:tag_class) { :UNIVERSAL }
265
+ its(:tag) { should == 14 }
266
+ its(:tag_class) { should == :UNIVERSAL }
267
+ its(:value) { should == nil }
268
+ its(:infinite_length) { should == false }
269
+ end
270
+ end
271
+
272
+ context "rejects :EXPLICIT" do
273
+ it { -> { klazz.new(42, 3, :EXPLICIT) }.should raise_error asn1error }
274
+ end
275
+
276
+ describe "rejects :EXPLICIT when set via accessor" do
277
+ it "primitive UNIVERSAL" do
278
+ asn1 = klazz.new(42, Krypt::ASN1::INTEGER, :UNIVERSAL)
279
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
280
+ end
281
+
282
+ it "primitive CONTEXT_SPECIFIC" do
283
+ asn1 = klazz.new("42", 0, :CONTEXT_SPECIFIC)
284
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
285
+ end
286
+
287
+ it "primitive APPLICATION" do
288
+ asn1 = klazz.new("42", 0, :APPLICATION)
289
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
290
+ end
291
+
292
+ it "primitive PRIVATE" do
293
+ asn1 = klazz.new("42", 0, :PRIVATE)
294
+ -> { asn1.tag_class = :EXPLICIT }.should raise_error asn1error
295
+ end
296
+ end
297
+
298
+ context "raises ArgumentError for more or less arguments" do
299
+ it { -> { klazz.new }.should raise_error ArgumentError }
300
+ it { -> { klazz.new(5) }.should raise_error ArgumentError }
301
+ it { -> { klazz.new(5, 2) }.should raise_error ArgumentError }
302
+ it { -> { klazz.new(5, 2, :UNIVERSAL, 17) }.should raise_error ArgumentError }
303
+ end
304
+ end
305
+
306
+ describe "#to_der" do
307
+ context "encodes UNIVERSAL tag values as if the equivalent primitive
308
+ class was used" do
309
+ subject { klass.new(value, tag, :UNIVERSAL).to_der }
310
+
311
+ context "END_OF_CONTENTS" do
312
+ let(:tag) { Krypt::ASN1::END_OF_CONTENTS }
313
+ let(:value) { nil }
314
+ it { should == Krypt::ASN1::EndOfContents.new().to_der }
315
+ end
316
+
317
+ context "BOOLEAN" do
318
+ let(:tag) { Krypt::ASN1::BOOLEAN }
319
+ let(:value) { true }
320
+ it { should == Krypt::ASN1::Boolean.new(true).to_der }
321
+ end
322
+
323
+ context "PRINTABLE_STRING" do
324
+ let(:tag) { Krypt::ASN1::PRINTABLE_STRING }
325
+ let(:value) { "test" }
326
+ it { should == Krypt::ASN1::PrintableString.new("test").to_der }
327
+ end
328
+
329
+ context "SEQUENCE" do
330
+ let(:tag) { Krypt::ASN1::SEQUENCE }
331
+ let(:value) { [Krypt::ASN1::Integer.new(1)] }
332
+ it { should == Krypt::ASN1::Sequence.new([Krypt::ASN1::Integer.new(1)]).to_der }
333
+ end
334
+
335
+ context "SET" do
336
+ let(:tag) { Krypt::ASN1::SET }
337
+ let(:value) { [Krypt::ASN1::Integer.new(1), Krypt::ASN1::Boolean.new(true)] }
338
+ it { should == Krypt::ASN1::Set.new([Krypt::ASN1::Integer.new(1), Krypt::ASN1::Boolean.new(true)]).to_der }
339
+ end
340
+ end
341
+
342
+ context "expects raw byte strings for non-universal tags" do
343
+ subject { klass.new(value, tag, tag_class).to_der }
344
+
345
+ context ":PRIVATE tag class" do
346
+ let(:tag_class) { :PRIVATE }
347
+ let(:value) { "\xC0\xFF\xEE\xBA\xBE" }
348
+
349
+ context "tag < 30" do
350
+ let(:tag) { Krypt::ASN1::BOOLEAN }
351
+ it { should == "\xC1\x05\xC0\xFF\xEE\xBA\xBE" }
352
+ end
353
+
354
+ context "tag > 30" do
355
+ let(:tag) { 42 }
356
+ it { should == "\xDF\x2A\x05\xC0\xFF\xEE\xBA\xBE" }
357
+ end
358
+ end
359
+
360
+ context ":APPLICATION tag class" do
361
+ let(:tag_class) { :APPLICATION }
362
+ let(:value) { "\xC0\xFF\xEE\xBA\xBE" }
363
+
364
+ context "tag < 30" do
365
+ let(:tag) { Krypt::ASN1::BOOLEAN }
366
+ it { should == "\x41\x05\xC0\xFF\xEE\xBA\xBE" }
367
+ end
368
+
369
+ context "tag > 30" do
370
+ let(:tag) { 42 }
371
+ it { should == "\x5F\x2A\x05\xC0\xFF\xEE\xBA\xBE" }
372
+ end
373
+ end
374
+
375
+ context ":CONTEXT_SPECIFIC tag class" do
376
+ let(:tag_class) { :CONTEXT_SPECIFIC }
377
+ let(:value) { "\xC0\xFF\xEE\xBA\xBE" }
378
+
379
+ context "tag < 30" do
380
+ let(:tag) { Krypt::ASN1::BOOLEAN }
381
+ it { should == "\x81\x05\xC0\xFF\xEE\xBA\xBE" }
382
+ end
383
+
384
+ context "tag > 30" do
385
+ let(:tag) { 42 }
386
+ it { should == "\x9F\x2A\x05\xC0\xFF\xEE\xBA\xBE" }
387
+ end
388
+ end
389
+
390
+ context ":IMPLICIT tag class" do
391
+ let(:tag_class) { :IMPLICIT }
392
+ let(:value) { "\xC0\xFF\xEE\xBA\xBE" }
393
+
394
+ context "tag < 30" do
395
+ let(:tag) { Krypt::ASN1::BOOLEAN }
396
+ it { should == "\x81\x05\xC0\xFF\xEE\xBA\xBE" }
397
+ end
398
+
399
+ context "tag > 30" do
400
+ let(:tag) { 42 }
401
+ it { should == "\x9F\x2A\x05\xC0\xFF\xEE\xBA\xBE" }
402
+ end
403
+ end
404
+ end
405
+
406
+ context "decides dynamically whether to encode non-UNIVERSAL data
407
+ as as constructed or a primitive encoding" do
408
+ it "when constructing an implicitly 0-tagged BOOLEAN" do
409
+ klass.new("\xFF", 0, :CONTEXT_SPECIFIC).to_der.should == "\x80\x01\xFF"
410
+ end
411
+
412
+ it "when constructing an explicitly 0-tagged BOOLEAN" do
413
+ asn1 = klass.new([Krypt::ASN1::Boolean.new(true)], 0, :CONTEXT_SPECIFIC)
414
+ asn1.to_der.should == "\xA0\x03\x01\x01\xFF"
415
+ end
416
+
417
+ it "when setting the value from a primitive value to an Enumerable" do
418
+ asn1 = klass.new("\xFF", 0, :CONTEXT_SPECIFIC)
419
+ asn1.to_der.should == "\x80\x01\xFF"
420
+ asn1.value = [Krypt::ASN1::Boolean.new(true)]
421
+ asn1.to_der.should == "\xA0\x03\x01\x01\xFF"
422
+ end
423
+
424
+ it "when setting the value from an Enumerable to a primitive value" do
425
+ asn1 = klass.new([Krypt::ASN1::Boolean.new(true)], 0, :CONTEXT_SPECIFIC)
426
+ asn1.to_der.should == "\xA0\x03\x01\x01\xFF"
427
+ asn1.value = "\xFF"
428
+ asn1.to_der.should == "\x80\x01\xFF"
429
+ end
430
+ end
431
+
432
+ context "decides dynamically how to encode UNIVERSAL data" do
433
+ subject { klass.new("\x01", 0, :CONTEXT_SPECIFIC) }
434
+
435
+ it "when resetting tag and value with a Primitive" do
436
+ subject.to_der.should == "\x80\x01\x01"
437
+ subject.tag = Krypt::ASN1::INTEGER
438
+ subject.to_der.should == "\x82\x01\x01"
439
+ subject.tag_class = :UNIVERSAL
440
+ subject.value = 1
441
+ subject.to_der.should == "\x02\x01\x01"
442
+ end
443
+
444
+ it "when resetting tag and value with a Constructive" do
445
+ subject.to_der.should == "\x80\x01\x01"
446
+ subject.tag = Krypt::ASN1::SEQUENCE
447
+ subject.to_der.should == "\x90\x01\x01"
448
+ subject.tag_class = :UNIVERSAL
449
+ subject.value = [ Krypt::ASN1::EndOfContents.new ]
450
+ subject.to_der.should == "\x30\x02\x00\x00"
451
+ end
452
+ end
453
+
454
+ context "encodes infinite length tagged values" do
455
+ subject do
456
+ asn1 = klass.new(value, 0, :CONTEXT_SPECIFIC)
457
+ asn1.infinite_length = true
458
+ asn1.to_der
459
+ end
460
+
461
+ context "SEQUENCE" do
462
+ let(:value) { [mod::Integer.new(1), mod::EndOfContents.new] }
463
+ it { subject.should == "\xA0\x80\x02\x01\x01\x00\x00" }
464
+ end
465
+
466
+ context "OCTET STRING" do
467
+ let(:value) { [mod::OctetString.new("\x00"), mod::OctetString.new("\x01"), mod::EndOfContents.new] }
468
+ it { subject.should == "\xA0\x80\x04\x01\x00\x04\x01\x01\x00\x00" }
469
+ end
470
+ end
471
+
472
+ context "encodes infinite length constructed values" do
473
+ subject do
474
+ asn1 = klass.new(value, tag, tag_class)
475
+ asn1.infinite_length = true
476
+ asn1.to_der
477
+ end
478
+
479
+ context "UNIVERSAL primitive with explicit EOC" do
480
+ let(:value) { [
481
+ mod::OctetString.new("\x01"),
482
+ mod::OctetString.new("\x02"),
483
+ mod::EndOfContents.new
484
+ ] }
485
+ let(:tag) { Krypt::ASN1::OCTET_STRING }
486
+ let(:tag_class) { :UNIVERSAL }
487
+ it { subject.should == "\x24\x80\x04\x01\x01\x04\x01\x02\x00\x00" }
488
+ end
489
+
490
+ context "UNIVERSAL primitive without explicit EOC" do
491
+ let(:value) { [
492
+ mod::OctetString.new("\x01"),
493
+ mod::OctetString.new("\x02"),
494
+ ] }
495
+ let(:tag) { Krypt::ASN1::OCTET_STRING }
496
+ let(:tag_class) { :UNIVERSAL }
497
+ it { subject.should == "\x24\x80\x04\x01\x01\x04\x01\x02\x00\x00" }
498
+ end
499
+
500
+ context "UNIVERSAL constructed with explicit EOC" do
501
+ let(:value) { [
502
+ mod::Integer.new(1),
503
+ mod::Boolean.new(true),
504
+ mod::EndOfContents.new
505
+ ] }
506
+ let(:tag) { Krypt::ASN1::SEQUENCE }
507
+ let(:tag_class) { :UNIVERSAL }
508
+ it { subject.should == "\x30\x80\x02\x01\x01\x01\x01\xFF\x00\x00" }
509
+ end
510
+
511
+ context "UNIVERSAL constructed without explicit EOC" do
512
+ let(:value) { [
513
+ mod::Integer.new(1),
514
+ mod::Boolean.new(true),
515
+ ] }
516
+ let(:tag) { Krypt::ASN1::SEQUENCE }
517
+ let(:tag_class) { :UNIVERSAL }
518
+ it { subject.should == "\x30\x80\x02\x01\x01\x01\x01\xFF\x00\x00" }
519
+ end
520
+
521
+ context "implicitly 0-tagged constructed with explicit EOC" do
522
+ let(:value) { [
523
+ mod::Integer.new(1),
524
+ mod::Boolean.new(true),
525
+ mod::EndOfContents.new
526
+ ] }
527
+ let(:tag) { 0 }
528
+ let(:tag_class) { :CONTEXT_SPECIFIC }
529
+ it { subject.should == "\xA0\x80\x02\x01\x01\x01\x01\xFF\x00\x00" }
530
+ end
531
+
532
+ context "implicitly 0-tagged constructed without explicit EOC" do
533
+ let(:value) { [
534
+ mod::Integer.new(1),
535
+ mod::Boolean.new(true),
536
+ mod::EndOfContents.new
537
+ ] }
538
+ let(:tag) { 0 }
539
+ let(:tag_class) { :CONTEXT_SPECIFIC }
540
+ it { subject.should == "\xA0\x80\x02\x01\x01\x01\x01\xFF\x00\x00" }
541
+ end
542
+
543
+ context "nested with explicit EOC" do
544
+ let(:value) do
545
+ inner = mod::OctetString.new([
546
+ mod::OctetString.new("\x01"),
547
+ mod::OctetString.new("\x02"),
548
+ mod::EndOfContents.new
549
+ ])
550
+ inner.infinite_length = true
551
+ [
552
+ inner,
553
+ mod::Integer.new(1),
554
+ mod::EndOfContents.new
555
+ ]
556
+ end
557
+ let(:tag) { mod::SEQUENCE }
558
+ let(:tag_class) { :UNIVERSAL }
559
+ it { subject.should == "\x30\x80\x24\x80\x04\x01\x01\x04\x01\x02\x00\x00\x02\x01\x01\x00\x00" }
560
+ end
561
+
562
+ context "nested without explicit EOC" do
563
+ let(:value) do
564
+ inner = mod::OctetString.new([
565
+ mod::OctetString.new("\x01"),
566
+ mod::OctetString.new("\x02"),
567
+ ])
568
+ inner.infinite_length = true
569
+ [
570
+ inner,
571
+ mod::Integer.new(1),
572
+ ]
573
+ end
574
+ let(:tag) { mod::SEQUENCE }
575
+ let(:tag_class) { :UNIVERSAL }
576
+ it { subject.should == "\x30\x80\x24\x80\x04\x01\x01\x04\x01\x02\x00\x00\x02\x01\x01\x00\x00" }
577
+ end
578
+
579
+ context "enumerable with explicit EOC" do
580
+ let(:value) do
581
+ o = Object.new
582
+ def o.each
583
+ yield Krypt::ASN1::OctetString.new("\x01")
584
+ yield Krypt::ASN1::OctetString.new("\x02")
585
+ yield Krypt::ASN1::EndOfContents.new
586
+ end
587
+ o
588
+ end
589
+ let(:tag) { mod::SEQUENCE }
590
+ let(:tag_class) { :UNIVERSAL }
591
+ it { subject.should == "\x30\x80\x04\x01\x01\x04\x01\x02\x00\x00" }
592
+ end
593
+
594
+ context "enumerable without explicit EOC" do
595
+ let(:value) do
596
+ o = Object.new
597
+ def o.each
598
+ yield Krypt::ASN1::OctetString.new("\x01")
599
+ yield Krypt::ASN1::OctetString.new("\x02")
600
+ end
601
+ o
602
+ end
603
+ let(:tag) { mod::SEQUENCE }
604
+ let(:tag_class) { :UNIVERSAL }
605
+ it { subject.should == "\x30\x80\x04\x01\x01\x04\x01\x02\x00\x00" }
606
+ end
607
+ end
608
+
609
+ context "all STRING classes except BIT STRING and UTF8 STRING behave like OCTET STRING" do
610
+ subject { decoder.decode(klazz.new("test").to_der).value == "test" }
611
+
612
+ context "OCTET STRING" do
613
+ let(:klazz) { mod::OctetString }
614
+ it { should == true }
615
+ end
616
+
617
+ context "NUMERIC STRING" do
618
+ let(:klazz) { mod::NumericString }
619
+ it { should == true }
620
+ end
621
+
622
+ context "PRINTABLE STRING" do
623
+ let(:klazz) { mod::PrintableString }
624
+ it { should == true }
625
+ end
626
+
627
+ context "T61 STRING" do
628
+ let(:klazz) { mod::T61String }
629
+ it { should == true }
630
+ end
631
+
632
+ context "VIDEOTEX STRING" do
633
+ let(:klazz) { mod::VideotexString }
634
+ it { should == true }
635
+ end
636
+
637
+ context "IA5 STRING" do
638
+ let(:klazz) { mod::IA5String }
639
+ it { should == true }
640
+ end
641
+
642
+ context "GRAPHIC STRING" do
643
+ let(:klazz) { mod::GraphicString }
644
+ it { should == true }
645
+ end
646
+
647
+ context "ISO64 STRING" do
648
+ let(:klazz) { mod::ISO64String }
649
+ it { should == true }
650
+ end
651
+
652
+ context "GENERAL STRING" do
653
+ let(:klazz) { mod::GeneralString }
654
+ it { should == true }
655
+ end
656
+
657
+ context "UNIVERSAL STRING" do
658
+ let(:klazz) { mod::UniversalString }
659
+ it { should == true }
660
+ end
661
+
662
+ context "BMP STRING" do
663
+ let(:klazz) { mod::BMPString }
664
+ it { should == true }
665
+ end
666
+ end
667
+
668
+ context "rejects UNIVERSAL tags > 30" do
669
+ it { -> { klass.new("\xFF", 31, :UNIVERSAL).to_der }.should raise_error asn1error }
670
+ end
671
+
672
+ it "rejects constructed primitive values that are not infinite length" do
673
+ asn1 = mod::OctetString.new [mod::OctetString.new("\x00"), mod::EndOfContents.new]
674
+ -> { asn1.to_der }.should raise_error asn1error
675
+ end
676
+
677
+ it "allows to encode constructed primitive values that are infinite length" do
678
+ asn1 = mod::OctetString.new [mod::OctetString.new("\x00"), mod::EndOfContents.new]
679
+ asn1.infinite_length = true
680
+ asn1.to_der.should == "\x24\x80\x04\x01\x00\x00\x00"
681
+ end
682
+
683
+ it "rejects primitive SEQUENCE values" do
684
+ asn1 = mod::Sequence.new(1)
685
+ -> { asn1.to_der }.should raise_error asn1error
686
+ end
687
+
688
+ it "rejects primitive SET values" do
689
+ asn1 = mod::Set.new(1)
690
+ -> { asn1.to_der }.should raise_error asn1error
691
+ end
692
+ end
693
+
694
+ describe "#encode_to" do
695
+ context "encodes to an IO" do
696
+ subject { klass.new("\xFF", 0, :CONTEXT_SPECIFIC).encode_to(io); io }
697
+
698
+ context "StringIO" do
699
+ let(:io) { string_io_object }
700
+ its(:written_bytes) { should == "\x80\x01\xFF" }
701
+ end
702
+
703
+ context "Object responds to :write" do
704
+ let(:io) { writable_object }
705
+ its(:written_bytes) { should == "\x80\x01\xFF" }
706
+ end
707
+
708
+ it "encodes to File IO" do
709
+ #io = File.open(IO::NULL, "wb") # not defined in JRuby yet
710
+ io = File.open("/dev/null", "wb")
711
+ begin
712
+ klass.new("\xFF", 0, :CONTEXT_SPECIFIC).encode_to(io)
713
+ ensure
714
+ io.close
715
+ end
716
+ end if File.exists?("/dev/null")
717
+
718
+ context "raise IO error transparently" do
719
+ let(:io) { io_error_object }
720
+ it { -> { subject }.should raise_error asn1error }
721
+ end
722
+ end
723
+
724
+ it "returns self" do
725
+ obj = klass.new(nil, Krypt::ASN1::END_OF_CONTENTS, :UNIVERSAL)
726
+ obj.encode_to(string_io_object).should == obj
727
+ end
728
+ end
729
+
730
+ describe "<=>" do
731
+ context "determines equality based on equality of the DER encoding" do
732
+ context "when equal" do
733
+ let(:v1) { decoder.decode("\x30\x03\x02\x01\x01") }
734
+ let(:v2) { decoder.decode("\x30\x03\x02\x01\x01") }
735
+ it { v1.should == v2 && v1.eql?(v2).should == false }
736
+ end
737
+
738
+ context "finds a value encoded and reparsed to be equal to itself" do
739
+ let(:v1) { decoder.decode("\x30\x03\x02\x01\x01") }
740
+ it { v1.should == (decoder.decode(v1.to_der)) }
741
+ end
742
+
743
+ context "when not equal" do
744
+ let(:v1) { decoder.decode("\x30\x03\x03\x01\x01") }
745
+ let(:v2) { decoder.decode("\x30\x03\x02\x01\x01") }
746
+ it { v1.should_not == v2 }
747
+ end
748
+
749
+ context "when equal in terms of DER but not BER" do
750
+ let(:v1) { decoder.decode("\x30\x83\x00\x00\x03\x02\x01\x01") }
751
+ let(:v2) { decoder.decode("\x30\x03\x02\x01\x01") }
752
+ it { v1.should_not == v2 }
753
+ end
754
+ end
755
+
756
+ context "orders the values by tag" do
757
+ let(:v1) { decoder.decode("\x02\x01\x01") }
758
+ let(:v2) { decoder.decode("\x05\x00") }
759
+ let(:v3) { decoder.decode("\x13\x03abc") }
760
+ it { v1.should < v2 }
761
+ it { v2.should < v3 }
762
+ it { v1.should < v3 } #transitivity
763
+ end
764
+
765
+ context "orders the values in lexographical bit order when tag is equal" do
766
+ let(:v1) { decoder.decode("\x13\x01\x01") }
767
+ let(:v2) { decoder.decode("\x13\x03\x00\x00\x00") }
768
+ let(:v3) { decoder.decode("\x13\x05\x00\x00\x00\x00\x00") }
769
+ it { v1.should < v2 }
770
+ it { v2.should < v3 }
771
+ it { v1.should < v3 }
772
+ end
773
+ end
774
+
775
+ describe "extracted from ASN1" do
776
+ subject { decoder.send(method, "#{tag}#{length}#{value}") }
777
+
778
+ [:decode, :decode_der].each do |m|
779
+ let(:method) { m }
780
+
781
+ context "for all non-UNIVERSAL primitive values" do
782
+ let(:length) { "\x01" }
783
+ let(:value) { "\xFF" }
784
+
785
+ context ":PRIVATE" do
786
+ let(:tag) { "\xC0" }
787
+ its(:tag) { should == 0 }
788
+ its(:tag_class) { should == :PRIVATE }
789
+ its(:value) { should == value }
790
+ it { subject.should be_an_instance_of klass }
791
+ end
792
+
793
+ context ":APPLICATION" do
794
+ let(:tag) { "\x40" }
795
+ its(:tag) { should == 0 }
796
+ its(:tag_class) { should == :APPLICATION }
797
+ its(:value) { should == value }
798
+ it { subject.should be_an_instance_of klass }
799
+ end
800
+
801
+ context ":CONTEXT_SPECIFIC" do
802
+ let(:tag) { "\x80" }
803
+ its(:tag) { should == 0 }
804
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
805
+ its(:value) { should == value }
806
+ it { subject.should be_an_instance_of klass }
807
+ end
808
+ end
809
+
810
+ context "ASN1Constructive is returned for all non-UNIVERSAL constructed values" do
811
+ context "implicitly 0-tagged sequence" do
812
+ let(:tag) { "\xA0" }
813
+ let(:length) { "\x03" }
814
+ let(:value) { "\x02\x01\x00" }
815
+ its(:tag) { should == 0 }
816
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
817
+ it "" do
818
+ subject.value.should respond_to :each
819
+ subject.value.size.should == 1
820
+ int = subject.value.first
821
+ int.tag.should == Krypt::ASN1::INTEGER
822
+ int.tag_class.should == :UNIVERSAL
823
+ int.value.should == 0
824
+ subject.should be_an_instance_of mod::Constructive
825
+ end
826
+ end
827
+
828
+ context "explicitly 1-tagged integer" do
829
+ let(:tag) { "\xA1" }
830
+ let(:length) { "\x03" }
831
+ let(:value) { "\x02\x01\x00" }
832
+ its(:tag) { should == 1 }
833
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
834
+ it "" do
835
+ subject.should be_an_instance_of mod::Constructive
836
+ subject.value.should respond_to :each
837
+ subject.value.size.should == 1
838
+ int = subject.value.first
839
+ int.tag.should == Krypt::ASN1::INTEGER
840
+ int.tag_class.should == :UNIVERSAL
841
+ int.value.should == 0
842
+ end
843
+ end
844
+
845
+ context "infinite-length 0-tagged octet string" do
846
+ let(:tag) { "\xA0" }
847
+ let(:length) { "\x80" }
848
+ let(:value) { "\x04\x01\x00\x04\x01\x01\x00\x00" }
849
+ its(:tag) { should == 0 }
850
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
851
+ its(:infinite_length) { should be_true }
852
+ it do
853
+ subject.should be_an_instance_of mod::Constructive
854
+ subject.value.should respond_to :each
855
+ subject.value.size.should == 2
856
+ oct1 = subject.value[0]
857
+ oct2 = subject.value[1]
858
+ [oct1, oct2].each do |oct|
859
+ oct.tag.should == Krypt::ASN1::OCTET_STRING
860
+ oct.tag_class.should == :UNIVERSAL
861
+ end
862
+ oct1.value.should == "\x00"
863
+ oct2.value.should == "\x01"
864
+ end
865
+ end
866
+ end
867
+
868
+ context "drops the EOC when parsing" do
869
+ context"and encoding again" do
870
+ let(:tag) { "\x30" }
871
+ let(:length) { "\x80" }
872
+ let(:value) { "\x02\x01\x01\x00\x00" }
873
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
874
+ its(:tag_class) { should == :UNIVERSAL }
875
+ its(:infinite_length) { should be_true }
876
+ its(:to_der) { should == "\x30\x80\x02\x01\x01\x00\x00" }
877
+ end
878
+
879
+ context"and inspecting the values" do
880
+ let(:tag) { "\x30" }
881
+ let(:length) { "\x80" }
882
+ let(:value) { "\x02\x01\x01\x00\x00" }
883
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
884
+ its(:tag_class) { should == :UNIVERSAL }
885
+ its(:infinite_length) { should be_true }
886
+ it do
887
+ subject.value.should respond_to :each
888
+ subject.value.size.should == 1
889
+ int = subject.value[0]
890
+ int.tag.should == Krypt::ASN1::INTEGER
891
+ int.tag_class.should == :UNIVERSAL
892
+ int.infinite_length.should be_false
893
+ subject.to_der.should == "\x30\x80\x02\x01\x01\x00\x00"
894
+ end
895
+ end
896
+
897
+ context "rejects an encoding without EOC" do
898
+ let(:tag) { "\x30" }
899
+ let(:length) { "\x80" }
900
+ let(:value) { "\x02\x01\x01" }
901
+ it { -> { subject.value }.should raise_error asn1error }
902
+ end
903
+ end
904
+
905
+ context "accepts BER redundant length encodings" do
906
+ let(:tag) { "\x04" }
907
+ let(:length) { "\x81\x01" }
908
+ let(:value) { "\x02" }
909
+ its(:tag) { should == Krypt::ASN1::OCTET_STRING }
910
+ its(:tag_class) { should == :UNIVERSAL }
911
+ its(:infinite_length) { should == false }
912
+ its(:to_der) { should == "#{tag}#{length}#{value}" }
913
+ it do
914
+ subject.value = "\x03" #forces re-encoding in DER
915
+ subject.to_der.should == "\x04\x01\x03"
916
+ end
917
+ end
918
+
919
+ context "accepts BER redundant length encodings multiple octets" do
920
+ context do
921
+ let(:tag) { "\x04" }
922
+ let(:length) { "\x8A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" }
923
+ let(:value) { "\x01" }
924
+ its(:tag) { should == Krypt::ASN1::OCTET_STRING }
925
+ its(:tag_class) { should == :UNIVERSAL }
926
+ its(:infinite_length) { should == false }
927
+ its(:to_der) { should == "#{tag}#{length}#{value}" }
928
+ it do
929
+ subject.value = "\x02" #forces re-encoding in DER
930
+ subject.to_der.should == "\x04\x01\x02"
931
+ end
932
+ end
933
+
934
+ context do
935
+ let(:tag) { "\x80" }
936
+ let(:length) { "\x8A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" }
937
+ let(:value) { "" }
938
+ its(:tag) { should == 0 }
939
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
940
+ its(:infinite_length) { should == false }
941
+ its(:to_der) { should == "#{tag}#{length}" }
942
+ it do
943
+ subject.value = nil #forces re-encoding in DER
944
+ subject.to_der.should == "\x80\x00"
945
+ end
946
+ end
947
+ end
948
+
949
+ context "rejects length encodings that exceed max Fixnum size" do
950
+ let(:tag) { "\x04" }
951
+ let(:length) { "\x8A\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" }
952
+ let(:value) { "\x01" }
953
+ it { -> { subject }.should raise_error asn1error }
954
+ end
955
+
956
+ context "rejects reserved initial octet 11111111 for long definite length
957
+ encodings" do
958
+ let(:tag) { "\x80" }
959
+ let(:length) { "\xFF\x01\x00" }
960
+ let(:value) { "" }
961
+ it { -> { subject }.should raise_error asn1error }
962
+ end
963
+
964
+ context "accepts BER redundant tag encodings single octet" do
965
+ let(:tag) { "\x1F\x02" }
966
+ let(:length) { "\x01" }
967
+ let(:value) { "\x01" }
968
+ its(:tag) { should == Krypt::ASN1::INTEGER }
969
+ its(:tag_class) { should == :UNIVERSAL }
970
+ its(:infinite_length) { should == false }
971
+ its(:to_der) { should == "#{tag}#{length}#{value}" }
972
+ it do
973
+ subject.value = 2 # does not force re-encoding in DER, since tag isn't changed
974
+ subject.to_der.should == "#{tag}#{length}\x02"
975
+ subject.tag_class = :CONTEXT_SPECIFIC
976
+ subject.to_der.should == "\x82\x01\x02"
977
+ end
978
+ end
979
+
980
+ context "rejects BER complex tag encodings where the first octet has
981
+ bits 7 to 1 set to 0" do
982
+ let(:tag) { "\x1F\x80\x80\x02" }
983
+ let(:length) { "\x01" }
984
+ let(:value) { "\x01" }
985
+ it { -> { subject }.should raise_error asn1error }
986
+ end
987
+
988
+ context "rejects complex tag encodings where the tag exceeds max Fixnum
989
+ value" do
990
+ let(:tag) { "\x1F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F" }
991
+ let(:length) { "\x00" }
992
+ let(:value) { "" }
993
+ it { -> { subject }.should raise_error asn1error }
994
+ end
995
+
996
+ context "rejects infinite length primitive values" do
997
+ let(:tag) { "\x80" }
998
+ let(:length) { "\x80" }
999
+ let(:value) { "\x01\x01\xFF\x00\x00" }
1000
+ it { -> { subject }.should raise_error asn1error }
1001
+ end
1002
+
1003
+ context "rejects UNIVERSAL tags > 30" do
1004
+ let(:tag) { "\x1F\x42" }
1005
+ let(:length) { "\x01" }
1006
+ let(:value) { "\x00" }
1007
+ it { -> { subject }.should raise_error asn1error }
1008
+ end
1009
+
1010
+ context "raises ParseError if premature EOF is detected" do
1011
+ let(:tag) { "\x02" }
1012
+ let(:length) { "\x02" }
1013
+ let(:value) { "\x00" }
1014
+ it { -> { subject }.should raise_error asn1error }
1015
+ end
1016
+
1017
+ context "raises ParseError if header ends prematurely" do
1018
+ let(:tag) { "" }
1019
+ let(:length) { "" }
1020
+ let(:value) { "" }
1021
+ it { -> { subject }.should raise_error asn1error }
1022
+ end
1023
+
1024
+ it "decodes arbitrary objects that respond to #to_der" do
1025
+ o = Object.new
1026
+ def o.to_der
1027
+ "\x02\x01\x01"
1028
+ end
1029
+ asn1 = decoder.decode(o)
1030
+ asn1.tag.should == mod::INTEGER
1031
+ asn1.value.should == 1
1032
+ end
1033
+
1034
+ it "decodes files" do
1035
+ io = Resources.certificate_io
1036
+ begin
1037
+ asn1 = decoder.decode(io)
1038
+ asn1.tag.should == mod::SEQUENCE
1039
+ asn1.to_der.should == Resources.certificate
1040
+ ensure
1041
+ io.close
1042
+ end
1043
+ end
1044
+
1045
+ context "handles 'unknown' tag number (13) as binary content" do
1046
+ context "primitive" do
1047
+ let(:tag) { "\x0D" }
1048
+ let(:length) { "\x01" }
1049
+ let(:value) { "\x01" }
1050
+ its(:tag) { should == 13 }
1051
+ its(:tag_class) { should == :UNIVERSAL }
1052
+ its(:value) { should == "\x01" }
1053
+ end
1054
+
1055
+ context "constructive" do
1056
+ let(:tag) { "\x2D" }
1057
+ let(:length) { "\x03" }
1058
+ let(:value) { "\x02\x01\x01" }
1059
+ its(:tag) { should == 13 }
1060
+ its(:tag_class) { should == :UNIVERSAL }
1061
+ its(:value) { should be_an_instance_of Array }
1062
+ it do
1063
+ content = subject.value
1064
+ content.size.should == 1
1065
+ int = content[0]
1066
+ int.tag.should == Krypt::ASN1::INTEGER
1067
+ int.tag_class.should == :UNIVERSAL
1068
+ int.value.should == 1
1069
+ end
1070
+ end
1071
+ end
1072
+
1073
+ it "should parse indefinite length constructive" do
1074
+ raw = "\x30\x80\x02\x01\x01\x80\x01\x02\x00\x00"
1075
+ asn1 = decoder.decode(raw)
1076
+ asn1.value.size.should == 2
1077
+ asn1.value.any? { |o| o.instance_of? Krypt::ASN1::EndOfContents }.should be_false
1078
+ end
1079
+ end
1080
+
1081
+ it "should handle IO as an IO" do
1082
+ io = StringIO.new(
1083
+ [
1084
+ Krypt::ASN1::Null.new,
1085
+ Krypt::ASN1::Integer.new(0)
1086
+ ].map { |e| e.to_der }.join
1087
+ )
1088
+ decoder.decode_der(io).should be_an_instance_of Krypt::ASN1::Null
1089
+ decoder.decode_der(io).should be_an_instance_of Krypt::ASN1::Integer
1090
+ end
1091
+
1092
+ # TODO: Fails for JRuby - bug?
1093
+ it "should handle generic IOs as an IO" do
1094
+ stringio = StringIO.new(
1095
+ [
1096
+ Krypt::ASN1::Null.new,
1097
+ Krypt::ASN1::Integer.new(0)
1098
+ ].map { |e| e.to_der }.join
1099
+ )
1100
+ c = Class.new do
1101
+ def initialize(io)
1102
+ @io = io
1103
+ end
1104
+
1105
+ def read(*args)
1106
+ @io.read(*args)
1107
+ end
1108
+ end
1109
+ generic = c.new(stringio)
1110
+ decoder.decode_der(generic).should be_an_instance_of Krypt::ASN1::Null
1111
+ decoder.decode_der(generic).should be_an_instance_of Krypt::ASN1::Integer
1112
+ end
1113
+ end
1114
+
1115
+ describe "extracted from ASN1.decode_pem" do
1116
+ subject { decoder.decode_pem(value) }
1117
+
1118
+ context "PEM certificate" do
1119
+ let(:value) { Resources.certificate_pem }
1120
+ its(:to_der) { should == Resources.certificate }
1121
+ end
1122
+
1123
+ context "rejects non PEM values" do
1124
+ let(:value) { Resources.certificate }
1125
+ it { -> { subject }.should raise_error asn1error }
1126
+ end
1127
+
1128
+ it "decodes files" do
1129
+ io = Resources.certificate_pem_io
1130
+ begin
1131
+ decoder.decode_pem(io).to_der.should == Resources.certificate
1132
+ ensure
1133
+ io.close
1134
+ end
1135
+ end
1136
+
1137
+ context "decodes StringIO" do
1138
+ let(:value) { StringIO.new(Resources.certificate_pem) }
1139
+ its(:to_der) { should == Resources.certificate }
1140
+ end
1141
+
1142
+ context "decodes arbitrary objects that respond to #to_pem" do
1143
+ let(:value) do
1144
+ o = Object.new
1145
+ def o.to_pem
1146
+ Resources.certificate_pem
1147
+ end
1148
+ o
1149
+ end
1150
+ its(:to_der) { should == Resources.certificate }
1151
+ end
1152
+ end
1153
+ end