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,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